rnbuilder 0.6.68 → 0.6.70

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 CHANGED
@@ -22,7 +22,7 @@ $ npm install -g rnbuilder
22
22
  $ rnbuilder COMMAND
23
23
  running command...
24
24
  $ rnbuilder (-v|--version|version)
25
- rnbuilder/0.6.68 darwin-arm64 node-v24.13.0
25
+ rnbuilder/0.6.70 darwin-arm64 node-v24.13.0
26
26
  $ rnbuilder --help [COMMAND]
27
27
  USAGE
28
28
  $ rnbuilder COMMAND
@@ -64,6 +64,7 @@ OPTIONS
64
64
  -g, --gitReset Do git reset when building
65
65
  -h, --help show CLI help
66
66
  -i, --installr=installr If enabled, the build will be uploaded to installR
67
+ -n, --install Install dependencies before building
67
68
  -s, --cleanup Do cleanup when building
68
69
  -t, --target=android|ios|android,ios Set the build target: android, ios or both
69
70
  -t, --testersIos=testersIos Tester ids for iOS distribution
@@ -78,7 +79,7 @@ EXAMPLE
78
79
  hello world from ./src/build.ts!
79
80
  ```
80
81
 
81
- _See code: [src/commands/build.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/build.ts)_
82
+ _See code: [src/commands/build.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/build.ts)_
82
83
 
83
84
  ## `rnbuilder check-version [MATCH-CHECK]`
84
85
 
@@ -97,7 +98,7 @@ EXAMPLE
97
98
  Nuke certificates ./src/match-check.ts!
98
99
  ```
99
100
 
100
- _See code: [src/commands/check-version.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/check-version.ts)_
101
+ _See code: [src/commands/check-version.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/check-version.ts)_
101
102
 
102
103
  ## `rnbuilder codepush [BUILD]`
103
104
 
@@ -116,7 +117,7 @@ EXAMPLE
116
117
  Push changes to existing apps ./src/firebase-sync-udids.ts!
117
118
  ```
118
119
 
119
- _See code: [src/commands/codepush.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/codepush.ts)_
120
+ _See code: [src/commands/codepush.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/codepush.ts)_
120
121
 
121
122
  ## `rnbuilder google-key [MATCH-CHECK]`
122
123
 
@@ -135,7 +136,7 @@ EXAMPLE
135
136
  Nuke certificates ./src/match-check.ts!
136
137
  ```
137
138
 
138
- _See code: [src/commands/google-key.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/google-key.ts)_
139
+ _See code: [src/commands/google-key.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/google-key.ts)_
139
140
 
140
141
  ## `rnbuilder help [COMMAND]`
141
142
 
@@ -167,7 +168,7 @@ EXAMPLE
167
168
  initialize environment for first run from ./src/initialize.ts!
168
169
  ```
169
170
 
170
- _See code: [src/commands/initialize.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/initialize.ts)_
171
+ _See code: [src/commands/initialize.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/initialize.ts)_
171
172
 
172
173
  ## `rnbuilder match-check [MATCH-CHECK]`
173
174
 
@@ -186,7 +187,7 @@ EXAMPLE
186
187
  Check match certificates ./src/match-check.ts!
187
188
  ```
188
189
 
189
- _See code: [src/commands/match-check.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/match-check.ts)_
190
+ _See code: [src/commands/match-check.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/match-check.ts)_
190
191
 
191
192
  ## `rnbuilder match-nuke [BUILD]`
192
193
 
@@ -205,7 +206,7 @@ EXAMPLE
205
206
  Nuke certificates ./src/match-nuke.ts!
206
207
  ```
207
208
 
208
- _See code: [src/commands/match-nuke.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/match-nuke.ts)_
209
+ _See code: [src/commands/match-nuke.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/match-nuke.ts)_
209
210
 
210
211
  ## `rnbuilder onesignal [BUILD]`
211
212
 
@@ -227,7 +228,7 @@ EXAMPLE
227
228
  Create and upload push certificate to One Signal from ./src/commands/onesignal.ts!
228
229
  ```
229
230
 
230
- _See code: [src/commands/onesignal.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/onesignal.ts)_
231
+ _See code: [src/commands/onesignal.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/onesignal.ts)_
231
232
 
232
233
  ## `rnbuilder reject-review [REJECT-REVIEW]`
233
234
 
@@ -245,7 +246,7 @@ EXAMPLE
245
246
  $ rnbuilder reject-review
246
247
  ```
247
248
 
248
- _See code: [src/commands/reject-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/reject-review.ts)_
249
+ _See code: [src/commands/reject-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/reject-review.ts)_
249
250
 
250
251
  ## `rnbuilder setup [SETUP]`
251
252
 
@@ -263,7 +264,7 @@ EXAMPLE
263
264
  hello world from ./src/setup.ts!
264
265
  ```
265
266
 
266
- _See code: [src/commands/setup.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/setup.ts)_
267
+ _See code: [src/commands/setup.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/setup.ts)_
267
268
 
268
269
  ## `rnbuilder submit-review [SUBMIT-REVIEW]`
269
270
 
@@ -282,7 +283,7 @@ EXAMPLE
282
283
  Push changes to existing apps ./src/firebase-sync-udids.ts!
283
284
  ```
284
285
 
285
- _See code: [src/commands/submit-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/submit-review.ts)_
286
+ _See code: [src/commands/submit-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/submit-review.ts)_
286
287
 
287
288
  ## `rnbuilder sync-udids [BUILD]`
288
289
 
@@ -301,5 +302,5 @@ EXAMPLE
301
302
  Sync device UDIDs from firebase from ./src/firebase-sync-udids.ts!
302
303
  ```
303
304
 
304
- _See code: [src/commands/sync-udids.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.68/src/commands/sync-udids.ts)_
305
+ _See code: [src/commands/sync-udids.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.70/src/commands/sync-udids.ts)_
305
306
  <!-- commandsstop -->
@@ -19,6 +19,7 @@ export default class Build extends Command {
19
19
  groupsIos: flags.IOptionFlag<string | undefined>;
20
20
  groupsAndroid: flags.IOptionFlag<string | undefined>;
21
21
  skipCheckVersion: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
22
+ install: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
22
23
  };
23
24
  static args: {
24
25
  name: string;
@@ -205,7 +205,8 @@ class Build extends command_1.Command {
205
205
  : 'email(s)'),
206
206
  suffix: ' for iOS (separated by commas)',
207
207
  default: testersAnswer.testers === 'groups'
208
- ? (_c = answers.groupsAndroid) !== null && _c !== void 0 ? _c : common_1.getTesterGroups(this.fastlaneConfigs, result.env) : answers.testersAndroid,
208
+ ? ((_c = answers.groupsAndroid) !== null && _c !== void 0 ? _c : common_1.getTesterGroups(this.fastlaneConfigs, result.env))
209
+ : answers.testersAndroid,
209
210
  },
210
211
  ]);
211
212
  result = Object.assign(Object.assign({}, result), anotherAnswer);
@@ -253,13 +254,15 @@ class Build extends command_1.Command {
253
254
  if (flags.cleanup) {
254
255
  shell.exec('rm -rf android/.gradle android/build android/app/build android/app/.cxx node_modules');
255
256
  }
256
- const installCmd = shell.test('-f', 'bun.lockb') || shell.test('-f', 'bun.lock')
257
- ? 'bun install'
258
- : shell.test('-f', 'pnpm-lock.yaml')
259
- ? 'pnpm install'
260
- : 'yarn install';
261
- shell.exec(installCmd);
262
- shell.exec('cd android && ./gradlew generateCodegenArtifactsFromSchema');
257
+ if (flags.install) {
258
+ const installCmd = shell.test('-f', 'bun.lockb') || shell.test('-f', 'bun.lock')
259
+ ? 'bun install'
260
+ : shell.test('-f', 'pnpm-lock.yaml')
261
+ ? 'pnpm install'
262
+ : 'yarn install';
263
+ shell.exec(installCmd);
264
+ shell.exec('cd android && ./gradlew generateCodegenArtifactsFromSchema');
265
+ }
263
266
  if (client) {
264
267
  client.forEach((cl) => {
265
268
  const c = cl.split(' ')[0];
@@ -345,5 +348,10 @@ Build.flags = {
345
348
  skipCheckVersion: command_1.flags.boolean({
346
349
  description: 'Skip checking current version on stores',
347
350
  }),
351
+ install: command_1.flags.boolean({
352
+ char: 'n',
353
+ description: 'Install dependencies before building',
354
+ default: false,
355
+ }),
348
356
  };
349
357
  Build.args = [{ name: 'build' }];
@@ -99,6 +99,9 @@ class Setup extends command_1.Command {
99
99
  // Setup fastlane
100
100
  const { firebaseIosApp, firebaseAndroidApp } = await fastlane_1.setupFastlane({
101
101
  client,
102
+ bundleId,
103
+ applicationId,
104
+ appName,
102
105
  });
103
106
  const fastlaneDir = path.join(process.cwd(), `fastlane/clients/${client}/fastlane`);
104
107
  const fastlaneEnvVars = env_1.readEnvVars(path.join(fastlaneDir, '/.env'));
@@ -0,0 +1,4 @@
1
+ export declare function addProductFlavor({ client, applicationId, }: {
2
+ client: string;
3
+ applicationId: string;
4
+ }): void;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addProductFlavor = void 0;
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ function insertIntoProductFlavors(gradle, flavor) {
7
+ // Find productFlavors block and insert before its closing brace
8
+ const blockStart = gradle.indexOf('productFlavors {');
9
+ if (blockStart === -1) {
10
+ // No productFlavors block — append one inside android {}
11
+ const androidEnd = gradle.lastIndexOf('}');
12
+ return (gradle.slice(0, androidEnd) +
13
+ `\n productFlavors {\n${flavor}\n }\n` +
14
+ gradle.slice(androidEnd));
15
+ }
16
+ // Walk forward matching braces to find closing }
17
+ let depth = 0;
18
+ let i = blockStart;
19
+ while (i < gradle.length) {
20
+ if (gradle[i] === '{')
21
+ depth++;
22
+ else if (gradle[i] === '}') {
23
+ depth--;
24
+ if (depth === 0)
25
+ break;
26
+ }
27
+ i++;
28
+ }
29
+ return gradle.slice(0, i) + '\n' + flavor + '\n' + gradle.slice(i);
30
+ }
31
+ function addProductFlavor({ client, applicationId, }) {
32
+ const gradlePath = path.join(process.cwd(), 'android/app/build.gradle');
33
+ if (!fs.existsSync(gradlePath)) {
34
+ console.warn(`build.gradle not found at ${gradlePath} — skipping`);
35
+ return;
36
+ }
37
+ const gradle = fs.readFileSync(gradlePath, 'utf-8');
38
+ // Already has this flavor
39
+ const flavorRegex = new RegExp(`\\b${client}\\s*\\{`);
40
+ if (flavorRegex.test(gradle)) {
41
+ console.log(`Flavor "${client}" already exists in build.gradle — skipping`);
42
+ return;
43
+ }
44
+ const flavorBlock = ` ${client} {\n` +
45
+ ` dimension "default"\n` +
46
+ ` applicationId "${applicationId}"\n` +
47
+ ` }`;
48
+ const updated = insertIntoProductFlavors(gradle, flavorBlock);
49
+ fs.writeFileSync(gradlePath, updated, 'utf-8');
50
+ console.log(`Added flavor "${client}" to android/app/build.gradle`);
51
+ }
52
+ exports.addProductFlavor = addProductFlavor;
@@ -1,3 +1,5 @@
1
- export declare const createClientConfig: (client: string) => Promise<any> & {
2
- ui: import("inquirer/lib/ui/prompt");
3
- };
1
+ export declare const createClientConfig: (client: string) => Promise<{
2
+ appName: any;
3
+ bundleId: any;
4
+ applicationId: any;
5
+ }>;
@@ -2,18 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createClientConfig = void 0;
4
4
  const inquirer = require("inquirer");
5
- exports.createClientConfig = (client) => {
6
- return inquirer.prompt([
7
- {
8
- type: 'confirm',
9
- name: 'android-client',
10
- message: `Please add **${client}** to **productFlavors** in android>app>build.gradle`,
11
- },
12
- {
13
- type: 'confirm',
14
- name: 'ios-client',
15
- message: `Please add **${client} prod** scheme and config Pre actions`,
16
- },
5
+ const android_1 = require("./android");
6
+ const ios_scheme_1 = require("./ios-scheme");
7
+ exports.createClientConfig = async (client) => {
8
+ const { appName, bundleId, applicationId } = await inquirer.prompt([
17
9
  {
18
10
  type: 'input',
19
11
  name: 'appName',
@@ -28,8 +20,11 @@ exports.createClientConfig = (client) => {
28
20
  {
29
21
  type: 'input',
30
22
  name: 'applicationId',
31
- message: 'What is application id (this is for android in case you need difference id for platforms)?',
23
+ message: 'What is application id (android, if different from bundle id)?',
32
24
  default: `com.edular.${client}`,
33
25
  },
34
26
  ]);
27
+ android_1.addProductFlavor({ client, applicationId });
28
+ ios_scheme_1.createXcodeScheme({ client, bundleId });
29
+ return { appName, bundleId, applicationId };
35
30
  };
@@ -1,4 +1,9 @@
1
- export declare const setupFastlane: ({ client }: any) => Promise<{
1
+ export declare const setupFastlane: ({ client, bundleId, applicationId, appName, }: {
2
+ client: string;
3
+ bundleId?: string | undefined;
4
+ applicationId?: string | undefined;
5
+ appName?: string | undefined;
6
+ }) => Promise<{
2
7
  firebaseIosApp: string;
3
8
  firebaseAndroidApp: string;
4
9
  }>;
@@ -4,28 +4,19 @@ exports.setupFastlane = void 0;
4
4
  const common_1 = require("../common");
5
5
  const path = require("path");
6
6
  const inquirer = require("inquirer");
7
- exports.setupFastlane = async ({ client }) => {
7
+ const firebase_1 = require("./firebase");
8
+ exports.setupFastlane = async ({ client, bundleId, applicationId, appName, }) => {
8
9
  const clientDir = path.join(process.cwd(), `fastlane/clients/${client}`);
9
10
  const fastlaneDir = path.join(clientDir, 'fastlane');
10
11
  if (!common_1.exists(fastlaneDir)) {
11
- // Copy template folders
12
12
  await common_1.copyDir(path.join(process.cwd(), 'template/fastlane'), fastlaneDir);
13
13
  }
14
- const { firebaseServiceAccountFile, firebaseIosApp, firebaseAndroidApp, jsonKeyFile, } = await inquirer.prompt([
14
+ const { firebaseServiceAccountFile, jsonKeyFile } = await inquirer.prompt([
15
15
  {
16
16
  type: 'input',
17
17
  name: 'firebaseServiceAccountFile',
18
18
  message: 'Firebase Service Account file?',
19
- },
20
- {
21
- type: 'input',
22
- name: 'firebaseIosApp',
23
- message: 'What is Firebase iOS App Id?',
24
- },
25
- {
26
- type: 'input',
27
- name: 'firebaseAndroidApp',
28
- message: 'What is Firebase Android App Id?',
19
+ default: process.env.FIREBASE_SERVICE_ACCOUNT_FILE,
29
20
  },
30
21
  {
31
22
  type: 'input',
@@ -33,6 +24,78 @@ exports.setupFastlane = async ({ client }) => {
33
24
  message: 'Path to Google json file? See https://docs.fastlane.tools/actions/supply/#setup',
34
25
  },
35
26
  ]);
27
+ let firebaseIosApp = '';
28
+ let firebaseAndroidApp = '';
29
+ const resolvedServiceAccount = common_1.normalise(firebaseServiceAccountFile) ||
30
+ process.env.FIREBASE_SERVICE_ACCOUNT_FILE;
31
+ if (resolvedServiceAccount) {
32
+ const { autoCreate } = await inquirer.prompt([
33
+ {
34
+ type: 'confirm',
35
+ name: 'autoCreate',
36
+ message: 'Auto-create Firebase apps?',
37
+ default: true,
38
+ },
39
+ ]);
40
+ if (autoCreate) {
41
+ const accessToken = await firebase_1.getAccessToken(resolvedServiceAccount);
42
+ const projectId = firebase_1.getProjectId(resolvedServiceAccount);
43
+ const displayName = appName || client;
44
+ console.log(`Creating Firebase apps in project ${projectId}...`);
45
+ const [iosAppId, androidAppId] = await Promise.all([
46
+ firebase_1.createFirebaseApp({
47
+ accessToken,
48
+ projectId,
49
+ platform: 'ios',
50
+ bundleId,
51
+ displayName,
52
+ }),
53
+ firebase_1.createFirebaseApp({
54
+ accessToken,
55
+ projectId,
56
+ platform: 'android',
57
+ packageName: applicationId,
58
+ displayName,
59
+ }),
60
+ ]);
61
+ firebaseIosApp = iosAppId;
62
+ firebaseAndroidApp = androidAppId;
63
+ console.log(`Firebase iOS App ID: ${iosAppId}`);
64
+ console.log(`Firebase Android App ID: ${androidAppId}`);
65
+ }
66
+ else {
67
+ const result = await inquirer.prompt([
68
+ {
69
+ type: 'input',
70
+ name: 'firebaseIosApp',
71
+ message: 'What is Firebase iOS App Id?',
72
+ },
73
+ {
74
+ type: 'input',
75
+ name: 'firebaseAndroidApp',
76
+ message: 'What is Firebase Android App Id?',
77
+ },
78
+ ]);
79
+ firebaseIosApp = result.firebaseIosApp;
80
+ firebaseAndroidApp = result.firebaseAndroidApp;
81
+ }
82
+ }
83
+ else {
84
+ const result = await inquirer.prompt([
85
+ {
86
+ type: 'input',
87
+ name: 'firebaseIosApp',
88
+ message: 'What is Firebase iOS App Id?',
89
+ },
90
+ {
91
+ type: 'input',
92
+ name: 'firebaseAndroidApp',
93
+ message: 'What is Firebase Android App Id?',
94
+ },
95
+ ]);
96
+ firebaseIosApp = result.firebaseIosApp;
97
+ firebaseAndroidApp = result.firebaseAndroidApp;
98
+ }
36
99
  if (firebaseServiceAccountFile) {
37
100
  await common_1.copyFile(common_1.normalise(firebaseServiceAccountFile), path.join(fastlaneDir, 'firebase.json'));
38
101
  }
@@ -40,7 +103,7 @@ exports.setupFastlane = async ({ client }) => {
40
103
  await common_1.copyFile(common_1.normalise(jsonKeyFile), path.join(clientDir, 'key.json'));
41
104
  }
42
105
  return {
43
- firebaseIosApp: common_1.normalise(firebaseIosApp),
44
- firebaseAndroidApp: common_1.normalise(firebaseAndroidApp),
106
+ firebaseIosApp,
107
+ firebaseAndroidApp,
45
108
  };
46
109
  };
@@ -0,0 +1,10 @@
1
+ export declare function getProjectId(serviceAccountPath: string): string;
2
+ export declare function getAccessToken(serviceAccountPath: string): Promise<string>;
3
+ export declare function createFirebaseApp({ accessToken, projectId, platform, bundleId, packageName, displayName, }: {
4
+ accessToken: string;
5
+ projectId: string;
6
+ platform: 'ios' | 'android';
7
+ bundleId?: string;
8
+ packageName?: string;
9
+ displayName: string;
10
+ }): Promise<string>;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFirebaseApp = exports.getAccessToken = exports.getProjectId = void 0;
4
+ const crypto = require("crypto");
5
+ const fs = require("fs");
6
+ const https = require("https");
7
+ function base64url(input) {
8
+ const buf = typeof input === 'string' ? Buffer.from(input) : input;
9
+ return buf
10
+ .toString('base64')
11
+ .replace(/=/g, '')
12
+ .replace(/\+/g, '-')
13
+ .replace(/\//g, '_');
14
+ }
15
+ function createJWT(serviceAccount) {
16
+ const now = Math.floor(Date.now() / 1000);
17
+ const header = base64url(JSON.stringify({ alg: 'RS256', typ: 'JWT' }));
18
+ const payload = base64url(JSON.stringify({
19
+ iss: serviceAccount.client_email,
20
+ scope: 'https://www.googleapis.com/auth/cloud-platform',
21
+ aud: 'https://oauth2.googleapis.com/token',
22
+ iat: now,
23
+ exp: now + 3600,
24
+ }));
25
+ const data = `${header}.${payload}`;
26
+ const sign = crypto.createSign('RSA-SHA256');
27
+ sign.update(data);
28
+ return `${data}.${base64url(sign.sign(serviceAccount.private_key))}`;
29
+ }
30
+ function httpsRequest(url, method, headers, body) {
31
+ return new Promise((resolve, reject) => {
32
+ const { hostname, pathname, search } = new URL(url);
33
+ const req = https.request({
34
+ hostname,
35
+ path: pathname + search,
36
+ method,
37
+ headers: body
38
+ ? Object.assign(Object.assign({}, headers), { 'Content-Length': Buffer.byteLength(body) }) : headers,
39
+ }, res => {
40
+ let raw = '';
41
+ res.on('data', chunk => (raw += chunk));
42
+ res.on('end', () => {
43
+ try {
44
+ resolve(JSON.parse(raw));
45
+ }
46
+ catch (_a) {
47
+ resolve(raw);
48
+ }
49
+ });
50
+ });
51
+ req.on('error', reject);
52
+ if (body)
53
+ req.write(body);
54
+ req.end();
55
+ });
56
+ }
57
+ function sleep(ms) {
58
+ return new Promise(r => setTimeout(r, ms));
59
+ }
60
+ async function pollOperation(operationName, accessToken) {
61
+ const url = `https://firebase.googleapis.com/v1beta1/${operationName}`;
62
+ for (let i = 0; i < 20; i++) {
63
+ await sleep(3000);
64
+ const op = await httpsRequest(url, 'GET', {
65
+ Authorization: `Bearer ${accessToken}`,
66
+ });
67
+ if (op.done) {
68
+ if (op.error)
69
+ throw new Error(`Firebase app creation failed: ${JSON.stringify(op.error)}`);
70
+ return op.response.appId;
71
+ }
72
+ }
73
+ throw new Error('Firebase app creation timed out after 60s');
74
+ }
75
+ function getProjectId(serviceAccountPath) {
76
+ const sa = JSON.parse(fs.readFileSync(serviceAccountPath, 'utf-8'));
77
+ return sa.project_id;
78
+ }
79
+ exports.getProjectId = getProjectId;
80
+ async function getAccessToken(serviceAccountPath) {
81
+ const sa = JSON.parse(fs.readFileSync(serviceAccountPath, 'utf-8'));
82
+ const jwt = createJWT(sa);
83
+ const body = new URLSearchParams({
84
+ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
85
+ assertion: jwt,
86
+ }).toString();
87
+ const result = await httpsRequest('https://oauth2.googleapis.com/token', 'POST', { 'Content-Type': 'application/x-www-form-urlencoded' }, body);
88
+ if (!result.access_token)
89
+ throw new Error(`Auth failed: ${JSON.stringify(result)}`);
90
+ return result.access_token;
91
+ }
92
+ exports.getAccessToken = getAccessToken;
93
+ async function createFirebaseApp({ accessToken, projectId, platform, bundleId, packageName, displayName, }) {
94
+ const endpoint = platform === 'ios' ? 'iosApps' : 'androidApps';
95
+ const payload = platform === 'ios'
96
+ ? { bundleId, displayName }
97
+ : { packageName, displayName };
98
+ const result = await httpsRequest(`https://firebase.googleapis.com/v1beta1/projects/${projectId}/${endpoint}`, 'POST', {
99
+ Authorization: `Bearer ${accessToken}`,
100
+ 'Content-Type': 'application/json',
101
+ }, JSON.stringify(payload));
102
+ if (result.error)
103
+ throw new Error(`Firebase API error: ${JSON.stringify(result.error)}`);
104
+ if (result.done)
105
+ return result.response.appId;
106
+ if (result.name)
107
+ return pollOperation(result.name, accessToken);
108
+ throw new Error(`Unexpected response: ${JSON.stringify(result)}`);
109
+ }
110
+ exports.createFirebaseApp = createFirebaseApp;
@@ -0,0 +1,4 @@
1
+ export declare function createXcodeScheme({ client, }: {
2
+ client: string;
3
+ bundleId: string;
4
+ }): void;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createXcodeScheme = void 0;
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ function findSchemeDir() {
7
+ const iosDir = path.join(process.cwd(), 'ios');
8
+ if (!fs.existsSync(iosDir))
9
+ return null;
10
+ for (const entry of fs.readdirSync(iosDir)) {
11
+ if (!entry.endsWith('.xcodeproj'))
12
+ continue;
13
+ const candidate = path.join(iosDir, entry, 'xcshareddata', 'xcschemes');
14
+ if (fs.existsSync(candidate))
15
+ return candidate;
16
+ }
17
+ return null;
18
+ }
19
+ function findExistingProdScheme(schemeDir) {
20
+ const files = fs
21
+ .readdirSync(schemeDir)
22
+ .filter(f => f.endsWith(' prod.xcscheme'));
23
+ return files.length > 0 ? path.join(schemeDir, files[0]) : null;
24
+ }
25
+ function extractClientFromFilename(filename) {
26
+ return path.basename(filename, '.xcscheme').replace(/ prod$/, '');
27
+ }
28
+ function createXcodeScheme({ client, }) {
29
+ const schemeDir = findSchemeDir();
30
+ if (!schemeDir) {
31
+ console.warn('Could not find xcshareddata/xcschemes — add iOS scheme manually');
32
+ return;
33
+ }
34
+ const targetScheme = path.join(schemeDir, `${client} prod.xcscheme`);
35
+ if (fs.existsSync(targetScheme)) {
36
+ console.log(`Scheme "${client} prod" already exists — skipping`);
37
+ return;
38
+ }
39
+ const sourceScheme = findExistingProdScheme(schemeDir);
40
+ if (!sourceScheme) {
41
+ console.warn('No existing "*prod.xcscheme" found to copy from — add iOS scheme manually');
42
+ return;
43
+ }
44
+ const oldClient = extractClientFromFilename(sourceScheme);
45
+ let xml = fs.readFileSync(sourceScheme, 'utf-8');
46
+ // Replace all occurrences of old client name — covers BuildableName,
47
+ // BlueprintName, and pre-action script paths like configs/oldclient/.env.*
48
+ xml = xml.split(oldClient).join(client);
49
+ fs.writeFileSync(targetScheme, xml, 'utf-8');
50
+ console.log(`Created iOS scheme "${client} prod" from "${path.basename(sourceScheme)}"`);
51
+ }
52
+ exports.createXcodeScheme = createXcodeScheme;
@@ -1 +1 @@
1
- {"version":"0.6.68","commands":{"build":{"id":"build","description":"Build react native apps","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder build\nhello world from ./src/build.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Set client that you want to build app"},"target":{"name":"target","type":"option","char":"t","description":"Set the build target: android, ios or both","options":["android","ios","android,ios"]},"env":{"name":"env","type":"option","char":"e","description":"Set the environment: prod, staging, dev"},"branch":{"name":"branch","type":"option","char":"b","description":"Set the source branch used to build the app"},"version":{"name":"version","type":"option","char":"v","description":"Set the version number for this build"},"installr":{"name":"installr","type":"option","char":"i","description":"If enabled, the build will be uploaded to installR"},"distribute":{"name":"distribute","type":"option","char":"d","description":"Specify where to distribute app"},"firebase":{"name":"firebase","type":"boolean","char":"f","description":"If enabled, the build will be uploaded to firebase","allowNo":false},"testersIos":{"name":"testersIos","type":"option","char":"t","description":"Tester ids for iOS distribution"},"testersAndroid":{"name":"testersAndroid","type":"option","char":"u","description":"Tester ids for Android distribution"},"gitReset":{"name":"gitReset","type":"boolean","char":"g","description":"Do git reset when building","allowNo":false},"cleanup":{"name":"cleanup","type":"boolean","char":"s","description":"Do cleanup when building","allowNo":false},"groupsIos":{"name":"groupsIos","type":"option","description":"Groups ids for iOS distribution"},"groupsAndroid":{"name":"groupsAndroid","type":"option","description":"Groups ids for Android distribution"},"skipCheckVersion":{"name":"skipCheckVersion","type":"boolean","description":"Skip checking current version on stores","allowNo":false}},"args":[{"name":"build"}]},"check-version":{"id":"check-version","description":"Check live versions","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder check-version\n Nuke certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"match-check"}]},"codepush":{"id":"codepush","description":"Push changes to existing apps","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder codepush\n Push changes to existing apps ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to push update"}},"args":[{"name":"build"}]},"google-key":{"id":"google-key","description":"Nuke certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-check\n Nuke certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"match-check"}]},"initialize":{"id":"initialize","description":"Initialize the environment for first run","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder initialize\ninitialize environment for first run from ./src/initialize.ts!\n"],"flags":{},"args":[]},"match-check":{"id":"match-check","description":"Check match certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-check\n Check match certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to check match certificates"}},"args":[{"name":"match-check"}]},"match-nuke":{"id":"match-nuke","description":"Nuke certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-nuke\n Nuke certificates ./src/match-nuke.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"build"}]},"onesignal":{"id":"onesignal","description":"Create and upload push cerfiticate to One Signal","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder onesignal\n Create and upload push certificate to One Signal from ./src/commands/onesignal.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"},"auth_token":{"name":"auth_token","type":"option","description":"Auth token for OneSignal"},"android_token":{"name":"android_token","type":"option"},"android_gcm_sender_id":{"name":"android_gcm_sender_id","type":"option"}},"args":[{"name":"build"}]},"reject-review":{"id":"reject-review","description":"Reject current App Store review version (In Review or Pending Developer Release)","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder reject-review\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client to reject App Store review version"}},"args":[{"name":"reject-review"}]},"setup":{"id":"setup","description":"Setup new client","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder build\nhello world from ./src/setup.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"setup"}]},"submit-review":{"id":"submit-review","description":"Submit ios for review","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder submit-review\n Push changes to existing apps ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to push update"}},"args":[{"name":"submit-review"}]},"sync-udids":{"id":"sync-udids","description":"Sync device UDIDs from firebase","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder sync-udids\n Sync device UDIDs from firebase from ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"build"}]}}}
1
+ {"version":"0.6.70","commands":{"build":{"id":"build","description":"Build react native apps","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder build\nhello world from ./src/build.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Set client that you want to build app"},"target":{"name":"target","type":"option","char":"t","description":"Set the build target: android, ios or both","options":["android","ios","android,ios"]},"env":{"name":"env","type":"option","char":"e","description":"Set the environment: prod, staging, dev"},"branch":{"name":"branch","type":"option","char":"b","description":"Set the source branch used to build the app"},"version":{"name":"version","type":"option","char":"v","description":"Set the version number for this build"},"installr":{"name":"installr","type":"option","char":"i","description":"If enabled, the build will be uploaded to installR"},"distribute":{"name":"distribute","type":"option","char":"d","description":"Specify where to distribute app"},"firebase":{"name":"firebase","type":"boolean","char":"f","description":"If enabled, the build will be uploaded to firebase","allowNo":false},"testersIos":{"name":"testersIos","type":"option","char":"t","description":"Tester ids for iOS distribution"},"testersAndroid":{"name":"testersAndroid","type":"option","char":"u","description":"Tester ids for Android distribution"},"gitReset":{"name":"gitReset","type":"boolean","char":"g","description":"Do git reset when building","allowNo":false},"cleanup":{"name":"cleanup","type":"boolean","char":"s","description":"Do cleanup when building","allowNo":false},"groupsIos":{"name":"groupsIos","type":"option","description":"Groups ids for iOS distribution"},"groupsAndroid":{"name":"groupsAndroid","type":"option","description":"Groups ids for Android distribution"},"skipCheckVersion":{"name":"skipCheckVersion","type":"boolean","description":"Skip checking current version on stores","allowNo":false},"install":{"name":"install","type":"boolean","char":"n","description":"Install dependencies before building","allowNo":false}},"args":[{"name":"build"}]},"check-version":{"id":"check-version","description":"Check live versions","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder check-version\n Nuke certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"match-check"}]},"codepush":{"id":"codepush","description":"Push changes to existing apps","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder codepush\n Push changes to existing apps ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to push update"}},"args":[{"name":"build"}]},"google-key":{"id":"google-key","description":"Nuke certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-check\n Nuke certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"match-check"}]},"initialize":{"id":"initialize","description":"Initialize the environment for first run","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder initialize\ninitialize environment for first run from ./src/initialize.ts!\n"],"flags":{},"args":[]},"match-check":{"id":"match-check","description":"Check match certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-check\n Check match certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to check match certificates"}},"args":[{"name":"match-check"}]},"match-nuke":{"id":"match-nuke","description":"Nuke certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-nuke\n Nuke certificates ./src/match-nuke.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"build"}]},"onesignal":{"id":"onesignal","description":"Create and upload push cerfiticate to One Signal","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder onesignal\n Create and upload push certificate to One Signal from ./src/commands/onesignal.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"},"auth_token":{"name":"auth_token","type":"option","description":"Auth token for OneSignal"},"android_token":{"name":"android_token","type":"option"},"android_gcm_sender_id":{"name":"android_gcm_sender_id","type":"option"}},"args":[{"name":"build"}]},"reject-review":{"id":"reject-review","description":"Reject current App Store review version (In Review or Pending Developer Release)","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder reject-review\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client to reject App Store review version"}},"args":[{"name":"reject-review"}]},"setup":{"id":"setup","description":"Setup new client","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder build\nhello world from ./src/setup.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"setup"}]},"submit-review":{"id":"submit-review","description":"Submit ios for review","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder submit-review\n Push changes to existing apps ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to push update"}},"args":[{"name":"submit-review"}]},"sync-udids":{"id":"sync-udids","description":"Sync device UDIDs from firebase","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder sync-udids\n Sync device UDIDs from firebase from ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"build"}]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rnbuilder",
3
3
  "description": "React Native builder tool",
4
- "version": "0.6.68",
4
+ "version": "0.6.70",
5
5
  "author": "Tuan Luong @r0b0t3d",
6
6
  "bin": "./bin/run",
7
7
  "bugs": "https://github.com/r0b0t3d/rnbuilder/issues",