rnbuilder 0.6.79 → 0.6.81

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
@@ -40,7 +40,7 @@ $ npm install -g rnbuilder
40
40
  $ rnbuilder COMMAND
41
41
  running command...
42
42
  $ rnbuilder (-v|--version|version)
43
- rnbuilder/0.6.79 darwin-arm64 node-v24.13.0
43
+ rnbuilder/0.6.81 darwin-arm64 node-v24.13.0
44
44
  $ rnbuilder --help [COMMAND]
45
45
  USAGE
46
46
  $ rnbuilder COMMAND
@@ -98,7 +98,7 @@ EXAMPLE
98
98
  hello world from ./src/build.ts!
99
99
  ```
100
100
 
101
- _See code: [src/commands/build.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/build.ts)_
101
+ _See code: [src/commands/build.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/build.ts)_
102
102
 
103
103
  ## `rnbuilder check-version [MATCH-CHECK]`
104
104
 
@@ -117,7 +117,7 @@ EXAMPLE
117
117
  Nuke certificates ./src/match-check.ts!
118
118
  ```
119
119
 
120
- _See code: [src/commands/check-version.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/check-version.ts)_
120
+ _See code: [src/commands/check-version.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/check-version.ts)_
121
121
 
122
122
  ## `rnbuilder codepush [BUILD]`
123
123
 
@@ -136,7 +136,7 @@ EXAMPLE
136
136
  Push changes to existing apps ./src/firebase-sync-udids.ts!
137
137
  ```
138
138
 
139
- _See code: [src/commands/codepush.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/codepush.ts)_
139
+ _See code: [src/commands/codepush.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/codepush.ts)_
140
140
 
141
141
  ## `rnbuilder google-key [MATCH-CHECK]`
142
142
 
@@ -155,7 +155,7 @@ EXAMPLE
155
155
  Nuke certificates ./src/match-check.ts!
156
156
  ```
157
157
 
158
- _See code: [src/commands/google-key.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/google-key.ts)_
158
+ _See code: [src/commands/google-key.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/google-key.ts)_
159
159
 
160
160
  ## `rnbuilder help [COMMAND]`
161
161
 
@@ -187,7 +187,7 @@ EXAMPLE
187
187
  initialize environment for first run from ./src/initialize.ts!
188
188
  ```
189
189
 
190
- _See code: [src/commands/initialize.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/initialize.ts)_
190
+ _See code: [src/commands/initialize.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/initialize.ts)_
191
191
 
192
192
  ## `rnbuilder match-check [MATCH-CHECK]`
193
193
 
@@ -206,7 +206,7 @@ EXAMPLE
206
206
  Check match certificates ./src/match-check.ts!
207
207
  ```
208
208
 
209
- _See code: [src/commands/match-check.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/match-check.ts)_
209
+ _See code: [src/commands/match-check.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/match-check.ts)_
210
210
 
211
211
  ## `rnbuilder match-nuke [BUILD]`
212
212
 
@@ -225,7 +225,7 @@ EXAMPLE
225
225
  Nuke certificates ./src/match-nuke.ts!
226
226
  ```
227
227
 
228
- _See code: [src/commands/match-nuke.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/match-nuke.ts)_
228
+ _See code: [src/commands/match-nuke.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/match-nuke.ts)_
229
229
 
230
230
  ## `rnbuilder onesignal [BUILD]`
231
231
 
@@ -247,7 +247,7 @@ EXAMPLE
247
247
  Create and upload push certificate to One Signal from ./src/commands/onesignal.ts!
248
248
  ```
249
249
 
250
- _See code: [src/commands/onesignal.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/onesignal.ts)_
250
+ _See code: [src/commands/onesignal.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/onesignal.ts)_
251
251
 
252
252
  ## `rnbuilder reject-review [REJECT-REVIEW]`
253
253
 
@@ -265,7 +265,7 @@ EXAMPLE
265
265
  $ rnbuilder reject-review
266
266
  ```
267
267
 
268
- _See code: [src/commands/reject-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/reject-review.ts)_
268
+ _See code: [src/commands/reject-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/reject-review.ts)_
269
269
 
270
270
  ## `rnbuilder setup [SETUP]`
271
271
 
@@ -283,7 +283,7 @@ EXAMPLE
283
283
  hello world from ./src/setup.ts!
284
284
  ```
285
285
 
286
- _See code: [src/commands/setup.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/setup.ts)_
286
+ _See code: [src/commands/setup.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/setup.ts)_
287
287
 
288
288
  ## `rnbuilder setup-gcp`
289
289
 
@@ -297,7 +297,7 @@ OPTIONS
297
297
  -h, --help show CLI help
298
298
  ```
299
299
 
300
- _See code: [src/commands/setup-gcp.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/setup-gcp.ts)_
300
+ _See code: [src/commands/setup-gcp.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/setup-gcp.ts)_
301
301
 
302
302
  ## `rnbuilder submit-review [SUBMIT-REVIEW]`
303
303
 
@@ -316,7 +316,7 @@ EXAMPLE
316
316
  Push changes to existing apps ./src/firebase-sync-udids.ts!
317
317
  ```
318
318
 
319
- _See code: [src/commands/submit-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/submit-review.ts)_
319
+ _See code: [src/commands/submit-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/submit-review.ts)_
320
320
 
321
321
  ## `rnbuilder sync-udids [BUILD]`
322
322
 
@@ -335,5 +335,5 @@ EXAMPLE
335
335
  Sync device UDIDs from firebase from ./src/firebase-sync-udids.ts!
336
336
  ```
337
337
 
338
- _See code: [src/commands/sync-udids.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.79/src/commands/sync-udids.ts)_
338
+ _See code: [src/commands/sync-udids.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.81/src/commands/sync-udids.ts)_
339
339
  <!-- commandsstop -->
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  /* eslint-disable complexity */
4
4
  /* eslint-disable no-negated-condition */
5
5
  const command_1 = require("@oclif/command");
6
+ const fs = require("fs");
6
7
  const inquirer = require("inquirer");
7
8
  const path = require("path");
8
9
  const app_icon_1 = require("../utils/setup/app-icon");
@@ -11,9 +12,22 @@ const launch_screen_1 = require("../utils/setup/launch-screen");
11
12
  const client_1 = require("../utils/setup/client");
12
13
  const env_1 = require("../utils/env");
13
14
  const apple_1 = require("../utils/setup/apple");
14
- const onesignal_1 = require("../utils/setup/onesignal");
15
15
  const common_1 = require("../utils/common");
16
16
  const fastlane_1 = require("../utils/setup/fastlane");
17
+ const firebase_1 = require("../utils/setup/firebase");
18
+ function addAppJsonEntry({ client, appName }) {
19
+ const appJsonPath = path.join(process.cwd(), 'app.json');
20
+ const appJson = common_1.checkFileExists(appJsonPath)
21
+ ? JSON.parse(fs.readFileSync(appJsonPath, 'utf-8'))
22
+ : {};
23
+ const today = new Date().toISOString().slice(0, 10);
24
+ appJson[client] = {
25
+ name: appName !== null && appName !== void 0 ? appName : client,
26
+ android: { version: '0.0.0', build: 0, buildDate: today },
27
+ ios: { version: '0.0.0', build: 0, buildDate: today },
28
+ };
29
+ fs.writeFileSync(appJsonPath, JSON.stringify(appJson, null, 2) + '\n', 'utf-8');
30
+ }
17
31
  class Setup extends command_1.Command {
18
32
  async run() {
19
33
  const questions = [
@@ -98,12 +112,7 @@ class Setup extends command_1.Command {
98
112
  env_1.setEnvValue('APPLICATION_ID', applicationId, prodEnvVars);
99
113
  env_1.saveEnvValues(prodEnvVars, prodEnvPath);
100
114
  // Setup fastlane
101
- const { firebaseIosApp, firebaseAndroidApp } = await fastlane_1.setupFastlane({
102
- client,
103
- bundleId,
104
- applicationId,
105
- appName,
106
- });
115
+ await fastlane_1.setupFastlane({ client });
107
116
  const fastlaneDir = path.join(process.cwd(), `fastlane/clients/${client}/fastlane`);
108
117
  const fastlaneEnvVars = env_1.readEnvVars(path.join(fastlaneDir, '/.env'));
109
118
  env_1.setEnvValue('CLIENT', client, fastlaneEnvVars);
@@ -124,25 +133,10 @@ class Setup extends command_1.Command {
124
133
  env_1.setEnvValue('ITC_TEAM_ID', itcTeamId, fastlaneEnvVars);
125
134
  }
126
135
  env_1.setEnvValue('FLAVOR', common_1.capitalize(client), fastlaneEnvVars);
127
- if (firebaseIosApp) {
128
- env_1.setEnvValue('FIREBASE_IOS_APP', firebaseIosApp, fastlaneEnvVars);
129
- }
130
- if (firebaseAndroidApp) {
131
- env_1.setEnvValue('FIREBASE_ANDROID_APP', firebaseAndroidApp, fastlaneEnvVars);
132
- }
133
136
  env_1.saveEnvValues(fastlaneEnvVars, fastlaneDir + '/.env');
134
- // Onesignal — creates the push cert via fastlane, needs the client fastlane
135
- // env (APPLE_TEAM_ID, APP_IDENTIFIER, CLIENT) already written above.
136
- const { onesignal } = await onesignal_1.prepareOneSignal({
137
- client,
138
- fastlaneDir,
139
- appleTeamId,
140
- appName,
141
- });
142
- if (onesignal) {
143
- env_1.setEnvValue('ONESIGNAL_APP_ID', onesignal, prodEnvVars);
144
- env_1.saveEnvValues(prodEnvVars, prodEnvPath);
145
- }
137
+ // Firebase apps + config files; needs the env files and fastlane .env written above.
138
+ await firebase_1.provisionFirebase({ client, fastlaneDir });
139
+ addAppJsonEntry({ client, appName });
146
140
  }
147
141
  }
148
142
  exports.default = Setup;
package/lib/utils/env.js CHANGED
@@ -13,10 +13,16 @@ exports.readEnvVars = (envFilePath) => {
13
13
  if (!line) {
14
14
  return;
15
15
  }
16
- const result = line.split('=');
17
- envObject[result[0]] = {
18
- key: result[0],
19
- value: result[1],
16
+ const separatorIndex = line.indexOf('=');
17
+ // Comments and other lines without `=` are kept verbatim
18
+ if (line.trim().startsWith('#') || separatorIndex === -1) {
19
+ envObject[`__raw_${index}`] = { raw: line, order: index };
20
+ return;
21
+ }
22
+ const key = line.slice(0, separatorIndex);
23
+ envObject[key] = {
24
+ key,
25
+ value: line.slice(separatorIndex + 1),
20
26
  order: index,
21
27
  };
22
28
  });
@@ -33,7 +39,7 @@ exports.readEnvVars = (envFilePath) => {
33
39
  exports.saveEnvValues = (newValues, destFilePath) => {
34
40
  const payload = Object.values(newValues)
35
41
  .sort((a, b) => a.order - b.order)
36
- .map((data) => `${data.key}=${data.value}`);
42
+ .map((data) => data.raw !== undefined ? data.raw : `${data.key}=${data.value}`);
37
43
  // write everything back to the file system
38
44
  const dirname = path.dirname(destFilePath);
39
45
  fs.mkdirSync(dirname, { recursive: true });
@@ -1,9 +1,3 @@
1
- export declare const setupFastlane: ({ client, bundleId, applicationId, appName, }: {
1
+ export declare const setupFastlane: ({ client }: {
2
2
  client: string;
3
- bundleId?: string | undefined;
4
- applicationId?: string | undefined;
5
- appName?: string | undefined;
6
- }) => Promise<{
7
- firebaseIosApp: string;
8
- firebaseAndroidApp: string;
9
- }>;
3
+ }) => Promise<void>;
@@ -4,8 +4,7 @@ exports.setupFastlane = void 0;
4
4
  const common_1 = require("../common");
5
5
  const path = require("path");
6
6
  const inquirer = require("inquirer");
7
- const firebase_1 = require("./firebase");
8
- exports.setupFastlane = async ({ client, bundleId, applicationId, appName, }) => {
7
+ exports.setupFastlane = async ({ client }) => {
9
8
  const clientDir = path.join(process.cwd(), `fastlane/clients/${client}`);
10
9
  const fastlaneDir = path.join(clientDir, 'fastlane');
11
10
  // Merge template files in without overwriting existing client files —
@@ -15,7 +14,7 @@ exports.setupFastlane = async ({ client, bundleId, applicationId, appName, }) =>
15
14
  {
16
15
  type: 'input',
17
16
  name: 'firebaseServiceAccountFile',
18
- message: 'Firebase Service Account file?',
17
+ message: 'Firebase Service Account file (for App Distribution)?',
19
18
  default: process.env.FIREBASE_SERVICE_ACCOUNT_FILE,
20
19
  },
21
20
  {
@@ -24,86 +23,10 @@ exports.setupFastlane = async ({ client, bundleId, applicationId, appName, }) =>
24
23
  message: 'Path to Google json file? See https://docs.fastlane.tools/actions/supply/#setup',
25
24
  },
26
25
  ]);
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
- }
99
26
  if (firebaseServiceAccountFile) {
100
27
  await common_1.copyFile(common_1.normalise(firebaseServiceAccountFile), path.join(fastlaneDir, 'firebase.json'));
101
28
  }
102
29
  if (jsonKeyFile) {
103
30
  await common_1.copyFile(common_1.normalise(jsonKeyFile), path.join(clientDir, 'key.json'));
104
31
  }
105
- return {
106
- firebaseIosApp,
107
- firebaseAndroidApp,
108
- };
109
32
  };
@@ -1,10 +1,4 @@
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>;
1
+ export declare const provisionFirebase: ({ client, fastlaneDir, }: {
2
+ client: string;
3
+ fastlaneDir: string;
4
+ }) => Promise<void>;
@@ -1,131 +1,67 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createFirebaseApp = exports.getAccessToken = exports.getProjectId = void 0;
4
- const crypto = require("crypto");
3
+ exports.provisionFirebase = void 0;
5
4
  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();
5
+ const inquirer = require("inquirer");
6
+ const path = require("path");
7
+ const shell = require("shelljs");
8
+ // Firebase apps are provisioned by the project's own script with the operator's
9
+ // `firebase login`. The client → Firebase project mapping lives in the project too.
10
+ const CLIENTS_FILE = 'scripts/firebase-clients.json';
11
+ const PROVISION_SCRIPT = 'scripts/firebase-provision.js';
12
+ const pickProject = async (clients) => {
13
+ const counts = {};
14
+ Object.values(clients).forEach(({ project }) => {
15
+ counts[project] = (counts[project] || 0) + 1;
55
16
  });
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}`,
17
+ const { project } = await inquirer.prompt([
18
+ {
19
+ type: 'list',
20
+ name: 'project',
21
+ message: 'Firebase project for this client? (2 apps per client, max 30 apps per project)',
22
+ choices: Object.keys(counts).map(p => ({
23
+ name: `${p} (${counts[p]} clients)`,
24
+ value: p,
25
+ })),
26
+ },
27
+ ]);
28
+ return project;
29
+ };
30
+ // Needs configs/<client>/.env.prod and fastlane/clients/<client>/fastlane/.env written:
31
+ // the script reads the package / bundle IDs and writes FIREBASE_ANDROID_APP / FIREBASE_IOS_APP.
32
+ exports.provisionFirebase = async ({ client, fastlaneDir, }) => {
33
+ const clientsPath = path.join(process.cwd(), CLIENTS_FILE);
34
+ if (!fs.existsSync(clientsPath) ||
35
+ !fs.existsSync(path.join(process.cwd(), PROVISION_SCRIPT))) {
36
+ throw new Error(`Firebase setup needs ${PROVISION_SCRIPT} and ${CLIENTS_FILE} in the project`);
37
+ }
38
+ const clients = JSON.parse(fs.readFileSync(clientsPath, 'utf-8'));
39
+ if (clients[client]) {
40
+ console.log(`${client} is mapped to ${clients[client].project}`);
41
+ }
42
+ else {
43
+ clients[client] = { project: await pickProject(clients) };
44
+ const sorted = {};
45
+ Object.keys(clients)
46
+ .sort()
47
+ .forEach(key => {
48
+ sorted[key] = clients[key];
66
49
  });
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
- }
50
+ fs.writeFileSync(clientsPath, JSON.stringify(sorted, null, 2) + '\n');
51
+ }
52
+ const result = shell.exec(`node ${PROVISION_SCRIPT} ${client}`);
53
+ if (result.code !== 0) {
54
+ console.warn(`Firebase provisioning failed; fix the error above and re-run: node ${PROVISION_SCRIPT} ${client}`);
72
55
  }
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 findExistingAppId({ accessToken, projectId, platform, bundleId, packageName, }) {
94
- const endpoint = platform === 'ios' ? 'iosApps' : 'androidApps';
95
- const result = await httpsRequest(`https://firebase.googleapis.com/v1beta1/projects/${projectId}/${endpoint}`, 'GET', { Authorization: `Bearer ${accessToken}` });
96
- const apps = result.apps || [];
97
- const match = platform === 'ios'
98
- ? apps.find((app) => app.bundleId === bundleId)
99
- : apps.find((app) => app.packageName === packageName);
100
- return match === null || match === void 0 ? void 0 : match.appId;
101
- }
102
- async function createFirebaseApp({ accessToken, projectId, platform, bundleId, packageName, displayName, }) {
103
- const endpoint = platform === 'ios' ? 'iosApps' : 'androidApps';
104
- const payload = platform === 'ios'
105
- ? { bundleId, displayName }
106
- : { packageName, displayName };
107
- const result = await httpsRequest(`https://firebase.googleapis.com/v1beta1/projects/${projectId}/${endpoint}`, 'POST', {
108
- Authorization: `Bearer ${accessToken}`,
109
- 'Content-Type': 'application/json',
110
- }, JSON.stringify(payload));
111
- if (result.error) {
112
- if (result.error.status === 'ALREADY_EXISTS') {
113
- const existingAppId = await findExistingAppId({
114
- accessToken,
115
- projectId,
116
- platform,
117
- bundleId,
118
- packageName,
119
- });
120
- if (existingAppId)
121
- return existingAppId;
122
- }
123
- throw new Error(`Firebase API error: ${JSON.stringify(result.error)}`);
56
+ const { apnsKey } = await inquirer.prompt([
57
+ {
58
+ type: 'confirm',
59
+ name: 'apnsKey',
60
+ message: 'Create or reuse the APNs key via fastlane sync_apns_key now (Apple ID login)?',
61
+ default: true,
62
+ },
63
+ ]);
64
+ if (apnsKey) {
65
+ shell.exec('bundle exec fastlane sync_apns_key', { cwd: fastlaneDir });
124
66
  }
125
- if (result.done)
126
- return result.response.appId;
127
- if (result.name)
128
- return pollOperation(result.name, accessToken);
129
- throw new Error(`Unexpected response: ${JSON.stringify(result)}`);
130
- }
131
- exports.createFirebaseApp = createFirebaseApp;
67
+ };
@@ -1 +1 @@
1
- {"version":"0.6.79","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-gcp":{"id":"setup-gcp","description":"Setup GCP service account impersonation","pluginName":"rnbuilder","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"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.81","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-gcp":{"id":"setup-gcp","description":"Setup GCP service account impersonation","pluginName":"rnbuilder","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"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.79",
4
+ "version": "0.6.81",
5
5
  "author": "Tuan Luong @r0b0t3d",
6
6
  "bin": "./bin/run",
7
7
  "bugs": "https://github.com/r0b0t3d/rnbuilder/issues",
@@ -1,9 +0,0 @@
1
- export declare const prepareOneSignal: ({ client, fastlaneDir, appleTeamId, appName, }: {
2
- client: string;
3
- fastlaneDir: string;
4
- appleTeamId?: string | undefined;
5
- appName?: string | undefined;
6
- }) => Promise<{
7
- onesignal?: string | undefined;
8
- onesignalRestApiKey?: string | undefined;
9
- }>;
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.prepareOneSignal = void 0;
4
- const inquirer = require("inquirer");
5
- const shell = require("shelljs");
6
- const common_1 = require("../common");
7
- function parseValue(output, key) {
8
- var _a;
9
- const match = output.match(new RegExp(`^(?:\\[\\d{2}:\\d{2}:\\d{2}\\]:\\s*)?${key}=(.*)$`, 'm'));
10
- const value = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.trim();
11
- return value ? value : undefined;
12
- }
13
- async function askAppIdManually() {
14
- const { onesignal } = await inquirer.prompt([
15
- {
16
- type: 'input',
17
- name: 'onesignal',
18
- message: 'What is OneSignal App Id?',
19
- },
20
- ]);
21
- return { onesignal, onesignalRestApiKey: undefined };
22
- }
23
- exports.prepareOneSignal = async ({ client, fastlaneDir, appleTeamId, appName, }) => {
24
- const fastlaneConfigs = common_1.getFastlaneConfigs();
25
- let authToken = fastlaneConfigs.onesignalAuthToken;
26
- if (!authToken) {
27
- const { inputToken } = await inquirer.prompt([
28
- {
29
- type: 'input',
30
- name: 'inputToken',
31
- message: 'OneSignal Organization Auth Token (add "onesignalAuthToken" to fastlane/configs.json to skip this prompt)?',
32
- },
33
- ]);
34
- authToken = inputToken;
35
- }
36
- if (!authToken) {
37
- return askAppIdManually();
38
- }
39
- const { autoCreate } = await inquirer.prompt([
40
- {
41
- type: 'confirm',
42
- name: 'autoCreate',
43
- message: `Create OneSignal app "${client}" + push certificate via fastlane now?`,
44
- default: true,
45
- },
46
- ]);
47
- if (!autoCreate) {
48
- return askAppIdManually();
49
- }
50
- let teamId = appleTeamId;
51
- if (!teamId) {
52
- const { inputTeamId } = await inquirer.prompt([
53
- {
54
- type: 'input',
55
- name: 'inputTeamId',
56
- message: 'Apple Developer Team ID (for the push certificate)?',
57
- },
58
- ]);
59
- teamId = inputTeamId;
60
- }
61
- const organizationId = fastlaneConfigs.onesignalOrganizationId;
62
- const parameters = common_1.buildKeyValuePairs(Object.assign(Object.assign(Object.assign({ auth_token: authToken }, (appName ? { app_name: appName } : {})), (organizationId ? { organization_id: organizationId } : {})), (teamId ? { team_id: teamId } : {})));
63
- // shell.exec('bundle install', { cwd: fastlaneDir } as any);
64
- const result = shell.exec(`bundle exec fastlane sync_onesignal ${parameters.join(' ')}`, { cwd: fastlaneDir });
65
- const output = `${result.stdout}\n${result.stderr}`;
66
- const onesignal = parseValue(output, 'ONESIGNAL_APP_ID');
67
- const onesignalRestApiKey = parseValue(output, 'ONESIGNAL_APP_AUTH_KEY');
68
- if (!onesignal) {
69
- console.warn('Could not parse OneSignal App Id from fastlane output — check the logs above and set ONESIGNAL_APP_ID manually if needed.');
70
- }
71
- return { onesignal, onesignalRestApiKey };
72
- };