You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit aa57749
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CLAUDE.md
+13-13Lines changed: 13 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ When code and plan disagree, stop and surface it; never improvise.
13
13
```
14
14
src/
15
15
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
17
17
utils/ the runner, command resolution and did-you-mean, the E_ catalog and its one mapping,
18
18
the global options, environment detection, config.json, the token store,
19
19
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/
28
28
the pack writer, the git provenance, the device hosts derived from the API URL,
29
29
the upload flow, the private key an upload is given, read into the pair that signs, and the writer of its file,
30
30
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,
32
32
the progress lines, the browser opener, the JSON, tables and details output,
33
33
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,
35
35
the lines a React Native project is wired with
36
36
config/ consts: the API URL, the client id and header, the config file, the docs and issues URLs,
37
37
the keyring entry, package.json, the project file, the SDK packages' names and pinned specs,
38
38
the manual step that runs `init`
39
39
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,
41
41
the Cordova project with its `config.xml`, the React Native project with its pbxproj,
42
42
the protocol's fixtures read from the installed package; never built
43
43
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
78
78
79
79
## Adding a framework
80
80
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,
83
83
the optional `resolveMainBundlePath`, which names the main JavaScript bundle among a bundle's files for the delta packs to carry as a patch.
84
84
2. One line joins the registry in `src/utils/frameworks/index.ts`.
85
85
3. Nothing outside the module names the framework: a command asks the module, never a config file or a path of its own.
86
86
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.
89
89
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.
90
90
`--path` is the prepared bundle directory of the one platform `--platform` names, refused without the JavaScript under the name that platform's app loads.
91
91
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
117
117
-**Commands call commands**: a command that needs what another does runs that command's action in place, never a copy of its logic.
118
118
-**A command that reports several outcomes** — `init`'s steps, `doctor`'s checks — prints them itself and ends with `ReportedFailureError` when one failed,
119
119
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,
122
122
an Expo project's JSON app config one plugin entry,
123
123
and `init` names the files it will change and asks once before touching them.
124
124
-**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
148
148
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.
149
149
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.
150
150
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.
154
154
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`.
155
155
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.
156
156
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.
`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.
49
49
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`.
50
50
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.
51
51
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`
69
69
`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.
70
70
`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.
71
71
`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.
73
73
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 CIa 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.
0 commit comments