Skip to content

Commit 8c55d99

Browse files
committed
Vendor acquisition-sdk instead of depending on the code-push npm package
Adds src/acquisition-sdk/ (vendored TypeScript from the archived microsoft/code-push repo, trimmed types.ts to only what's used, tests ported for future reference but not wired into any runner), a tsconfig.build.json + build:ts script compiling it to lib/ at prepack/setup time, and points CodePush.js at the compiled output instead of the code-push package. Drops the code-push dependency entirely, which was only ever used for this one submodule and pulled in the superagent/proxy-agent/vm2 CLI dependency chain that never actually shipped in the bundled app JS.
1 parent d4f2020 commit 8c55d99

13 files changed

Lines changed: 858 additions & 8 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ build/Release
7777
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
7878
node_modules
7979

80+
# Compiled output of src/ (built via `npm run build:ts`, generated fresh at publish time)
81+
lib/
82+
8083
# Xcode
8184
#
8285
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

.npmignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ Recipes/
3434
bin/
3535
test/
3636

37+
# Don't publish TypeScript source - only the compiled lib/ output (built via `npm run build:ts`
38+
# as part of `prepack`) ships
39+
# Anchored to repo root (leading slash) - an unanchored `src/` also matches android/app/src/,
40+
# which stripped the native Android module's Java sources from every published tarball.
41+
/src/
42+
3743
# Remove after this framework is published on NPM
3844
code-push-plugin-testing-framework/
3945

@@ -101,3 +107,9 @@ packages/
101107

102108
.watchmanconfig
103109

110+
# Dev tooling, not relevant to consumers
111+
.claude/
112+
.config/
113+
CLAUDE.md
114+
mise.toml
115+

CLAUDE.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ React Native CodePush is a native module that enables over-the-air updates for R
1616
### Build
1717
- `npm run build` - Build TypeScript tests to bin/ directory
1818
- `npm run tsc` - TypeScript compilation
19+
- `npm run build:ts` - Compiles `src/` (currently just the vendored `acquisition-sdk`) to `lib/`, which is what ships to consumers instead of raw `.ts`. Wired into `setup` (so local dev/tests have `lib/` available) and `prepack` (so `npm publish`/`npm pack` always ship a freshly built `lib/`).
20+
- This split (a separate `tsconfig.build.json` and `tsconfig.json` for `test/` -> `bin/`) is temporary. Once `CodePush.js` and the rest of this repo's runtime JS are migrated to TypeScript, these should be unified into a single build, and adopting `react-native-builder-bob` (or some other common tool) is worth considering at that point instead of hand-rolled `tsc` + npm script wiring.
1921

2022
### Platform Testing
2123
- Tests run on actual emulators/simulators with real React Native apps
@@ -28,7 +30,7 @@ React Native CodePush is a native module that enables over-the-air updates for R
2830
- **JavaScript Bridge** (`CodePush.js`): Main API layer exposing update methods
2931
- **Native Modules**: Platform-specific implementations handling file operations, bundle management
3032
- **Update Manager**: Handles download, installation, and rollback logic
31-
- **Acquisition SDK**: Manages server communication and update metadata
33+
- **Acquisition SDK** (`src/acquisition-sdk/`): Manages server communication and update metadata
3234

3335
### Platform Structure
3436
- **iOS**: `ios/` - Objective-C implementation with CocoaPods integration
@@ -46,6 +48,7 @@ React Native CodePush is a native module that enables over-the-air updates for R
4648
- **Custom Test Runner**: TypeScript-based test framework in `test/`
4749
- **Real App Testing**: Creates actual React Native apps for integration testing
4850
- **Scenario Testing**: Update, rollback, and error scenarios
51+
- **No unit test infra yet**: this repo only has the mocha-based integration suite above. `src/acquisition-sdk/__tests__/` contains tests ported from upstream `microsoft/code-push`, kept for future reference - they are deliberately not wired into `npm test` or any runner. Don't assume they're dead/forgotten code, and don't wire them in without setting up real unit test infra first.
4952
- **Templates**: `test/template/` holds native files (Podfile, AppDelegate, Android app files) and JS scenarios copied over top of a freshly generated RN/Expo app during test setup, overwriting its defaults — edit files here, not the generated project, for changes to persist
5053
- **`test:ios` vs `test:setup:ios` vs `test:fast:ios`**: `test:ios` is just `test:setup:ios` followed by `test:fast:ios` — the two are meant to be split apart for local iteration.
5154
- `test:setup:ios` (mocha `--ios --setup`) boots the simulator and provisions the test app once: copies templates, runs `pod install`, patches Info.plist/AppDelegate. It never builds or runs any test scenario.
@@ -61,3 +64,4 @@ React Native CodePush is a native module that enables over-the-air updates for R
6164
- **Android Gradle Plugin**: Automatically generates bundle hashes and processes assets
6265
- **iOS CocoaPods**: Manages native dependencies and build configuration
6366
- **Bundle Processing**: Automated zip creation and hash calculation for OTA updates
67+
- **`.npmignore` is a blocklist, not an allowlist**: `package.json` has no `files` field, so any new top-level file/dir ships to npm by default unless explicitly excluded. When adding new repo tooling/config, check whether it needs a `.npmignore` entry. Verify with `npm pack --dry-run`.

CodePush.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AcquisitionManager as Sdk } from "code-push/script/acquisition-sdk";
1+
import { AcquisitionManager as Sdk } from "./lib/acquisition-sdk/acquisition-sdk";
22
import { Alert } from "./AlertAdapter";
33
import requestFetchAdapter from "./request-fetch-adapter";
44
import { AppState, Platform } from "react-native";

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
"author": "Bitrise",
1515
"license": "MIT",
1616
"scripts": {
17-
"clean": "shx rm -rf bin",
18-
"setup": "npm install --quiet --no-progress",
17+
"clean": "shx rm -rf bin lib",
18+
"setup": "npm install --quiet --no-progress && npm run build:ts",
19+
"build:ts": "tsc -p tsconfig.build.json",
20+
"prepack": "npm run build:ts",
1921
"prebuild:tests": "npm run clean && npm run tslint",
2022
"build:tests": "tsc",
2123
"test": "npm run build:tests && npm run test:setup && npm run test:fast",
@@ -42,7 +44,6 @@
4244
"url": "https://github.com/bitrise-io/react-native-code-push"
4345
},
4446
"dependencies": {
45-
"code-push": "4.2.3",
4647
"glob": "^7.1.7",
4748
"hoist-non-react-statics": "^3.3.2",
4849
"inquirer": "^8.1.5",

request-fetch-adapter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module.exports = {
1212
"Content-Type": "application/json",
1313
"X-CodePush-Plugin-Name": packageJson.name,
1414
"X-CodePush-Plugin-Version": packageJson.version,
15-
"X-CodePush-SDK-Version": packageJson.dependencies["code-push"]
15+
"X-CodePush-SDK-Version": packageJson.version
1616
};
1717

1818
if (requestBody && typeof requestBody === "object") {
@@ -37,7 +37,7 @@ module.exports = {
3737

3838
function getHttpMethodName(verb) {
3939
// Note: This should stay in sync with the enum definition in
40-
// https://github.com/microsoft/code-push/blob/master/sdk/script/acquisition-sdk.ts#L6
40+
// https://github.com/microsoft/code-push/blob/master/src/script/acquisition-sdk.ts#L5
4141
return [
4242
"GET",
4343
"HEAD",
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Ported from https://github.com/microsoft/code-push/blob/master/src/test/acquisition-rest-mock.ts (archived, MIT licensed)
2+
// Not currently wired into any test runner — this repo has no unit test infra yet.
3+
4+
import * as querystring from "querystring";
5+
6+
import * as acquisitionSdk from "../acquisition-sdk";
7+
import * as types from "../types";
8+
9+
export var validDeploymentKey = "Valid Deployment Key";
10+
export var latestPackage = <types.UpdateCheckResponse>{
11+
download_url: "http://www.windowsazure.com/blobs/awperoiuqpweru",
12+
description: "Angry flappy birds",
13+
target_binary_range: "1.5.0",
14+
label: "2.4.0",
15+
is_mandatory: false,
16+
is_available: true,
17+
update_app_version: false,
18+
package_hash: "hash240",
19+
package_size: 1024
20+
};
21+
22+
export var serverUrl = "http://myurl.com";
23+
var publicPrefixUrl = "/v0.1/public/codepush";
24+
var reportStatusDeployUrl = serverUrl + publicPrefixUrl + "/report_status/deploy";
25+
var reportStatusDownloadUrl = serverUrl + publicPrefixUrl + "/report_status/download";
26+
var updateCheckUrl = serverUrl + publicPrefixUrl + "/update_check?";
27+
28+
export function updateMockUrl() {
29+
reportStatusDeployUrl = serverUrl + publicPrefixUrl + "/report_status/deploy";
30+
reportStatusDownloadUrl = serverUrl + publicPrefixUrl + "/report_status/download";
31+
updateCheckUrl = serverUrl + publicPrefixUrl + "/update_check?";
32+
}
33+
34+
export class HttpRequester implements acquisitionSdk.Http.Requester {
35+
private expectedStatusCode: number;
36+
37+
constructor(expectedStatusCode?: number) {
38+
this.expectedStatusCode = expectedStatusCode;
39+
}
40+
41+
public request(verb: acquisitionSdk.Http.Verb, url: string, requestBodyOrCallback: string | acquisitionSdk.Callback<acquisitionSdk.Http.Response>, callback?: acquisitionSdk.Callback<acquisitionSdk.Http.Response>): void {
42+
if (!callback && typeof requestBodyOrCallback === "function") {
43+
callback = <acquisitionSdk.Callback<acquisitionSdk.Http.Response>>requestBodyOrCallback;
44+
}
45+
46+
if (verb === acquisitionSdk.Http.Verb.GET && url.indexOf(updateCheckUrl) === 0) {
47+
var params = querystring.parse(url.substring(updateCheckUrl.length));
48+
Server.onUpdateCheck(params, callback, this.expectedStatusCode);
49+
} else if (verb === acquisitionSdk.Http.Verb.POST && url === reportStatusDeployUrl) {
50+
Server.onReportStatus(callback, this.expectedStatusCode);
51+
} else if (verb === acquisitionSdk.Http.Verb.POST && url === reportStatusDownloadUrl) {
52+
Server.onReportStatus(callback, this.expectedStatusCode);
53+
} else {
54+
throw new Error("Unexpected call");
55+
}
56+
}
57+
}
58+
59+
export class CustomResponseHttpRequester implements acquisitionSdk.Http.Requester {
60+
response: acquisitionSdk.Http.Response;
61+
62+
constructor(response: acquisitionSdk.Http.Response) {
63+
this.response = response;
64+
}
65+
66+
public request(verb: acquisitionSdk.Http.Verb, url: string, requestBodyOrCallback: string | acquisitionSdk.Callback<acquisitionSdk.Http.Response>, callback?: acquisitionSdk.Callback<acquisitionSdk.Http.Response>): void {
67+
if (typeof requestBodyOrCallback !== "function") {
68+
throw new Error("Unexpected request body");
69+
}
70+
71+
callback = <acquisitionSdk.Callback<acquisitionSdk.Http.Response>>requestBodyOrCallback;
72+
callback(null, this.response);
73+
}
74+
}
75+
76+
class Server {
77+
public static onAcquire(params: any, callback: acquisitionSdk.Callback<acquisitionSdk.Http.Response>): void {
78+
if (params.deploymentKey !== validDeploymentKey) {
79+
callback(/*error=*/ null, {
80+
statusCode: 200,
81+
body: JSON.stringify({ update_info: { isAvailable: false } })
82+
});
83+
} else {
84+
callback(/*error=*/ null, {
85+
statusCode: 200,
86+
body: JSON.stringify({ update_info: latestPackage })
87+
});
88+
}
89+
}
90+
91+
public static onUpdateCheck(params: any, callback: acquisitionSdk.Callback<acquisitionSdk.Http.Response>, expectedStatusCode?: number): void {
92+
var updateRequest: types.UpdateCheckRequest = {
93+
deployment_key: params.deployment_key,
94+
app_version: params.app_version,
95+
package_hash: params.package_hash,
96+
is_companion: !!(params.is_companion),
97+
label: params.label
98+
};
99+
100+
if (!updateRequest.deployment_key || !updateRequest.app_version) {
101+
callback(/*error=*/ null, { statusCode: 400 });
102+
} else {
103+
var updateInfo = <types.UpdateCheckResponse>{ is_available: false };
104+
if (updateRequest.deployment_key === validDeploymentKey) {
105+
if (updateRequest.is_companion || updateRequest.app_version === latestPackage.target_binary_range) {
106+
if (updateRequest.package_hash !== latestPackage.package_hash) {
107+
updateInfo = latestPackage;
108+
}
109+
} else if (updateRequest.app_version < latestPackage.target_binary_range) {
110+
updateInfo = <types.UpdateCheckResponse><any>{ update_app_version: true, target_binary_range: latestPackage.target_binary_range };
111+
}
112+
}
113+
114+
callback(/*error=*/ null, {
115+
statusCode: expectedStatusCode ? expectedStatusCode : 200,
116+
body: JSON.stringify({ update_info: updateInfo })
117+
});
118+
}
119+
}
120+
121+
public static onReportStatus(callback: acquisitionSdk.Callback<acquisitionSdk.Http.Response>, expectedStatusCode: number): void {
122+
callback(/*error*/ null, /*response*/ { statusCode: expectedStatusCode ? expectedStatusCode : 200 });
123+
}
124+
}

0 commit comments

Comments
 (0)