Skip to content

Commit aa57749

Browse files
robingenzclaude
andcommitted
docs: the build step is two commands the native build chooses between, and init wires Capacitor as it wires React Native
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 84ed5e3 commit aa57749

2 files changed

Lines changed: 16 additions & 16 deletions

File tree

‎CLAUDE.md‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ When code and plan disagree, stop and surface it; never improvise.
1313
```
1414
src/
1515
index.ts the registry: space-separated command names, each a lazy import
16-
commands/ a folder per noun and a file per verb, channel/create.ts; the standalone commands flat, login.ts, init.ts, doctor.ts, open.ts
16+
commands/ a folder per noun and a file per verb, channel/create.ts, resource-file/write.ts; the standalone commands flat, login.ts, init.ts, doctor.ts, open.ts
1717
utils/ the runner, command resolution and did-you-mean, the E_ catalog and its one mapping,
1818
the global options, environment detection, config.json, the token store,
1919
the auth client, the API client, hotcodepush.json and its directory, the JSON files a person edits read as `E_INVALID_JSON` when they do not parse, a resource by id or name,
@@ -28,16 +28,16 @@ src/
2828
the pack writer, the git provenance, the device hosts derived from the API URL,
2929
the upload flow, the private key an upload is given, read into the pair that signs, and the writer of its file,
3030
the delta bases, the main bundle's patches and the bsdiff module behind one function,
31-
the store build's binary identity from the native projects, the resource file,
31+
the build step both commands share, the resource file,
3232
the progress lines, the browser opener, the JSON, tables and details output,
3333
init's step runner, the outcome rows init and doctor print, the package manager and its visible runs,
34-
the binary create hook in package.json, the resource reference and the binary create phase in the Xcode project,
34+
the native-project edits: the binary create phase in the Xcode project and the removal of the resource reference an earlier init added, package.json reading,
3535
the lines a React Native project is wired with
3636
config/ consts: the API URL, the client id and header, the config file, the docs and issues URLs,
3737
the keyring entry, package.json, the project file, the SDK packages' names and pinned specs,
3838
the manual step that runs `init`
3939
test/ the command tests' harness, the API faked behind fetch, their fixtures, the release routes
40-
and the Capacitor project a test writes, with the pbxproj of `cap add ios`, the fingerprint inputs,
40+
and the Capacitor project a test writes, with the pbxproj of `cap add ios`, its Gradle file and the old resource reference, the fingerprint inputs,
4141
the Cordova project with its `config.xml`, the React Native project with its pbxproj,
4242
the protocol's fixtures read from the installed package; never built
4343
bsdiff-wasm/ the bsdiff module, our build of the Rust crate `qbsdiff`: the crate that wraps it, its `Cargo.lock`,
@@ -78,14 +78,14 @@ No releases yet: the version stays `0.0.0`, and release-please and npm provenanc
7878

7979
## Adding a framework
8080

81-
1. `src/utils/frameworks/<framework>.ts` exports a `FrameworkModule`: the build output, the native projects, the resource file's place,
82-
the store build's identity, what `init` installs and wires, what `doctor` checks, and, where the framework has one,
81+
1. `src/utils/frameworks/<framework>.ts` exports a `FrameworkModule`: the build output, the native projects, what `init` installs and wires,
82+
what `doctor` checks, and, where the framework has one,
8383
the optional `resolveMainBundlePath`, which names the main JavaScript bundle among a bundle's files for the delta packs to carry as a patch.
8484
2. One line joins the registry in `src/utils/frameworks/index.ts`.
8585
3. Nothing outside the module names the framework: a command asks the module, never a config file or a path of its own.
8686

87-
Capacitor's module reads `capacitor.config` as text and the native projects' own files; Cordova's reads `config.xml` through `fast-xml-parser` and derives the store build's identity as Cordova's prepare does.
88-
React Native's and Expo's have no build output to read and share React Native's release build in `frameworks/react-native-build.ts`: `packageReactNativeBundles` runs the module's bundler and Hermes' compiler per platform into the command's packaging directory, one bundle each, `collectEmbeddedFiles` takes `main.jsbundle` and `assets/` out of the app the Xcode phase points at, the native build passes the identity and `--out` in, and `resolveMainBundlePath` answers `main.jsbundle` on iOS and `index.android.bundle` on Android where a bundle's files hold it.
87+
Capacitor's module reads `capacitor.config` as text and no native file; Cordova's reads `config.xml` through `fast-xml-parser` for the file-mode preference alone. The store build's identity comes from the build on every framework, never from a project file: the hook script passes the version and the build number it read from the processed `Info.plist` or the variant. Capacitor and React Native are wired the same way, `init` adding the phase and the Gradle line; Cordova's plugin and Expo's config plugin wire themselves.
88+
React Native's and Expo's have no build output to read and share React Native's release build in `frameworks/react-native-build.ts`: `packageReactNativeBundles` runs the module's bundler and Hermes' compiler per platform into the command's packaging directory, one bundle each, `collectEmbeddedFiles` takes `main.jsbundle` and `assets/` out of the app the Xcode phase points at, the native build passes the identity and `--resource-file-path` in, and `resolveMainBundlePath` answers `main.jsbundle` on iOS and `index.android.bundle` on Android where a bundle's files hold it.
8989
The bundler is all the two differ in there: `react-native bundle` with the project's entry file for React Native, `expo export:embed`, which resolves the entry file itself, for Expo.
9090
`--path` is the prepared bundle directory of the one platform `--platform` names, refused without the JavaScript under the name that platform's app loads.
9191
React Native's wiring is five edits, each recognised afterwards by what it wrote: the Xcode phase through the `xcode` package, and one line each in `build.gradle`, `AppDelegate.swift`, `MainApplication.kt` and the Podfile, in `utils/react-native-project.ts`.
@@ -117,8 +117,8 @@ A project with an app config that is code, or with a JSON one that does not pars
117117
- **Commands call commands**: a command that needs what another does runs that command's action in place, never a copy of its logic.
118118
- **A command that reports several outcomes** — `init`'s steps, `doctor`'s checks — prints them itself and ends with `ReportedFailureError` when one failed,
119119
so the exit code is set without a second message; nothing else throws it.
120-
- **`init` and `binary create` edit only what they can recognise afterwards**: the hook script gains the `binary create` command or is returned as the manual step,
121-
the Xcode project gains one resource reference or one run-script phase through the `xcode` package, a React Native project's other files one line each,
120+
- **`init` edits only what it can recognise afterwards**: the Xcode project gains one run-script phase through the `xcode` package and loses the resource reference an earlier `init` added,
121+
a Capacitor or React Native project's other files one line each,
122122
an Expo project's JSON app config one plugin entry,
123123
and `init` names the files it will change and asks once before touching them.
124124
- **The token** is `readToken()`: `HOTCODEPUSH_TOKEN` when set, then the keyring, then the `config.json` fallback that any keyring failure latches for the rest of the process.
@@ -148,9 +148,9 @@ A project with an app config that is code, or with a JSON one that does not pars
148148
A patch that cannot be made — a base file the files host does not answer or answers with other bytes, a diff that fails — sends the file whole and says so in one line, never failing the upload.
149149
A patch is made once per pair of contents, however many bases share it; the base files are fetched by hash from the files host three at a time, and the diffs run one after another.
150150
bsdiff goes through `utils/bsdiff.ts` alone, over the module in `bsdiff-wasm/`: the BSDIFF40 format the SDKs apply, the algorithm `qbsdiff`'s and never written here.
151-
- **`binary create` resolves the channel before it writes anything**: an id is taken as it is and never asks the API; a name is resolved through the API, which alone knows the id the resource file carries, and a name the app lacks fails everywhere with `E_INVALID_PARAMETER`.
152-
A build that cannot ask still builds: with `HOTCODEPUSH_OFFLINE=1`, read in `utils/environment.ts` and honoured in CI too, or without a token locally, the API is asked nothing, the resource file carries `channelId: null` or the id it was given, no binary is created, one warning is printed and the exit is 0; an API that cannot be reached or refuses while a name is resolved ends the same way locally.
153-
CI is the loud half: without a token the build fails with `E_NOT_LOGGED_IN`, exit 3, its fix naming `HOTCODEPUSH_TOKEN` and `HOTCODEPUSH_OFFLINE=1` for a build that is never shipped, and a failed resolution or a failed creation fails the build there, `E_BINARY_CONFLICT` under an unbumped build number being a pipeline mistake.
151+
- **The build step is two commands over one module, `utils/build-step.ts`**: `resource-file write` resolves the channel and writes the resource file; `binary create` does the same and creates the binary first, so the file carries its embedded bundle's id. An id is taken as it is and never asks the API; a name is resolved through the API, which alone knows the id the resource file carries, and a name the app lacks fails everywhere with `E_INVALID_PARAMETER`.
152+
`resource-file write` never fails for want of a token or an API, in CI too: with `HOTCODEPUSH_OFFLINE=1`, read in `utils/environment.ts`, or without a token, the API is asked nothing, the file carries `channelId: null` or the id it was given, one warning is printed and the exit is 0; an API that cannot be reached or refuses while a name is resolved ends the same way.
153+
`binary create` is the same on a laptop, warning and creating nothing, and loud in CI: without a token the build fails with `E_NOT_LOGGED_IN`, exit 3, its fix naming `HOTCODEPUSH_TOKEN`, and a failed resolution or a failed creation fails the build there, `E_BINARY_CONFLICT` under an unbumped build number being a pipeline mistake. `isCi()` decides that alone; whether a binary is created is the hook script's choice, by the build's own variables, never the CLI's.
154154
A build that bundled nothing — a React Native or Expo debug build, Metro serving its JavaScript — is neither: before any token is read, the file is written with `embeddedBundle: null` and the channel id only where the project named the channel by id, no binary is created, one line on stderr says so and the exit is 0; every check in that build answers `SKIPPED` with `BUILD_DEBUG`.
155155
The fingerprint is the strict half too: a project the recipe cannot read is `E_FINGERPRINT_UNAVAILABLE` on `binary create` and upload alike, never `null`, since a release targets it.
156156
The device hosts it writes derive from the API URL: none for production, the staging hosts for staging, `<apiUrl>/files` and `/updates` for any other, `HOTCODEPUSH_FILES_BASE_URL` and `HOTCODEPUSH_UPDATES_BASE_URL` overriding.

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ npx hotcodepush fingerprint diff store-build.json fingerprint.json
4545
```
4646

4747
`init` takes a Capacitor, Cordova, Expo or React Native project from sign-in to the first release — the organization, the app, the SDK package from its pkg.pr.new build until it is published, `hotcodepush.json` and the build step — re-runnable at any step, each step `done`, `skipped` or `stopped` with the manual step; `doctor` is the read-only check of the same, and `open` opens the app's console page.
48-
On Capacitor the build step is the `capacitor:copy:after` hook and the iOS resource reference, which `init` wires; on Cordova `init` runs `cordova plugin add`, and the plugin brings its own `after_prepare` hook, so nothing is wired.
48+
On Capacitor `init` adds the Xcode phase "Create HotCodePush binary" after the app target's last phase and one `apply from` line to `android/app/build.gradle`, which run the build step inside the native build, and removes the resource reference an earlier `init` added; on Cordova `init` runs `cordova plugin add`, and the plugin wires its own Xcode phase and Gradle task, so nothing is wired.
4949
On React Native `init` adds the Xcode phase "Create HotCodePush binary" after "Bundle React Native code and images" and one `apply from` line to `android/app/build.gradle`, which run the build step inside the native build, makes `AppDelegate.swift` and `MainApplication.kt` ask the SDK for the bundle React Native runs, pins the `HotCodePushCore` pod in the Podfile until it is published, and runs `pod install`; an edit a file has no place for is that step's manual step, and `hotcodepush.json` names no `dir`.
5050
On Expo `init` installs the package and adds its config plugin to the app config, `app.config.json` where the project has one and `app.json` otherwise; the plugin wires the native projects at `npx expo prebuild` as `init` wires a React Native project, so `init` edits no native file and runs no prebuild.
5151
Beside an app config that is code, or with a JSON one the CLI cannot parse, `init` edits no app config and the entry to add is that step's manual step; `hotcodepush.json` names no `dir` on Expo either.
@@ -69,9 +69,9 @@ A release carries its conditions as flags — `--binary`, `--os`, `--attribute`
6969
`release revoke` takes one release, every release from a number on with `--release-from`, a channel's whole log with `--all`, or every release of a bundle with `--bundle`; revoked is final, and the confirmation says how many releases move and where their devices land.
7070
`device probe` answers why a device did not update: it reads the live index as a device would, evaluates every release in the frontier for the facts given, or for a registered device with `--device`, and marks each condition passed, failed or unknown.
7171
`statistics get` reads the fleet, the updates or the usage of an app, chosen with `--type`, and `fingerprint` prints the native contract's hash with the packages and native sources behind it, without a login; `fingerprint diff` takes two files `fingerprint --json` wrote, the store build's first, and prints the packages and native sources added, removed or moved between them, so a release the store build cannot take names the package that moved.
72-
`binary create` is the build step the native hook runs — `npx hotcodepush binary create` from Capacitor's `capacitor:copy:after`, the Cordova plugin's `after_prepare`, or the Xcode phase and the Gradle task of a React Native or Expo build, which pass in the version, the build number and where the file goes — writing the resource file the SDK reads and creating the store build's binary in HotCodePush, with the bundle it ships and its fingerprint; a Cordova build takes its version and build number from `config.xml`, as Cordova itself derives them.
72+
The build step runs inside every native build, from the Xcode phase and the Gradle task the SDK ships, which pass in the platform, the embedded bundle's directory and where the resource file goes: an Xcode archive or a Gradle release variant runs `binary create`, which creates the store build's binary in HotCodePush, with the bundle it ships and its fingerprint, and writes the resource file the SDK reads; every other build runs `resource-file write`, which writes the same file and creates nothing. The version and build number come from the build itself on every framework, the processed `Info.plist` on iOS and the variant on Android.
7373
A React Native or Expo build that bundled nothing, a debug build Metro serves, gets the file without an embedded bundle and with the channel only where `hotcodepush.json` names it by id, no binary, no request and no login, so every check in that build answers `SKIPPED` with `BUILD_DEBUG`.
74-
Without a token, or with `HOTCODEPUSH_OFFLINE=1` for a build that is never shipped, it writes the file without a channel and creates no binary, so the build takes no updates; in CI a missing token fails the build instead.
74+
`resource-file write` never fails for want of a token or an API: without a token, or with `HOTCODEPUSH_OFFLINE=1`, it writes the file without a channel, so the build takes no updates, and says so. `binary create` behaves the same on a laptop, warning and creating no binary, and fails the build in CI, where a missing token, an unreachable API or a conflicting binary is a pipeline mistake someone must see.
7575

7676
## Documentation
7777

0 commit comments

Comments
 (0)