eoas 1.0.2 → 1.0.3

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.
Files changed (70) hide show
  1. package/dist/commands/generate-certs.d.ts +8 -0
  2. package/dist/commands/generate-certs.js +90 -0
  3. package/dist/commands/init.d.ts +8 -0
  4. package/dist/commands/init.js +113 -0
  5. package/dist/commands/publish.d.ts +18 -0
  6. package/dist/commands/publish.js +249 -0
  7. package/dist/lib/assets.d.ts +19 -0
  8. package/dist/lib/assets.js +90 -0
  9. package/dist/lib/auth.d.ts +6 -0
  10. package/dist/lib/auth.js +57 -0
  11. package/dist/lib/expoConfig.d.ts +23 -0
  12. package/dist/lib/expoConfig.js +198 -0
  13. package/dist/lib/log.d.ts +40 -0
  14. package/dist/lib/log.js +101 -0
  15. package/dist/lib/ora.d.ts +9 -0
  16. package/dist/lib/ora.js +103 -0
  17. package/dist/lib/package.d.ts +1 -0
  18. package/dist/lib/package.js +9 -0
  19. package/dist/lib/prompts.d.ts +13 -0
  20. package/dist/lib/prompts.js +68 -0
  21. package/dist/lib/repo.d.ts +6 -0
  22. package/dist/lib/repo.js +48 -0
  23. package/dist/lib/runtimeVersion.d.ts +42 -0
  24. package/dist/lib/runtimeVersion.js +116 -0
  25. package/dist/lib/utils.d.ts +1 -0
  26. package/dist/lib/utils.js +7 -0
  27. package/dist/lib/vcs/clients/git.d.ts +31 -0
  28. package/dist/lib/vcs/clients/git.js +322 -0
  29. package/dist/lib/vcs/clients/gitNoCommit.d.ts +8 -0
  30. package/dist/lib/vcs/clients/gitNoCommit.js +42 -0
  31. package/dist/lib/vcs/clients/noVcs.d.ts +7 -0
  32. package/dist/lib/vcs/clients/noVcs.js +22 -0
  33. package/dist/lib/vcs/git.d.ts +13 -0
  34. package/dist/lib/vcs/git.js +60 -0
  35. package/dist/lib/vcs/index.d.ts +2 -0
  36. package/dist/lib/vcs/index.js +26 -0
  37. package/dist/lib/vcs/local.d.ts +19 -0
  38. package/dist/lib/vcs/local.js +85 -0
  39. package/dist/lib/vcs/vcs.d.ts +25 -0
  40. package/dist/lib/vcs/vcs.js +61 -0
  41. package/dist/lib/workflow.d.ts +4 -0
  42. package/dist/lib/workflow.js +40 -0
  43. package/package.json +6 -2
  44. package/.eslintignore +0 -1
  45. package/.eslintrc.js +0 -73
  46. package/.prettierrc +0 -9
  47. package/src/commands/generate-certs.ts +0 -95
  48. package/src/commands/init.ts +0 -117
  49. package/src/commands/publish.ts +0 -277
  50. package/src/index.d.ts +0 -7
  51. package/src/lib/assets.ts +0 -118
  52. package/src/lib/auth.ts +0 -67
  53. package/src/lib/expoConfig.ts +0 -265
  54. package/src/lib/log.ts +0 -122
  55. package/src/lib/ora.ts +0 -113
  56. package/src/lib/package.ts +0 -6
  57. package/src/lib/prompts.ts +0 -97
  58. package/src/lib/repo.ts +0 -62
  59. package/src/lib/runtimeVersion.ts +0 -177
  60. package/src/lib/utils.ts +0 -3
  61. package/src/lib/vcs/README.md +0 -1
  62. package/src/lib/vcs/clients/git.ts +0 -390
  63. package/src/lib/vcs/clients/gitNoCommit.ts +0 -45
  64. package/src/lib/vcs/clients/noVcs.ts +0 -23
  65. package/src/lib/vcs/git.ts +0 -68
  66. package/src/lib/vcs/index.ts +0 -25
  67. package/src/lib/vcs/local.ts +0 -88
  68. package/src/lib/vcs/vcs.ts +0 -90
  69. package/src/lib/workflow.ts +0 -47
  70. package/tsconfig.json +0 -17
@@ -0,0 +1,19 @@
1
+ export declare function getRootPath(): string;
2
+ /**
3
+ * Ignore wraps the 'ignore' package to support multiple .gitignore files
4
+ * in subdirectories.
5
+ *
6
+ * Inconsistencies with git behavior:
7
+ * - if parent .gitignore has ignore rule and child has exception to that rule,
8
+ * file will still be ignored,
9
+ * - node_modules is always ignored,
10
+ * - if .easignore exists, .gitignore files are not used.
11
+ */
12
+ export declare class Ignore {
13
+ private readonly rootDir;
14
+ private ignoreMapping;
15
+ constructor(rootDir: string);
16
+ initIgnoreAsync(): Promise<void>;
17
+ ignores(relativePath: string): boolean;
18
+ }
19
+ export declare function makeShallowCopyAsync(src: string, dst: string): Promise<void>;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeShallowCopyAsync = exports.Ignore = exports.getRootPath = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
6
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
7
+ const ignore_1 = tslib_1.__importDefault(require("ignore"));
8
+ const path_1 = tslib_1.__importDefault(require("path"));
9
+ const EASIGNORE_FILENAME = '.easignore';
10
+ const GITIGNORE_FILENAME = '.gitignore';
11
+ const DEFAULT_IGNORE = `
12
+ .git
13
+ node_modules
14
+ `;
15
+ function getRootPath() {
16
+ const rootPath = process.env.EAS_PROJECT_ROOT ?? process.cwd();
17
+ if (!path_1.default.isAbsolute(rootPath)) {
18
+ return path_1.default.resolve(process.cwd(), rootPath);
19
+ }
20
+ return rootPath;
21
+ }
22
+ exports.getRootPath = getRootPath;
23
+ /**
24
+ * Ignore wraps the 'ignore' package to support multiple .gitignore files
25
+ * in subdirectories.
26
+ *
27
+ * Inconsistencies with git behavior:
28
+ * - if parent .gitignore has ignore rule and child has exception to that rule,
29
+ * file will still be ignored,
30
+ * - node_modules is always ignored,
31
+ * - if .easignore exists, .gitignore files are not used.
32
+ */
33
+ class Ignore {
34
+ rootDir;
35
+ ignoreMapping = [];
36
+ constructor(rootDir) {
37
+ this.rootDir = rootDir;
38
+ }
39
+ async initIgnoreAsync() {
40
+ const easIgnorePath = path_1.default.join(this.rootDir, EASIGNORE_FILENAME);
41
+ if (await fs_extra_1.default.pathExists(easIgnorePath)) {
42
+ this.ignoreMapping = [
43
+ ['', (0, ignore_1.default)().add(DEFAULT_IGNORE)],
44
+ ['', (0, ignore_1.default)().add(await fs_extra_1.default.readFile(easIgnorePath, 'utf-8'))],
45
+ ];
46
+ return;
47
+ }
48
+ const ignoreFilePaths = (await (0, fast_glob_1.default)(`**/${GITIGNORE_FILENAME}`, {
49
+ cwd: this.rootDir,
50
+ ignore: ['node_modules'],
51
+ followSymbolicLinks: false,
52
+ }))
53
+ // ensure that parent dir is before child directories
54
+ .sort((a, b) => a.length - b.length && a.localeCompare(b));
55
+ const ignoreMapping = await Promise.all(ignoreFilePaths.map(async (filePath) => {
56
+ return [
57
+ filePath.slice(0, filePath.length - GITIGNORE_FILENAME.length),
58
+ (0, ignore_1.default)().add(await fs_extra_1.default.readFile(path_1.default.join(this.rootDir, filePath), 'utf-8')),
59
+ ];
60
+ }));
61
+ this.ignoreMapping = [['', (0, ignore_1.default)().add(DEFAULT_IGNORE)], ...ignoreMapping];
62
+ }
63
+ ignores(relativePath) {
64
+ for (const [prefix, ignore] of this.ignoreMapping) {
65
+ if (relativePath.startsWith(prefix) && ignore.ignores(relativePath.slice(prefix.length))) {
66
+ return true;
67
+ }
68
+ }
69
+ return false;
70
+ }
71
+ }
72
+ exports.Ignore = Ignore;
73
+ async function makeShallowCopyAsync(src, dst) {
74
+ const ignore = new Ignore(src);
75
+ await ignore.initIgnoreAsync();
76
+ await fs_extra_1.default.copy(src, dst, {
77
+ filter: (srcFilePath) => {
78
+ if (srcFilePath === src) {
79
+ return true;
80
+ }
81
+ return !ignore.ignores(path_1.default.relative(src, srcFilePath));
82
+ },
83
+ });
84
+ }
85
+ exports.makeShallowCopyAsync = makeShallowCopyAsync;
@@ -0,0 +1,25 @@
1
+ export declare abstract class Client {
2
+ abstract makeShallowCopyAsync(destinationPath: string): Promise<void>;
3
+ abstract getRootPathAsync(): Promise<string>;
4
+ ensureRepoExistsAsync(): Promise<void>;
5
+ isCommitRequiredAsync(): Promise<boolean>;
6
+ hasUncommittedChangesAsync(): Promise<boolean | undefined>;
7
+ commitAsync(_arg: {
8
+ commitMessage: string;
9
+ commitAllFiles?: boolean;
10
+ nonInteractive: boolean;
11
+ }): Promise<void>;
12
+ trackFileAsync(_file: string): Promise<void>;
13
+ showDiffAsync(): Promise<void>;
14
+ /** (optional) print list of changed files */
15
+ showChangedFilesAsync(): Promise<void>;
16
+ getCommitHashAsync(): Promise<string | undefined>;
17
+ getBranchNameAsync(): Promise<string | null>;
18
+ getLastCommitMessageAsync(): Promise<string | null>;
19
+ isFileIgnoredAsync(_filePath: string): Promise<boolean>;
20
+ /**
21
+ * Whether this VCS client can get the last commit message.
22
+ * Used for EAS Update - implementation can be false for noVcs client.
23
+ */
24
+ abstract canGetLastCommitMessage(): boolean;
25
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Client = void 0;
4
+ class Client {
5
+ // (optional) ensureRepoExistsAsync should verify whether repository exists and tooling is installed
6
+ // it's not required for minimal support, but lack of validation might cause the failure at a later stage.
7
+ async ensureRepoExistsAsync() { }
8
+ // (optional) checks whether commit is necessary before calling makeShallowCopyAsync
9
+ //
10
+ // If it's not implemented method `makeShallowCopyAsync` needs to be able to include uncommitted changes
11
+ // when creating copy
12
+ async isCommitRequiredAsync() {
13
+ return false;
14
+ }
15
+ // (optional) hasUncommittedChangesAsync should check whether there are changes in local repository
16
+ async hasUncommittedChangesAsync() {
17
+ return undefined;
18
+ }
19
+ // (optional) commitAsync commits changes
20
+ //
21
+ // - Should be implemented if hasUncommittedChangesAsync is implemented
22
+ // - If it's not implemented method `makeShallowCopyAsync` needs to be able to include uncommitted changes
23
+ // in project copy
24
+ async commitAsync(_arg) {
25
+ // it should not be called unless hasUncommittedChangesAsync is implemented
26
+ throw new Error('commitAsync is not implemented');
27
+ }
28
+ // (optional) mark file as tracked, if this method is called on file, the next call to
29
+ // `commitAsync({ commitAllFiles: false })` should commit that file
30
+ async trackFileAsync(_file) { }
31
+ // (optional) print diff of the changes that will be commited in the next call to
32
+ // `commitAsync({ commitAllFiles: false })`
33
+ async showDiffAsync() { }
34
+ /** (optional) print list of changed files */
35
+ async showChangedFilesAsync() { }
36
+ // (optional) returns hash of the last commit
37
+ // used for metadata - implementation can be safely skipped
38
+ async getCommitHashAsync() {
39
+ return undefined;
40
+ }
41
+ // (optional) returns name of the current branch
42
+ // used for EAS Update - implementation can be safely skipped
43
+ async getBranchNameAsync() {
44
+ return null;
45
+ }
46
+ // (optional) returns message of the last commit
47
+ // used for EAS Update - implementation can be safely skipped
48
+ async getLastCommitMessageAsync() {
49
+ return null;
50
+ }
51
+ // (optional) checks if the file is ignored, an implementation should ensure
52
+ // that if file exists and `isFileIgnoredAsync` returns true, then that file
53
+ // should not be included in the project tarball.
54
+ //
55
+ // @param filePath has to be a relative normalized path pointing to a file
56
+ // located under the root of the repository
57
+ async isFileIgnoredAsync(_filePath) {
58
+ return false;
59
+ }
60
+ }
61
+ exports.Client = Client;
@@ -0,0 +1,4 @@
1
+ import { Platform, Workflow } from '@expo/eas-build-job';
2
+ import { Client } from './vcs/vcs';
3
+ export declare function resolveWorkflowAsync(projectDir: string, platform: Platform, vcsClient: Client): Promise<Workflow>;
4
+ export declare function resolveWorkflowPerPlatformAsync(projectDir: string, vcsClient: Client): Promise<Record<Platform, Workflow>>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveWorkflowPerPlatformAsync = exports.resolveWorkflowAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const config_plugins_1 = require("@expo/config-plugins");
6
+ const eas_build_job_1 = require("@expo/eas-build-job");
7
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
+ const path_1 = tslib_1.__importDefault(require("path"));
9
+ async function resolveWorkflowAsync(projectDir, platform, vcsClient) {
10
+ let platformWorkflowMarkers;
11
+ try {
12
+ platformWorkflowMarkers =
13
+ platform === eas_build_job_1.Platform.ANDROID
14
+ ? [
15
+ path_1.default.join(projectDir, 'android/app/build.gradle'),
16
+ await config_plugins_1.AndroidConfig.Paths.getAndroidManifestAsync(projectDir),
17
+ ]
18
+ : [config_plugins_1.IOSConfig.Paths.getPBXProjectPath(projectDir)];
19
+ }
20
+ catch {
21
+ return eas_build_job_1.Workflow.MANAGED;
22
+ }
23
+ const vcsRootPath = path_1.default.normalize(await vcsClient.getRootPathAsync());
24
+ for (const marker of platformWorkflowMarkers) {
25
+ if ((await fs_extra_1.default.pathExists(marker)) &&
26
+ !(await vcsClient.isFileIgnoredAsync(path_1.default.relative(vcsRootPath, marker)))) {
27
+ return eas_build_job_1.Workflow.GENERIC;
28
+ }
29
+ }
30
+ return eas_build_job_1.Workflow.MANAGED;
31
+ }
32
+ exports.resolveWorkflowAsync = resolveWorkflowAsync;
33
+ async function resolveWorkflowPerPlatformAsync(projectDir, vcsClient) {
34
+ const [android, ios] = await Promise.all([
35
+ resolveWorkflowAsync(projectDir, eas_build_job_1.Platform.ANDROID, vcsClient),
36
+ resolveWorkflowAsync(projectDir, eas_build_job_1.Platform.IOS, vcsClient),
37
+ ]);
38
+ return { android, ios };
39
+ }
40
+ exports.resolveWorkflowPerPlatformAsync = resolveWorkflowPerPlatformAsync;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eoas",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "build": "tsc --project tsconfig.json",
@@ -88,5 +88,9 @@
88
88
  "commands": "./dist/commands",
89
89
  "dirname": "eoas",
90
90
  "topicSeparator": ":"
91
- }
91
+ },
92
+ "files": [
93
+ "/bin",
94
+ "/dist"
95
+ ]
92
96
  }
package/.eslintignore DELETED
@@ -1 +0,0 @@
1
- node_modules
package/.eslintrc.js DELETED
@@ -1,73 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- extends: ['universe/node'],
4
- plugins: ['node'],
5
- ignorePatterns: ['bin/'],
6
- rules: {
7
- 'no-console': 'warn',
8
- 'no-constant-condition': ['warn', { checkLoops: false }],
9
- 'sort-imports': [
10
- 'warn',
11
- {
12
- ignoreDeclarationSort: true,
13
- },
14
- ],
15
- curly: 'warn',
16
- 'import/no-cycle': 'error',
17
- 'import/no-extraneous-dependencies': [
18
- 'error',
19
- { devDependencies: ['**/__tests__/**/*', '**/__mocks__/**/*'] },
20
- ],
21
- 'import/no-relative-packages': 'error',
22
- 'no-restricted-imports': [
23
- 'error',
24
- {
25
- paths: [
26
- {
27
- name: 'lodash',
28
- message: "Don't use lodash, it's heavy!",
29
- },
30
- ],
31
- },
32
- ],
33
- 'no-underscore-dangle': ['error', { allow: ['__typename'] }],
34
- 'node/no-sync': 'error',
35
- },
36
- overrides: [
37
- {
38
- files: ['*.ts', '*.d.ts'],
39
- parserOptions: {
40
- project: './tsconfig.json',
41
- },
42
- rules: {
43
- '@typescript-eslint/explicit-function-return-type': [
44
- 'warn',
45
- {
46
- allowExpressions: true,
47
- },
48
- ],
49
- '@typescript-eslint/prefer-nullish-coalescing': ['warn', { ignorePrimitives: true }],
50
- '@typescript-eslint/no-confusing-void-expression': 'warn',
51
- '@typescript-eslint/await-thenable': 'error',
52
- '@typescript-eslint/no-misused-promises': [
53
- 'error',
54
- {
55
- checksVoidReturn: false,
56
- },
57
- ],
58
- '@typescript-eslint/no-floating-promises': 'error',
59
- 'no-void': ['warn', { allowAsStatement: true }],
60
- 'no-return-await': 'off',
61
- '@typescript-eslint/return-await': ['error', 'always'],
62
- '@typescript-eslint/no-confusing-non-null-assertion': 'warn',
63
- '@typescript-eslint/no-extra-non-null-assertion': 'warn',
64
- '@typescript-eslint/prefer-as-const': 'warn',
65
- '@typescript-eslint/prefer-includes': 'warn',
66
- '@typescript-eslint/prefer-readonly': 'warn',
67
- '@typescript-eslint/prefer-string-starts-ends-with': 'warn',
68
- '@typescript-eslint/prefer-ts-expect-error': 'warn',
69
- '@typescript-eslint/no-unnecessary-type-assertion': 'warn',
70
- },
71
- },
72
- ],
73
- };
package/.prettierrc DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "printWidth": 100,
3
- "tabWidth": 2,
4
- "singleQuote": true,
5
- "bracketSameLine": true,
6
- "trailingComma": "es5",
7
- "arrowParens": "avoid",
8
- "endOfLine": "auto"
9
- }
@@ -1,95 +0,0 @@
1
- import {
2
- convertCertificateToCertificatePEM,
3
- convertKeyPairToPEM,
4
- generateKeyPair,
5
- generateSelfSignedCodeSigningCertificate,
6
- } from '@expo/code-signing-certificates';
7
- import { Command } from '@oclif/core';
8
- import { ensureDirSync, writeFile } from 'fs-extra';
9
- import path from 'path';
10
-
11
- import Log from '../lib/log';
12
- import { promptAsync } from '../lib/prompts';
13
-
14
- export default class GenerateCerts extends Command {
15
- static override args = {};
16
- static override description = 'Generate private & public certificates for code signing';
17
- static override examples = ['<%= config.bin %> <%= command.id %>'];
18
- static override flags = {};
19
- public async run(): Promise<void> {
20
- const { certificateOutputDir } = await promptAsync({
21
- message:
22
- 'In which directory would you like to store your code signing certificate (used by your expo app)?',
23
- name: 'certificateOutputDir',
24
- type: 'text',
25
- initial: './keysStore',
26
- validate: v => {
27
- try {
28
- // eslint-disable-next-line
29
- ensureDirSync(path.join(process.cwd(), v));
30
- return true;
31
- } catch {
32
- return false;
33
- }
34
- },
35
- });
36
- const { keyOutputDir } = await promptAsync({
37
- message:
38
- 'In which directory would you like to store your key pair (used by your OTA Server) ?. ⚠️ Those keysStore are sensitive and should be kept private.',
39
- name: 'keyOutputDir',
40
- type: 'text',
41
- initial: './keysStore',
42
- validate: v => {
43
- try {
44
- // eslint-disable-next-line
45
- ensureDirSync(path.join(process.cwd(), v));
46
- return true;
47
- } catch {
48
- return false;
49
- }
50
- },
51
- });
52
- const { certificateCommonName } = await promptAsync({
53
- message: 'Please enter your Organization name',
54
- name: 'certificateCommonName',
55
- type: 'text',
56
- initial: 'Your Organization Name',
57
- validate: v => {
58
- return !!v;
59
- },
60
- });
61
- const { certificateValidityDurationYears } = await promptAsync({
62
- message: 'How many years should the certificate be valid for?',
63
- name: 'certificateValidityDurationYears',
64
- type: 'number',
65
- initial: 10,
66
- validate: v => {
67
- return v > 0 && Number.isInteger(v);
68
- },
69
- });
70
- const validityDurationYears = Math.floor(Number(certificateValidityDurationYears));
71
- const certificateOutput = path.resolve(process.cwd(), certificateOutputDir);
72
- const keyOutput = path.resolve(process.cwd(), keyOutputDir);
73
- const validityNotBefore = new Date();
74
- const validityNotAfter = new Date();
75
- validityNotAfter.setFullYear(validityNotAfter.getFullYear() + validityDurationYears);
76
- const keyPair = generateKeyPair();
77
- const certificate = generateSelfSignedCodeSigningCertificate({
78
- keyPair,
79
- validityNotBefore,
80
- validityNotAfter,
81
- commonName: certificateCommonName,
82
- });
83
- const keyPairPEM = convertKeyPairToPEM(keyPair);
84
- const certificatePEM = convertCertificateToCertificatePEM(certificate);
85
- await Promise.all([
86
- writeFile(path.join(keyOutput, 'public-key.pem'), keyPairPEM.publicKeyPEM),
87
- writeFile(path.join(keyOutput, 'private-key.pem'), keyPairPEM.privateKeyPEM),
88
- writeFile(path.join(certificateOutput, 'certificate.pem'), certificatePEM),
89
- ]);
90
- Log.succeed(
91
- `Generated public and private keys output in ${keyOutputDir}. Please follow the documentation to securely store them and do not commit them to your repository.`
92
- );
93
- Log.succeed(`Generated code signing certificate output in ${certificateOutputDir}.`);
94
- }
95
- }
@@ -1,117 +0,0 @@
1
- import { Command } from '@oclif/core';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
-
5
- import {
6
- createOrModifyExpoConfigAsync,
7
- getExpoConfigUpdateUrl,
8
- getPrivateExpoConfigAsync,
9
- } from '../lib/expoConfig';
10
- import Log from '../lib/log';
11
- import { ora } from '../lib/ora';
12
- import { isExpoInstalled } from '../lib/package';
13
- import { confirmAsync, promptAsync } from '../lib/prompts';
14
- import { isValidUpdateUrl } from '../lib/utils';
15
-
16
- export default class Init extends Command {
17
- static override args = {};
18
- static override description = 'Configure your existing expo project with Expo Open OTA';
19
- static override examples = ['<%= config.bin %> <%= command.id %>'];
20
- static override flags = {};
21
- public async run(): Promise<void> {
22
- const projectDir = process.cwd();
23
- const hasExpo = isExpoInstalled(projectDir);
24
- if (!hasExpo) {
25
- Log.error('Expo is not installed in this project. Please install Expo first.');
26
- return;
27
- }
28
- const config = await getPrivateExpoConfigAsync(projectDir);
29
- if (!config) {
30
- Log.error(
31
- 'Could not find Expo config in this project. Please make sure you have an Expo config.'
32
- );
33
- return;
34
- }
35
- const { updateUrl: promptedUrl } = await promptAsync({
36
- message: 'Enter the URL of your update server (ex: https://customota.com)',
37
- name: 'updateUrl',
38
- type: 'text',
39
- initial: getExpoConfigUpdateUrl(config),
40
- validate: v => {
41
- return !!v && isValidUpdateUrl(v);
42
- },
43
- });
44
- let manifestEndpoint = `${promptedUrl}/manifest`;
45
- const updateUrl = getExpoConfigUpdateUrl(config);
46
- if (updateUrl && !updateUrl.includes('expo.dev')) {
47
- const confirmed = await confirmAsync({
48
- message: `Expo config already has an update URL set to ${updateUrl}. Do you want to replace it?`,
49
- name: 'replace',
50
- type: 'confirm',
51
- });
52
- if (!confirmed) {
53
- manifestEndpoint = updateUrl;
54
- }
55
- }
56
- const confirmed = await confirmAsync({
57
- message: 'Do you have already generated your certificates and keysStore for code signing?',
58
- name: 'certificates',
59
- type: 'confirm',
60
- });
61
- if (!confirmed) {
62
- Log.fail('You need to generate your certificates first by using npx eoas generate-keysStore');
63
- return;
64
- }
65
- const { codeSigningCertificatePath } = await promptAsync({
66
- message: 'Enter the path to your code signing certificate (ex: ./keysStore/certificate.pem)',
67
- name: 'codeSigningCertificatePath',
68
- type: 'text',
69
- initial: './keysStore/certificate.pem',
70
- validate: v => {
71
- try {
72
- const fullPath = path.resolve(projectDir, v);
73
- // eslint-disable-next-line
74
- const fileExists = fs.existsSync(fullPath);
75
- if (!fileExists) {
76
- Log.newLine();
77
- Log.error('File does not exist');
78
- return false;
79
- }
80
- // eslint-disable-next-line
81
- const key = fs.readFileSync(fullPath, 'utf8');
82
- if (!key) {
83
- Log.error('Empty key');
84
- return false;
85
- }
86
- return true;
87
- } catch {
88
- return false;
89
- }
90
- },
91
- });
92
- const newUpdateConfig = {
93
- url: manifestEndpoint,
94
- codeSigningMetadata: {
95
- keyid: 'main',
96
- alg: 'rsa-v1_5-sha256' as const,
97
- },
98
- codeSigningCertificate: codeSigningCertificatePath,
99
- enabled: true,
100
- requestHeaders: {
101
- 'expo-channel-name': 'process.env.RELEASE_CHANNEL',
102
- },
103
- };
104
- const updateConfigSpinner = ora('Updating Expo config').start();
105
- try {
106
- await createOrModifyExpoConfigAsync(projectDir, {
107
- updates: newUpdateConfig,
108
- });
109
- updateConfigSpinner.succeed(
110
- 'Expo config successfully updated do not forget to format the file with prettier or eslint'
111
- );
112
- } catch (e) {
113
- updateConfigSpinner.fail('Failed to update Expo config');
114
- Log.error(e);
115
- }
116
- }
117
- }