Skip to content

fix(ios): review adjustments for #419#440

Closed
jkmassel wants to merge 23 commits intofeat/improve-media-uploads-and-errorsfrom
jkmassel/review-pr-419
Closed

fix(ios): review adjustments for #419#440
jkmassel wants to merge 23 commits intofeat/improve-media-uploads-and-errorsfrom
jkmassel/review-pr-419

Conversation

@jkmassel
Copy link
Copy Markdown
Contributor

@jkmassel jkmassel commented Apr 8, 2026

Suggested changes from reviewing #419.

Changes

1. Use Int64 for HTTPRequestParser.bytesWritten

bytesWritten was Int while expectedContentLength and maxBodySize are already Int64. This is consistent on all Apple platforms today (where Int is 64-bit), but using Int64 explicitly matches the convention used throughout the parser and avoids unnecessary Int64(...) casts at comparison sites.

2. Add end-to-end test for 413 + CORS headers

The core motivation for the drain+handler routing in #419 is that 413 responses include CORS headers so the WebView's fetch() can read them. This adds an integration test that sends an oversized request to MediaUploadServer and verifies both the 413 status code and the Access-Control-Allow-Origin header.

To support this, MediaUploadServer.start() now exposes a maxRequestBodySize parameter (defaulting to the existing 4 GB), so the test can use a small limit without sending gigabytes of data.

Related issues

dependabot bot and others added 23 commits March 29, 2026 12:28
Bumps [@wordpress/wordcount](https://github.com/WordPress/gutenberg/tree/HEAD/packages/wordcount) from 4.41.0 to 4.42.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/wordcount/CHANGELOG.md)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/wordcount@4.42.0/packages/wordcount)

---
updated-dependencies:
- dependency-name: "@wordpress/wordcount"
  dependency-version: 4.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@wordpress/primitives](https://github.com/WordPress/gutenberg/tree/HEAD/packages/primitives) from 4.41.0 to 4.42.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/primitives/CHANGELOG.md)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/primitives@4.42.0/packages/primitives)

---
updated-dependencies:
- dependency-name: "@wordpress/primitives"
  dependency-version: 4.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* build(deps): Bump @wordpress/rich-text from 7.41.0 to 7.42.0

Bumps [@wordpress/rich-text](https://github.com/WordPress/gutenberg/tree/HEAD/packages/rich-text) from 7.41.0 to 7.42.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/rich-text/CHANGELOG.md)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/rich-text@7.42.0/packages/rich-text)

---
updated-dependencies:
- dependency-name: "@wordpress/rich-text"
  dependency-version: 7.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* build: Generate @wordpress/rich-text patch

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: David Calhoun <github@davidcalhoun.me>
…#409)

Bumps [@wordpress/global-styles-engine](https://github.com/WordPress/gutenberg/tree/HEAD/packages/global-styles-engine) from 1.8.0 to 1.9.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/global-styles-engine@1.9.0/packages/global-styles-engine)

---
updated-dependencies:
- dependency-name: "@wordpress/global-styles-engine"
  dependency-version: 1.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat: Authorize AJAX with application passwords

Include authorization header in AJAX requets, as we do not have cookies
to send in the mobile app environment.

* refactor: Rename AJAX and api-fetch configuration utilities

* fix: Configure AJAX after the library loads

If we configure AJAX before loading the library, the configuration is
overridden.

* test: Fix test imports and assertions

* fix: Set the global WordPress admin AJAX URL

This global is often used by WordPress Admin page scripts.

* test: Assert AJAX configuration

* feat: Allow configuring the Android asset loader domain

Useful when needing to allow CORS for specific domains.

* docs: Note AJAX support requirements

* docs: Note AJAX CORS errors in troubleshooting documentation

* fix: Add type checks before wrapping wp.ajax methods (#282)

Address PR feedback about potential race condition. The code now checks
if `window.wp.ajax.send` and `window.wp.ajax.post` are functions before
wrapping them. This prevents TypeError when calling the wrapped function
if the original method was undefined during configuration.

Update tests to verify that missing methods remain undefined rather than
being wrapped with an undefined reference.

Co-authored-by: Claude <noreply@anthropic.com>

* feat: conditionally reinstate VideoPress bridge

When `videopress/video` is not in `allowed_block_types`, initialize the
VideoPress AJAX bridge to handle `core/video` blocks extended to rely
upon VideoPress upload services. AJAX auth is always initialized.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: filter lodash-js-after inline script from editor assets

WordPress's `lodash-js-after` inline script calls `_.noConflict()` to
restore `window._` to Underscore.js. Since GutenbergKit excludes core
WordPress assets from the editor assets endpoint but doesn't load
Underscore, this wipes `window._` to `undefined`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: vendor and load wp-util.js

GutenbergKit excludes core WordPress assets from the editor assets
endpoint, so wp-util.js (which provides wp.ajax and wp.template) must
be vendored and loaded directly. Load it via dynamic import at the end
of initializeWordPressGlobals() after jQuery and lodash are on window,
since its IIFE captures jQuery via closure at execution time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: align wp.ajax wrapper signatures with wp-util

The wp.ajax.send and wp.ajax.post wrappers accepted a single options
argument, but wp-util's implementation accepts (action, options). Align
the wrapper signatures so the action argument is forwarded correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use home URL for iOS demo app site URL

Use `homeUrlString()` instead of `siteUrlString()` from the REST API
root response. The `url` field often returns `http://` for WordPress.com
sites, while `home` returns the actual public-facing `https://` URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: alias wp.media.ajax and wp.media.post to wp.ajax

WordPress core sets these aliases in media-models.js, which
GutenbergKit doesn't load. Alias them after auth wrapping so media
uploads use the authenticated AJAX methods.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* build: Use wp-util from production WordPress release

Avoid including latest changes from the WordPress/wordpress-develop
repository.

* docs: Expand inline comments

* refactor: scope AJAX auth to same-site requests via ajaxPrefilter

Replace jQuery.ajaxSetup and wp.ajax.send/post wrappers with a single
jQuery.ajaxPrefilter that only injects the Authorization header when
the request URL starts with the configured siteURL. This prevents
leaking credentials to cross-origin requests and avoids argument
normalization issues with the previous wp.ajax wrapper approach.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: strip trailing slash from siteURL before building AJAX URLs

Prevents double-slash in constructed URLs (e.g.,
`https://example.com//wp-admin/admin-ajax.php`) when siteURL is
provided with a trailing slash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: warn instead of logging success when jQuery is unavailable for AJAX auth

The ajaxPrefilter silently no-ops via optional chaining when jQuery is
missing, but the debug log still claims auth was configured. Guard with
an early return and warning so the log accurately reflects what happened.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use origin-based matching for AJAX auth header injection

Replace `startsWith(siteURL)` with `URL.origin` comparison so that
scheme, host, and port must all match exactly. This prevents credential
leakage to lookalike domains (e.g. `https://example.com.evil.com`).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: separate AJAX config examples from Android requirement

Move the iOS and Android code examples out of the Android-specific
requirement so they are not visually nested under that bullet point.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: remove redundant AJAX setup from VideoPress bridge

configureAjax() now initializes wp.ajax, wp.ajax.settings, and the AJAX
URL before the VideoPress bridge runs, making the duplicate setup in
initializeVideoPressAjaxBridge() unnecessary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add defensive guards to AJAX configuration

- Wrap `new URL(siteURL)` in try/catch so a malformed siteURL logs a
  warning instead of throwing.
- Guard `configureMediaAjax` against missing `wp.ajax.send`/`post`
  (e.g., if wp-util.js failed to load).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: validate assetLoaderDomain in Android EditorConfiguration

Throw IllegalArgumentException if the value contains a scheme, path, or
is blank, so callers get a clear error instead of a malformed asset URL
at runtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add vendor README documenting wp-util.js source

Record the upstream commit hash and rationale for vendoring so future
maintainers know where the file came from and when to update it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add https scheme to WP.com site URL in Android demo app

Account.WpCom.username stores just the hostname (e.g.,
"dcpaid.wordpress.com") since it is extracted via URI.host during OAuth.
ConfigurationItem was using this bare hostname as siteUrl, producing
invalid AJAX endpoints. Prepend "https://" to match the self-hosted
flow, which receives a full URL from the callback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: extract duplicated AJAX URL into local variable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: remove lint/format exclusion note from vendor README

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: derive Android WebView asset domain from site URL

Derive the WebViewAssetLoader domain from the configured siteURL
instead of defaulting to the synthetic appassets.androidplatform.net
domain. This makes REST API and admin-ajax.php requests same-origin,
eliminating CORS restrictions without requiring server-side headers.

- Restrict shouldOverrideUrlLoading to /assets/ paths on the asset
  domain so arbitrary site pages don't load inside the WebView.
- Reorder shouldInterceptRequest to check the cache interceptor
  before the asset loader, preventing cached JS/CSS from being
  short-circuited when both share the site domain.
- Remove the now-unnecessary assetLoaderDomain configuration option
  from EditorConfiguration.
- Update AJAX documentation to reflect the simplified setup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
* refactor: consolidate @WordPress mocks in __mocks__ directory

Add shared mock stubs for @WordPress packages that crash when imported
in the test environment. Flatten existing directory-based mocks (i18n,
components) to top-level files for consistency. Remove exports that
have no effect on test outcomes — the files themselves are still needed
to prevent Vitest from importing the real modules.

Tests declare vi.mock('module') without a factory to use the shared
stub, and override locally only when test-specific behavior is needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: remove unnecessary vi.mock() calls from existing tests

Remove @wordpress/preferences (editor.test.jsx) and @wordpress/i18n
(editor-load-notice, offline-indicator) mocks that have no effect on
test outcomes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: coordinate bridge readiness and editor visibility for onEditorLoaded

Replace the IntersectionObserver in use-editor-visible with a new
useEditorReady hook that coordinates two conditions before signaling
the native host via onEditorLoaded:

1. All window.editor.* bridge methods are assigned (from useHostBridge)
2. The editor content is visible in the viewport (via
   IntersectionObserver on the VisualEditor/TextEditor root element)

useEditorReady returns a callback ref (for DOM attachment observation),
a standard ref (for imperative access in useHostBridge), and a
markBridgeReady callback. The callback ref is forwarded to
VisualEditor/TextEditor via forwardRef so the observer fires when the
actual editor content is in the viewport — not just the wrapper div.

The editorLoaded() call is deferred by one frame via
requestAnimationFrame so the browser has painted the editor content
before the native host starts the fade-in animation.

Remove the now-unused useEditorVisible hook and add the missing
window.editor.focus cleanup on unmount.

The error path in editor-environment.js retains its own editorLoaded()
call since useEditorReady won't run when initialization fails.

Addresses CMM-2008 and CMM-2009.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add isReady guards to iOS JS bridge calls

Add isReady guards to undo(), redo(), dismissTopModal(),
isCodeEditorEnabled, appendTextAtCursor(), getContent(), and
getTitleAndContent(). Previously only setContent() was guarded.

Reset isReady to false in controllerWebContentProcessDidTerminate so
JS bridge calls are blocked until the editor re-emits onEditorLoaded
after a WebView process crash and reload.

Fire-and-forget methods silently return when not ready. Async throwing
methods (getContent, getTitleAndContent) throw EditorNotReadyError so
callers can handle the case explicitly.

Addresses CMM-2008 and CMM-2009.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add tests for bridge setup ordering guarantees

Verify window.editor.* methods are assigned and markBridgeReady is
called, and that all methods are cleaned up on unmount.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ci: add CodeQL workflow for Swift analysis on macOS

The default CodeQL setup only runs on Linux runners, which can't build
this project's Swift package (requires Xcode/iOS SDK). This adds a
dedicated workflow using macos-15 runners with path filtering so it
only runs when Swift code changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: add workflow_dispatch trigger to CodeQL Swift workflow

Allows manual triggering from the Actions tab for testing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: trigger CodeQL Swift workflow with trivial whitespace change

Remove trailing newline to trigger the path-filtered workflow on this PR.
This can be reverted after verifying the workflow passes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: replace Swift-only workflow with full CodeQL workflow

The default CodeQL setup and custom workflows can't coexist, so this
replaces the default setup with a single workflow covering all languages.
Swift runs on macos-15 with Xcode 16.3 (for Swift 6.2); JS, Kotlin,
and Actions run on ubuntu-latest with autobuild.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: fix Swift Xcode version and disable default CodeQL setup

- Use Xcode 26.0.1 (Swift 6.2) instead of Xcode 16.3 (Swift 6.1)
- Disabled default CodeQL setup via API since custom and default
  workflows cannot coexist
- Reverted back to Swift-only + all-languages workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…#414)

Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](lodash/lodash@4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* refactor: Move editor loading UI into GutenbergView

GutenbergView previously extended WebView directly and delegated all
loading UI (progress bar, spinner, error states) to consumers via the
EditorLoadingListener interface. This forced every app embedding the
editor to implement its own loading UI boilerplate.

This change makes GutenbergView extend FrameLayout instead, containing
an internal WebView plus overlay views for loading states:

- EditorProgressView (progress bar + label) during dependency fetching
- ProgressBar (circular/indeterminate) during WebView initialization
- EditorErrorView (new) for error states

The view manages its own state transitions with 200ms fade animations,
matching the iOS EditorViewController pattern. The EditorLoadingListener
interface is removed entirely — consumers no longer need loading UI code.

Changes:
- GutenbergView: WebView -> FrameLayout with internal WebView child
- New EditorErrorView for displaying load failures
- Delete EditorLoadingListener (no longer needed)
- Simplify demo EditorActivity by removing ~90 lines of loading UI
- Update tests to use editorWebView accessor for WebView properties
- Delete unused activity_editor.xml layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Cancel in-flight view animations in onDetachedFromWindow

Prevents withEndAction callbacks from firing on detached views
if the editor is closed mid-animation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Remove unused LoadingState enum from GutenbergView

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Remove unused ASSET_LOADING_TIMEOUT_MS constant from GutenbergView

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Clear openMediaLibraryListener and logJsExceptionListener in onDetachedFromWindow

These two listeners were not being nulled out during teardown,
inconsistent with all other listener cleanup in the same method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update AGP

* Add required constructor

* Enforce valid postId using the type system

* fix: use webView reference in dispatchConnectivityEvent

After the FrameLayout refactor, `this.evaluateJavascript` no longer
compiles since GutenbergView is no longer a WebView.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update detekt baseline and tests for FrameLayout refactor

The Detekt baseline referenced `GutenbergView : WebView` which no
longer matches after the FrameLayout change. Two tests also referenced
`webViewClient` directly on GutenbergView instead of via `editorWebView`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: normalize namespace trailing slash in RESTAPIRepository on both platforms

Ensures namespaces like "sites/123" (without trailing slash) produce
the same URLs as "sites/123/" so callers don't need to worry about
the convention. Adds tests on both platforms to verify.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use try? in namespace URL tests to avoid mock decoding failures

The mock HTTP client returns empty data, causing JSON decoding errors
that prevented the namespace URL assertions from being reached. Since
these tests only verify URL construction, try? is appropriate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: David Calhoun <github@davidcalhoun.me>
* fix: coerce post ID 0 to nil on both platforms and JS bridge

WordPress uses 0 as a sentinel for "no post" in several contexts;
passing it through causes incorrect API requests and editor state.
This treats post ID 0 as nil/absent across Android, iOS, and the
JS bridge layer, with unit tests on both platforms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add JS unit tests for post ID 0 coercion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: David Calhoun <github@davidcalhoun.me>
…422)

Increase the `waitForClearToTakeEffect` polling timeout from 1s to 5s
and add `.timeLimit(.minutes(1))` to the two clear-related tests.
`URLCache.removeAllCachedResponses()` is internally asynchronous and
CI environments with slower I/O can exceed the previous 1s window.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* build(deps): Bump @wordpress/blocks from 15.15.0 to 15.16.0

Bumps [@wordpress/blocks](https://github.com/WordPress/gutenberg/tree/HEAD/packages/blocks) from 15.15.0 to 15.16.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/blocks/CHANGELOG.md)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/blocks@15.16.0/packages/blocks)

---
updated-dependencies:
- dependency-name: "@wordpress/blocks"
  dependency-version: 15.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* build: Re-generate @wordpress/rich-text patch

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: David Calhoun <github@davidcalhoun.me>
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.0 to 8.0.3.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@8.0.3/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@wordpress/style-engine](https://github.com/WordPress/gutenberg/tree/HEAD/packages/style-engine) from 2.42.0 to 2.43.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/style-engine/CHANGELOG.md)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/style-engine@2.43.0/packages/style-engine)

---
updated-dependencies:
- dependency-name: "@wordpress/style-engine"
  dependency-version: 2.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
#428)

Bumps [@wordpress/prettier-config](https://github.com/WordPress/gutenberg/tree/HEAD/packages/prettier-config) from 4.41.0 to 4.43.0.
- [Release notes](https://github.com/WordPress/gutenberg/releases)
- [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/prettier-config/CHANGELOG.md)
- [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/prettier-config@4.43.0/packages/prettier-config)

---
updated-dependencies:
- dependency-name: "@wordpress/prettier-config"
  dependency-version: 4.43.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ry (#430)

Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 8.0.3 to 8.0.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.5
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
#432)

* fix(android): include restBase and restNamespace in GBKit post payload

The api-fetch filterEndpointsMiddleware blocks server fetches for the
post being edited (preventing them from overwriting local edits with
stale or context-mismatched data). The middleware bails out early when
either restBase or restNamespace is missing from window.GBKit.post:

    if ( id === undefined || ! restNamespace || ! restBase ) {
        return next( options );  // lets the request through
    }

iOS already populates these from EditorConfiguration.postType
(PostTypeDetails struct), but Android's GBKitGlobal.Post only had
{ id, type, status, title, content }. As a result, when the editor
mounted with an existing post ID, WordPress core data fetched the
post via GET /wp/v2/posts/{id} unfiltered, and the response (without
context=edit) overwrote the title and content set from the native
host with empty values — causing the editor to briefly show the
loaded post before clearing it.

Adds restBase and restNamespace fields to GBKitGlobal.Post and derives
them from the postType slug ("post" → "posts", "page" → "pages",
custom types pluralized).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(android): assert restBase and restNamespace in GBKitGlobal payload

Adds coverage for the restBase/restNamespace fields recently added to
GBKitGlobal.Post, including the heuristic pluralization for custom
post types.

* fix(api-fetch): apply post fallbacks in filterEndpointsMiddleware

The middleware previously bailed out when window.GBKit.post was missing
restBase or restNamespace, letting the editor's GET /wp/v2/posts/{id}
request through unfiltered. The response (without context=edit) then
clobbered the host-provided title and content.

Apply the same fallback contract that getPost() already uses
('posts' / 'wp/v2'), centralized in a new POST_FALLBACKS export so
both consumers stay in sync. Hosts that omit those fields now get the
filter applied with sensible defaults instead of silently slipping past.

* docs(api-fetch): note follow-up for filterEndpointsMiddleware

Captures a @todo explaining that this middleware could likely be
removed in favor of properly seeding entity content into the store
on initialization, and links to the historical commit that added it.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
)

* fix: normalize data store attributes to plain strings in JS bridge

The WordPress data store's `getEditedPostContent()` may return
`{raw, rendered}` objects instead of plain strings because it uses
`getEditedEntityRecord` (which preserves the object shape) rather than
`getRawEntityRecord` (which extracts `.raw`).

Add `normalizeAttribute()` to always extract the raw string before
returning values to the native host via `getTitleAndContent()`.

Also remove the redundant `getContent()` bridge method and its iOS
public API — `getTitleAndContent()` is the single accessor for editor
state.

* fix: harden normalizeAttribute and extend test coverage

- Make normalizeAttribute explicitly handle null/undefined instead of
  relying on typeof null === 'object' with optional chaining
- Coerce non-string primitives to strings via String()
- Normalize postTitleRef/postContentRef initialization defensively
- Normalize block content in appendTextAtCursor
- Add unit tests for edge cases: null, undefined, {raw: null},
  {raw: undefined}, arrays, non-string primitives
- Add unit tests for changed flag correctness with object values
- Add unit tests for appendTextAtCursor (object content, string
  content, no block selected, unsupported block type)
- Add changed flag assertions to E2E object-injection regression tests

* fix: restore getContent() as convenience accessor

Restore the getContent() bridge method on both JS and iOS. It is used
in contexts where the editor has no title field (e.g. comment editors).

Both implementations delegate to getTitleAndContent() so normalization
happens in one place.

* test: use project-level mocks for WordPress packages in host bridge tests

* fix: use Array.isArray for explicit array handling in normalizeAttribute
Change `bytesWritten` from `Int` to `Int64` for consistency with
`expectedContentLength` and `maxBodySize`, which are already `Int64`.
Expose maxRequestBodySize on MediaUploadServer.start() and add an
integration test that sends an oversized request and verifies the
response includes both a 413 status and CORS headers.
@github-actions github-actions bot added the [Type] Bug An existing feature does not function as intended label Apr 8, 2026
@jkmassel
Copy link
Copy Markdown
Contributor Author

jkmassel commented Apr 8, 2026

Recreating with correct base — branch had extra commits from trunk.

@jkmassel jkmassel closed this Apr 8, 2026
@jkmassel jkmassel deleted the jkmassel/review-pr-419 branch April 8, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants