Skip to content

Advertise binary diff capability to the server - #63

Merged
ofalvai merged 1 commit into
masterfrom
push-mnzosllxrtkx
Sep 24, 2026
Merged

ofalvai merged 1 commit into
masterfrom
push-mnzosllxrtkx

Conversation

@ofalvai

@ofalvai ofalvai commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

Why

We need to keep the client's capabilities in sync with the server response, in order to avoid receiving update payloads that the client can't handle.

What

Sends the client's capabilities on both update_check and report_status/deploy so the server can serve ZIPs with bsdiff patches (and meter their size correctly).

As this feature is opt-in for now (CodePushEnableDeltaUpdates in Info.plist / strings.xml), the capability is advertised only when the config is enabled. The native side rejects a v2 diff when the flag is off, and the server would keep serving the same diff, so advertising it unconditionally would block that release on the device.

Since the capability is ultimately decided by the CodePushEnableDeltaUpdates config (controlled by the user of this SDK), we need to expose this value from the native sides to the JS side, where API calls like update_check are implemented.

The E2E test apps enable delta updates, and checkForUpdate.update asserts the capability on update_check, which covers the flag end to end (native config -> getConfiguration() -> SDK).

Also adds CodePushEnableDeltaUpdates to the Expo config plugin, since expo prebuild regenerates the native config and Expo apps had no way to set the flag.

Decisions

Wanted to replace the hand-rolled queryStringify() function with URLSearchParams, but its React Native polyfill doesn't support what we need on RN 0.76-0.79, and I think those versions are worth supporting for now. See the inline comment for more details.

Tests: adding full E2E test coverage for the delta update feature would be really complex, and would increase our already poor test run times, so I think unit tests are a better fit for this. Nevertheless, this PR enables CodePushEnableDeltaUpdates in the E2E test apps, and adds verification for the update_check API call's capability field, so at least this part is covered when running the existing E2E tests.

Copilot AI balanced review requested due to automatic review settings September 23, 2026 08:58
@ofalvai ofalvai changed the title JS SDK: advertise binary diff capability to the server Advertise binary diff capability to the server Sep 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The TypeScript build failure and broken bare-iOS test setup are approval-blocking.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity

Open (2)
What changed in this PR

Adds opt-in binary-diff capability advertising from native configuration through the acquisition SDK.

Changes:

  • Advertises capabilities during update checks and deployment reports.
  • Exposes delta-update settings on iOS and Android.
  • Adds Expo configuration and test coverage.
File Summary Finding
test/​test.ts Enables and verifies E2E capability advertising. Critical: iOS setup fails because plutil -replace targets a missing plist key.
test/​template/​app.json Enables delta updates for Expo tests. No issue.
test/​template/​android/​app/​src/​main/​res/​values/​strings.xml Enables Android test-app delta updates. No issue.
src/​acquisition-sdk/​types.ts Adds capability request fields. No issue.
src/​acquisition-sdk/​acquisition-sdk.ts Serializes and sends capabilities. Critical: Object.entries is incompatible with the configured ES6 TypeScript library.
src/​acquisition-sdk/​__tests__/​capabilities.test.ts Adds capability serialization tests. Nit: This suite is not compiled or executed by current test targets.
ios/​CodePush/​CodePushConfig.m Exposes the iOS delta-update setting. No issue.
expo.js Adds Expo plugin support for delta updates. No issue.
android/​app/​src/​main/​java/​com/​microsoft/​codepush/​react/​CodePushNativeModule.java Exposes Android configuration to JavaScript. No issue.
android/​app/​src/​main/​java/​com/​microsoft/​codepush/​react/​CodePush.java Stores and exposes the Android setting. No issue.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.


queryString += encodeURIComponent(property) + "=";
queryString += encodeURIComponent(value);
for (var [key, value] of Object.entries(request)) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to split the fix into its own PR: #64

Comment thread test/test.ts
}

async function setPlistBoolValue(plistPath: string, key: string, value: boolean): Promise<void> {
await promisify(childProcess.execFile)("plutil", ["-replace", key, "-bool", String(value), plistPath]);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plutil -replace inserts the key when it's missing, it doesn't require it to exist. The existing CodePushDeploymentKey, CodePushServerURL, and CodePushPublicKey lines work the same way. They are not in any template either.

Sends the client's capabilities on both update_check (as a plain
repeated capabilities=<value> query param, no bracket notation) and
report_status/deploy (as a JSON array), so the server can serve v2
(bsdiff) diffs and meter their size correctly. The two calls must
agree: report_status/deploy's capabilities drive the server's
byte-count reconstruction independently of what update_check
advertised, so omitting it there would silently over-report downloaded
bytes for clients that received a v2 diff.

The capability is advertised only when the app enables delta updates
(CodePushEnableDeltaUpdates in Info.plist / strings.xml). The native
side rejects a v2 diff when the flag is off, and the server would keep
serving the same diff, so advertising it unconditionally would block
that release on the device. Both platforms now expose the flag through
getConfiguration(). On iOS it stays a typed property on CodePushConfig
and is serialized only at the JS boundary, not stored in the untyped
config dictionary.

Replaces queryStringify with a toQueryString that expands array values
into a repeated key. It builds the string by hand, because the
URLSearchParams polyfill in RN 0.76-0.79 accepts only a plain object,
which cannot hold a repeated key.

The E2E test apps enable delta updates, and checkForUpdate.update
asserts the capability on update_check, which covers the flag end to
end (native config -> getConfiguration() -> SDK).

Also adds CodePushEnableDeltaUpdates to the Expo config plugin for both
platforms, since expo prebuild regenerates the native config and Expo
apps had no way to set the flag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ofalvai
ofalvai merged commit faf0213 into master Sep 24, 2026
6 checks passed
@ofalvai
ofalvai deleted the push-mnzosllxrtkx branch September 24, 2026 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants