@radhya/mach 2.5.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -18
- package/dist/chunk-QFXPWC5D.js +4 -0
- package/dist/chunk-UJHZ27JT.js +682 -0
- package/dist/commands/isolated-upload.js +1 -1
- package/dist/credentials-BSXCVQX5.js +1 -0
- package/dist/index.js +2399 -1
- package/docs/deep-links.md +20 -2
- package/docs/frameworks/README.md +13 -9
- package/docs/frameworks/flutter.md +120 -32
- package/docs/ota.md +28 -2
- package/docs/push.md +12 -1
- package/package.json +4 -3
- package/dist/chunk-BPQENJ3N.js +0 -46
- package/dist/chunk-ZHFE3HI3.js +0 -1
- package/dist/credentials-UZSOTKBK.js +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Cloud Build & Delivery for React Native, Expo, and Flutter**
|
|
4
4
|
|
|
5
|
-
Mach is a CLI that
|
|
5
|
+
Mach is a CLI that builds, signs, audits, versions, and submits Flutter, React Native, and Expo apps locally or in the cloud.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -21,7 +21,7 @@ mach push send --user user_123 --title "Hello" --body "Your update is ready."
|
|
|
21
21
|
mach push status --days 30
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
MACH Push supports Expo development builds and bare React Native. It
|
|
24
|
+
MACH Push supports Flutter, Expo development builds, and bare React Native. It
|
|
25
25
|
adds a working default permission, registration, receive, and tap flow while
|
|
26
26
|
leaving an editable callback file in the application. The app config only marks
|
|
27
27
|
push as enabled; MACH stores encrypted
|
|
@@ -41,6 +41,7 @@ mach link
|
|
|
41
41
|
# Run a cloud build
|
|
42
42
|
mach build --platform ios
|
|
43
43
|
mach build --platform android
|
|
44
|
+
mach build --platform web # Flutter projects
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
## Commands
|
|
@@ -61,7 +62,7 @@ mach build --platform android
|
|
|
61
62
|
| `mach env` | Manage, list, and download environment variables and secrets |
|
|
62
63
|
| `mach version` | Show and seed DB-owned native version counters |
|
|
63
64
|
| `mach config` | Show resolved configuration for a build profile |
|
|
64
|
-
| `mach start` | Start the
|
|
65
|
+
| `mach start` | Start Flutter or the React Native/Expo development server |
|
|
65
66
|
| `mach device` | Register test devices for ad-hoc distribution |
|
|
66
67
|
| `mach audit` | Check project health, delivery impact, and security locally |
|
|
67
68
|
| `mach agent` | Manage the local device discovery agent for Install Hub |
|
|
@@ -109,7 +110,8 @@ Useful options:
|
|
|
109
110
|
|
|
110
111
|
## Cloud Builds
|
|
111
112
|
|
|
112
|
-
Trigger a build in the cloud — Mach handles
|
|
113
|
+
Trigger a build in the cloud — Mach handles source upload, framework-specific
|
|
114
|
+
compilation, signing, and delivery of IPA, APK, or AAB artifacts.
|
|
113
115
|
|
|
114
116
|
```bash
|
|
115
117
|
# iOS build (production)
|
|
@@ -140,9 +142,9 @@ Supported values:
|
|
|
140
142
|
| ---------------- | ------------ | ------------------------------------------------------------------------------ |
|
|
141
143
|
| `react-native` | Supported | Uses committed `ios/` and `android/` native projects. No Expo prebuild runs. |
|
|
142
144
|
| `expo` | Supported | Runs Expo prebuild before native compilation and applies Expo-specific guards. |
|
|
143
|
-
| `flutter` |
|
|
145
|
+
| `flutter` | Supported | Uses Flutter/Dart with managed Android/iOS signing, web artifacts, caches, symbols, and submissions. |
|
|
144
146
|
|
|
145
|
-
`mach init` and `mach link`
|
|
147
|
+
`mach init` and `mach link` detect the selected app and save its framework. The saved value remains explicit, preventing one framework's build behavior from affecting another in CI.
|
|
146
148
|
|
|
147
149
|
Use the framework guide that matches your app. The command surface stays the same; only `framework` changes the build pipeline:
|
|
148
150
|
|
|
@@ -153,7 +155,7 @@ Use the framework guide that matches your app. The command surface stays the sam
|
|
|
153
155
|
|
|
154
156
|
## OTA Updates
|
|
155
157
|
|
|
156
|
-
Mach OTA
|
|
158
|
+
Mach OTA uses a framework-specific provider: Mach-hosted `expo-updates` for Expo and bare React Native, and customer-owned Shorebird for Flutter. Mach never stores `SHOREBIRD_TOKEN`.
|
|
157
159
|
|
|
158
160
|
```bash
|
|
159
161
|
mach ota setup
|
|
@@ -164,6 +166,15 @@ mach ota rollback --update-id <updateId>
|
|
|
164
166
|
mach ota promote --update-id <updateId>
|
|
165
167
|
```
|
|
166
168
|
|
|
169
|
+
For Flutter, the equivalent workflow is:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
mach ota setup --profile staging
|
|
173
|
+
mach ota release --platform all --profile staging
|
|
174
|
+
mach ota publish --platform all --profile staging --track staging --release-version latest
|
|
175
|
+
mach ota promote --release-version 1.2.0+42 --patch-number 1
|
|
176
|
+
```
|
|
177
|
+
|
|
167
178
|
`mach ota setup` uses the open-source `expo-updates` runtime for both Expo and bare React Native apps while keeping publishing, manifests, assets, channels, metrics, and rollback on Mach. It writes the `ota` config, installs or refreshes the compatible project-local plugin when approved, and wires `@radhya/mach/expo-plugin`. Updates are served from Mach instead of EAS Update.
|
|
168
179
|
|
|
169
180
|
For bare React Native, setup first installs Expo Modules when needed, then uses the installed `expo-updates configuration:syncnative` tool to update the committed Android and iOS projects. It does not run Expo prebuild or replace the native folders. Run setup from a clean branch so you can review the package and native integration changes.
|
|
@@ -178,6 +189,8 @@ Runtime precedence is `--runtime-version`, `ota.runtimeVersion`, `ota.runtimeVer
|
|
|
178
189
|
|
|
179
190
|
Bare React Native uses the same Expo Updates protocol and the same Mach endpoint as Expo. `mach-react-native` remains reserved for a future Mach-owned native runtime and cannot currently be selected for publishing.
|
|
180
191
|
|
|
192
|
+
Flutter setup initializes Shorebird, records only `engine: "shorebird"` and the default track, and delegates release/patch storage and delivery directly to the customer's Shorebird account. CI reads `SHOREBIRD_TOKEN` only from its environment. Native or asset changes still require a new base release; Dart-only compatible fixes can be patched.
|
|
193
|
+
|
|
181
194
|
See [OTA Updates](docs/ota.md) for setup behavior, bare React Native requirements, runtime matching, and validation.
|
|
182
195
|
|
|
183
196
|
## Deep Links
|
|
@@ -216,7 +229,7 @@ mach deeplink setup \
|
|
|
216
229
|
--output public
|
|
217
230
|
```
|
|
218
231
|
|
|
219
|
-
`setup` writes compact `deepLinks` settings into `mach.config.json`, generates Apple AASA and Android `assetlinks.json` files,
|
|
232
|
+
`setup` writes compact `deepLinks` settings into `mach.config.json`, generates Apple AASA and Android `assetlinks.json` files, wires an Expo config plugin for Expo projects, and safely patches Flutter's Android manifest plus iOS entitlements/URL scheme. Re-running it is idempotent. The interactive flow can also enable iOS Web Credentials for HTTPS OAuth callbacks and Android Login Credentials for website password and passkey sharing; both remain disabled by default. For Expo apps, Mach prefers `@radhya/mach/expo-plugin`; interactive setup offers to install `@radhya/mach` locally, and `--yes` or `--install-plugin` installs it automatically. Use `--no-install-plugin` to skip package installation; if the package is missing, Mach generates a local `./plugins/withMachDeepLinks` fallback. See [Deep Links](docs/deep-links.md).
|
|
220
233
|
|
|
221
234
|
## Local Device Agent
|
|
222
235
|
|
|
@@ -457,13 +470,15 @@ Create a `mach.config.json` in your project root:
|
|
|
457
470
|
| `framework` | Required build framework: `react-native`, `expo`, or `flutter`. Builds never infer this from `package.json` |
|
|
458
471
|
| `appDirectory` | Optional mobile app path relative to the repository root, for example `apps/mobile`. Defaults to `"."` for existing projects. |
|
|
459
472
|
| `name` | App display name |
|
|
460
|
-
| `nodeVersion` | Node.js version
|
|
473
|
+
| `nodeVersion` | React Native/Expo Node.js version (e.g. `"24"`, `"20.11.0"`). Flutter builds do not use this field |
|
|
474
|
+
| `flutter.sdkVersion` | Exact Flutter stable SDK for managed builds. `mach init` and `mach link` pin the installed SDK automatically |
|
|
461
475
|
|
|
462
476
|
### Monorepo Layout
|
|
463
477
|
|
|
464
|
-
Keep `mach.config.json
|
|
465
|
-
|
|
466
|
-
bare React Native
|
|
478
|
+
Keep `mach.config.json` and the workspace configuration at the repository root.
|
|
479
|
+
For JavaScript workspaces, keep the package-manager lockfile there too. Set
|
|
480
|
+
`appDirectory` when an Expo, bare React Native, or Flutter application lives
|
|
481
|
+
below the root:
|
|
467
482
|
|
|
468
483
|
```json
|
|
469
484
|
{
|
|
@@ -472,9 +487,10 @@ bare React Native app lives below that root:
|
|
|
472
487
|
}
|
|
473
488
|
```
|
|
474
489
|
|
|
475
|
-
Mach uploads
|
|
476
|
-
|
|
477
|
-
|
|
490
|
+
Mach uploads from the repository root, resolves npm/Yarn/pnpm or Dart pub
|
|
491
|
+
workspace dependencies as appropriate, and runs the selected framework's
|
|
492
|
+
native toolchain from `appDirectory`. Root-level projects need no config change
|
|
493
|
+
and continue to use `"."`.
|
|
478
494
|
|
|
479
495
|
### Platform Properties
|
|
480
496
|
|
|
@@ -497,6 +513,12 @@ change and continue to use `"."`.
|
|
|
497
513
|
| `distribution` | `development` for iOS development signing, `internal` for ad-hoc/internal testing builds, or `store` for App Store / Play Store release builds |
|
|
498
514
|
| `android.emulator` | `true` to include Android emulator ABI support (`x86_64`) for Maestro/e2e APK builds |
|
|
499
515
|
| `android.architectures` | Override Android release ABIs, for example `armeabi-v7a,arm64-v8a,x86_64` |
|
|
516
|
+
| `flutter.flavor` | Flutter Android product flavor and shared iOS scheme. Omit for unflavored apps |
|
|
517
|
+
| `flutter.target` | Dart entrypoint relative to `appDirectory`; defaults to `lib/main.dart` |
|
|
518
|
+
| `flutter.mode` | Flutter compilation mode: `debug`, `profile`, or `release` |
|
|
519
|
+
| `flutter.dartDefinesFromEnv` | Environment-key names passed with `--dart-define`. Values are compiled into the app and must not be secrets |
|
|
520
|
+
| `flutter.obfuscate` | Obfuscate Dart code for Android/iOS release builds and retain downloadable split debug symbols |
|
|
521
|
+
| `flutter.splitDebugInfo` | Retain downloadable split debug symbols without otherwise changing app behavior |
|
|
500
522
|
| `preBuild` / `postBuild` | Shell command or script reference to run around the build |
|
|
501
523
|
| `envGroups` | Array of environment group names to merge into this profile |
|
|
502
524
|
|
|
@@ -648,9 +670,9 @@ press `i` for iOS, `a` for Android, `w` for web, and `r` to reload. Use the flag
|
|
|
648
670
|
|
|
649
671
|
`mach audit` combines doctor-style environment checks, delivery-impact advice,
|
|
650
672
|
and security scanning in one offline-friendly command. It validates Mach config,
|
|
651
|
-
framework and profile consistency, app identifiers, Node
|
|
652
|
-
dependency alignment, permissions, secrets,
|
|
653
|
-
and native manifests when available.
|
|
673
|
+
framework and profile consistency, app identifiers, Node or Flutter/Dart
|
|
674
|
+
toolchains, lockfiles, dependency alignment, permissions, secrets, storage,
|
|
675
|
+
networking, and native manifests when available.
|
|
654
676
|
|
|
655
677
|
```bash
|
|
656
678
|
mach audit
|
|
@@ -706,6 +728,7 @@ mach submit --latest --platform android --profile production
|
|
|
706
728
|
## Requirements
|
|
707
729
|
|
|
708
730
|
- Node.js 18+
|
|
731
|
+
- For local Flutter builds: the Flutter SDK version pinned in `mach.config.json`
|
|
709
732
|
- For iOS builds: Xcode (local builds) or cloud build subscription
|
|
710
733
|
- For Android builds: Android SDK (local builds) or cloud build subscription
|
|
711
734
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var o={name:"Mach",nameLower:"mach",nameUpper:"MACH",company:"Radhya Softlabs",npmScope:"@radhya",configFileName:"mach.config.json",configDir:".mach",workspacesDir:".mach-workspaces",remoteWorkspacesDir:"mach_workspaces",envPrefix:"MACH_",bucketPrefix:"skye-builds-385229479322",buildPrefix:"mach-build",credentialsKeychain:"mach-credentials.keychain",keychainPassword:"mach",cliTag:e=>` Mach CLI - ${e} `,fastlanePrefix:"mach",jsonStartMarker:"___MACH_JSON_START___",jsonEndMarker:"___MACH_JSON_END___",prewarmedMarker:"/opt/mach-prewarmed"};import s from"fs";import f from"path";import y from"os";import v from"axios";var m=f.join(y.homedir(),o.configDir),d=f.join(m,"credentials.json");function h(){return process.env[`${o.envPrefix}TOKEN`]?.trim()||void 0}function T(e){s.existsSync(m)||s.mkdirSync(m,{recursive:!0}),s.writeFileSync(d,JSON.stringify(e,null,2))}function l(){let e=h();if(e)return{token:e,email:"token-auth"};if(!s.existsSync(d))return null;try{return JSON.parse(s.readFileSync(d,"utf-8"))}catch{return null}}function I(){return s.existsSync(d)?(s.unlinkSync(d),!0):!1}function $(){let e=h();if(e)return{token:e,email:"token-auth"};let r=l();if(r?.token)return r;console.error(`\x1B[31mAuthentication required.\x1B[0m Either:
|
|
2
|
+
1. Run \x1B[33m${o.nameLower} login\x1B[0m for interactive login
|
|
3
|
+
2. Set \x1B[33m${o.envPrefix}TOKEN\x1B[0m environment variable for CI/CD`),process.exit(1)}async function k(e){let r=l();if(!r||!r.refreshToken)return null;try{let t=await v.post(`${e}/refresh-token`,{username:r.email,refreshToken:r.refreshToken});if(t.data.status==="success"&&t.data.user){let n={...r,id:t.data.user.id||r.id,token:t.data.user.token,refreshToken:t.data.user.refreshToken||r.refreshToken};return T(n),n.token}}catch{}return null}import A from"axios";import g from"dotenv";import x from"path";import{fileURLToPath as C}from"url";var b=x.dirname(C(import.meta.url));g.config({path:x.join(b,"../.env"),quiet:!0});var c=process.env[`${o.envPrefix}API_URL`]||"https://mach-api.securejs.in",_="https://getmach.dev",D=c.includes("localhost:3001")||c.includes("127.0.0.1:3001")?c.replace("3001","8081"):_,B=process.env[`${o.envPrefix}DASHBOARD_URL`]||D;var u=A.create({baseURL:c,headers:{Connection:"close"}});u.interceptors.request.use(e=>{let t=l()?.token||process.env[`${o.envPrefix}TOKEN`];return t&&(e.headers.Authorization=`Bearer ${t}`),e},e=>Promise.reject(e));u.interceptors.response.use(e=>e,async e=>{let{config:r}=e;if((!e.response||e.code==="ECONNRESET"||e.code==="ETIMEDOUT")&&(!r._retryCount||r._retryCount<3)){r._retryCount=(r._retryCount||0)+1;let n=Math.pow(2,r._retryCount-1)*1e3;return console.warn(`\x1B[33m[NETWORK] Transient error (${e.code||"UNKNOWN"}). Retrying in ${n/1e3}s... (Attempt ${r._retryCount}/3)\x1B[0m`),await new Promise(a=>setTimeout(a,n)),u(r)}return Promise.reject(e)});u.interceptors.response.use(e=>e,async e=>{let r=e.config;if(e.response?.status===401&&!r._retry){if(r._retry=!0,process.env[`${o.envPrefix}TOKEN`])return console.error(`\x1B[31mAuthentication failed.\x1B[0m Your ${o.envPrefix}TOKEN may be invalid or expired.
|
|
4
|
+
Generate a new token at the ${o.name} Dashboard \u2192 Settings \u2192 Access Tokens.`),Promise.reject(e);try{let n=await k(c);if(n)return r.headers.Authorization=`Bearer ${n}`,u(r)}catch(n){return Promise.reject(n)}}return Promise.reject(e)});var p=e=>String(e||"").trim().toLowerCase().replace(/_/g,"-");function S(e){let r=p(e);if(["development","dev"].includes(r))return"development";if(["adhoc","ad-hoc","internal","staging","stage","preview"].includes(r))return"adhoc";if(["store","app-store","appstore","production","prod"].includes(r))return"store"}function X(e){if(e.storedDistributionType!==e.requestedDistributionType)throw new Error(`Dashboard stored ${e.credentialType} as ${String(e.storedDistributionType||"unknown")} instead of ${e.requestedDistributionType}.`)}function Z(e){let r=S(e.requestedCredentialType);if(r)return r;let t=e.profile||{};if(t.developmentClient||t.simulator||t.ios?.simulator)return"development";let n=p(t.distribution),a=p(t.iosExportMethod||t.ios?.exportMethod),i=p(t.environment);return a==="app-store"||n==="store"?"store":a==="development"||n==="development"?"development":a==="ad-hoc"||a==="adhoc"||n==="ad-hoc"||n==="adhoc"||n==="internal"?"adhoc":i==="production"||i==="store"?"store":i==="development"||i==="dev"?"development":"adhoc"}export{o as a,T as b,l as c,I as d,$ as e,c as f,B as g,u as h,S as i,X as j,Z as k};
|