eas-cli 16.23.0 → 16.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ import { PackageManager } from '../../onboarding/installDependencies';
2
+ export declare function cloneTemplateAsync(targetProjectDir: string): Promise<string>;
3
+ export declare function installProjectDependenciesAsync(projectDir: string, packageManager: PackageManager): Promise<void>;
4
+ export declare function initializeGitRepositoryAsync(projectDir: string): Promise<void>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initializeGitRepositoryAsync = exports.installProjectDependenciesAsync = exports.cloneTemplateAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ const log_1 = tslib_1.__importDefault(require("../../log"));
8
+ const git_1 = require("../../onboarding/git");
9
+ const installDependencies_1 = require("../../onboarding/installDependencies");
10
+ const runCommand_1 = require("../../onboarding/runCommand");
11
+ async function cloneTemplateAsync(targetProjectDir) {
12
+ const githubUsername = 'expo';
13
+ const githubRepositoryName = 'expo-template-default';
14
+ log_1.default.log(`📂 Cloning the project to ${targetProjectDir}`);
15
+ log_1.default.newLine();
16
+ const cloneMethod = (await (0, git_1.canAccessRepositoryUsingSshAsync)({
17
+ githubUsername,
18
+ githubRepositoryName,
19
+ }))
20
+ ? 'ssh'
21
+ : 'https';
22
+ const { targetProjectDir: finalTargetProjectDirectory } = await (0, git_1.runGitCloneAsync)({
23
+ githubUsername,
24
+ githubRepositoryName,
25
+ targetProjectDir,
26
+ cloneMethod,
27
+ });
28
+ return finalTargetProjectDirectory;
29
+ }
30
+ exports.cloneTemplateAsync = cloneTemplateAsync;
31
+ async function installProjectDependenciesAsync(projectDir, packageManager) {
32
+ await (0, installDependencies_1.installDependenciesAsync)({
33
+ outputLevel: 'none',
34
+ projectDir,
35
+ packageManager,
36
+ });
37
+ const dependencies = ['expo-updates', '@expo/metro-runtime'];
38
+ for (const dependency of dependencies) {
39
+ await (0, runCommand_1.runCommandAsync)({
40
+ cwd: projectDir,
41
+ command: 'npx',
42
+ args: ['expo', 'install', dependency],
43
+ showOutput: false,
44
+ });
45
+ }
46
+ }
47
+ exports.installProjectDependenciesAsync = installProjectDependenciesAsync;
48
+ async function initializeGitRepositoryAsync(projectDir) {
49
+ await fs_extra_1.default.remove(path_1.default.join(projectDir, '.git'));
50
+ const commands = [['init'], ['add', '.'], ['commit', '-m', 'Initial commit']];
51
+ for (const args of commands) {
52
+ await (0, runCommand_1.runCommandAsync)({
53
+ cwd: projectDir,
54
+ command: 'git',
55
+ args,
56
+ showOutput: false,
57
+ });
58
+ log_1.default.log();
59
+ }
60
+ }
61
+ exports.initializeGitRepositoryAsync = initializeGitRepositoryAsync;
@@ -0,0 +1,25 @@
1
+ import { Choice } from '../../prompts';
2
+ import { Actor } from '../../user/User';
3
+ import { ExpoGraphqlClient } from '../context/contextUtils/createGraphqlClient';
4
+ export declare function generateProjectConfigAsync(actor: Actor, pathArg: string | undefined, options: {
5
+ graphqlClient: ExpoGraphqlClient;
6
+ projectAccount: string;
7
+ }): Promise<{
8
+ projectName: string;
9
+ projectDirectory: string;
10
+ }>;
11
+ export declare function promptForProjectAccountAsync(actor: Actor): Promise<string>;
12
+ export declare function getAccountChoices(actor: Actor, permissionsMap?: Map<string, boolean>): Choice[];
13
+ export declare function generateProjectNameVariations(actor: Actor, baseName: string): string[];
14
+ /**
15
+ * Finds an available project name that doesn't conflict with either:
16
+ * Local filesystem (directory already exists)
17
+ * Remote server (project already exists on Expo)
18
+ */
19
+ export declare function findAvailableProjectNameAsync(actor: Actor, baseName: string, parentDirectory: string, { graphqlClient, projectAccount, }: {
20
+ graphqlClient: ExpoGraphqlClient;
21
+ projectAccount: string;
22
+ }): Promise<{
23
+ projectName: string;
24
+ projectDirectory: string;
25
+ }>;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findAvailableProjectNameAsync = exports.generateProjectNameVariations = exports.getAccountChoices = exports.promptForProjectAccountAsync = exports.generateProjectConfigAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
+ const nanoid_1 = require("nanoid");
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ const generated_1 = require("../../graphql/generated");
9
+ const log_1 = tslib_1.__importDefault(require("../../log"));
10
+ const fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync_1 = require("../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync");
11
+ const prompts_1 = require("../../prompts");
12
+ const User_1 = require("../../user/User");
13
+ function validateProjectPath(resolvedPath) {
14
+ const normalizedPath = path_1.default.normalize(resolvedPath);
15
+ // Check for path traversal attempts
16
+ if (normalizedPath.includes('..')) {
17
+ throw new Error(`Invalid project path: "${resolvedPath}". Path traversal is not allowed.`);
18
+ }
19
+ // Ensure we're not trying to create a project in system directories
20
+ const systemDirs = ['/bin', '/sbin', '/etc', '/usr', '/var', '/sys', '/proc', '/dev'];
21
+ const isSystemDir = systemDirs.some(dir => normalizedPath === dir || normalizedPath.startsWith(dir + path_1.default.sep));
22
+ if (isSystemDir) {
23
+ throw new Error(`Invalid project path: "${resolvedPath}". Cannot create projects in system directories.`);
24
+ }
25
+ }
26
+ async function generateProjectConfigAsync(actor, pathArg, options) {
27
+ let baseName = 'new-expo-project';
28
+ let parentDirectory = process.cwd();
29
+ if (pathArg) {
30
+ const resolvedPath = path_1.default.isAbsolute(pathArg) ? pathArg : path_1.default.resolve(process.cwd(), pathArg);
31
+ validateProjectPath(resolvedPath);
32
+ baseName = path_1.default.basename(resolvedPath);
33
+ parentDirectory = path_1.default.dirname(resolvedPath);
34
+ }
35
+ // Find an available name checking both local filesystem and remote server
36
+ const { projectName, projectDirectory } = await findAvailableProjectNameAsync(actor, baseName, parentDirectory, options);
37
+ log_1.default.withInfo(`Using project directory: ${projectDirectory}`);
38
+ return {
39
+ projectName,
40
+ projectDirectory,
41
+ };
42
+ }
43
+ exports.generateProjectConfigAsync = generateProjectConfigAsync;
44
+ function getAccountPermissionsMap(actor) {
45
+ const permissionsMap = new Map();
46
+ for (const account of actor.accounts) {
47
+ const hasPermission = account.users.find(it => it.actor.id === actor.id)?.role !== generated_1.Role.ViewOnly;
48
+ permissionsMap.set(account.name, hasPermission);
49
+ }
50
+ return permissionsMap;
51
+ }
52
+ async function promptForProjectAccountAsync(actor) {
53
+ const permissionsMap = getAccountPermissionsMap(actor);
54
+ // If only one account, use it (if has permissions)
55
+ if (actor.accounts.length === 1) {
56
+ const account = actor.accounts[0];
57
+ if (permissionsMap.get(account.name)) {
58
+ return account.name;
59
+ }
60
+ throw new Error(`You don't have permission to create projects on your only available account (${account.name}).`);
61
+ }
62
+ // Multiple accounts - prompt user to select one with permissions
63
+ return (await (0, prompts_1.promptAsync)({
64
+ type: 'select',
65
+ name: 'account',
66
+ message: 'Which account should own this project?',
67
+ choices: getAccountChoices(actor, permissionsMap),
68
+ })).account.name;
69
+ }
70
+ exports.promptForProjectAccountAsync = promptForProjectAccountAsync;
71
+ function getAccountChoices(actor, permissionsMap) {
72
+ const permissions = permissionsMap ?? getAccountPermissionsMap(actor);
73
+ const sortedAccounts = [...actor.accounts].sort((a, _b) => actor.__typename === 'User' ? (a.name === actor.username ? -1 : 1) : 0);
74
+ return sortedAccounts.map(account => {
75
+ const isPersonalAccount = actor.__typename === 'User' && account.name === actor.username;
76
+ const accountDisplayName = isPersonalAccount
77
+ ? `${account.name} (personal account)`
78
+ : account.name;
79
+ const disabled = !permissions.get(account.name);
80
+ return {
81
+ title: accountDisplayName,
82
+ value: { name: account.name },
83
+ ...(disabled && {
84
+ disabled: true,
85
+ description: 'You do not have the required permissions to create projects on this account.',
86
+ }),
87
+ };
88
+ });
89
+ }
90
+ exports.getAccountChoices = getAccountChoices;
91
+ function generateProjectNameVariations(actor, baseName) {
92
+ const username = (0, User_1.getActorUsername)(actor);
93
+ const date = new Date().toISOString().split('T')[0];
94
+ return [
95
+ baseName,
96
+ `${baseName}-${username}-${date}`,
97
+ `${baseName}-${username}-${date}-${(0, nanoid_1.nanoid)(6)}`,
98
+ ];
99
+ }
100
+ exports.generateProjectNameVariations = generateProjectNameVariations;
101
+ async function verifyProjectDoesNotExistAsync(graphqlClient, accountName, projectName, { silent = false } = {}) {
102
+ const existingProjectId = await (0, fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync_1.findProjectIdByAccountNameAndSlugNullableAsync)(graphqlClient, accountName, projectName);
103
+ const doesNotExist = existingProjectId === null;
104
+ if (!doesNotExist && !silent) {
105
+ log_1.default.warn(`Project @${accountName}/${projectName} already exists on the server.`);
106
+ }
107
+ return doesNotExist;
108
+ }
109
+ /**
110
+ * Finds an available project name that doesn't conflict with either:
111
+ * Local filesystem (directory already exists)
112
+ * Remote server (project already exists on Expo)
113
+ */
114
+ async function findAvailableProjectNameAsync(actor, baseName, parentDirectory, { graphqlClient, projectAccount, }) {
115
+ const nameVariations = generateProjectNameVariations(actor, baseName);
116
+ for (let i = 0; i < nameVariations.length; i++) {
117
+ const nameVariation = nameVariations[i];
118
+ const proposedDirectory = path_1.default.join(parentDirectory, nameVariation);
119
+ const usingVariant = i !== 0;
120
+ const localExists = await fs_extra_1.default.pathExists(proposedDirectory);
121
+ if (localExists) {
122
+ continue;
123
+ }
124
+ const remoteAvailable = await verifyProjectDoesNotExistAsync(graphqlClient, projectAccount, nameVariation, { silent: usingVariant });
125
+ if (!remoteAvailable) {
126
+ continue;
127
+ }
128
+ log_1.default.withInfo(`Using ${usingVariant ? 'alternate ' : ''}project name: ${nameVariation}`);
129
+ return {
130
+ projectName: nameVariation,
131
+ projectDirectory: proposedDirectory,
132
+ };
133
+ }
134
+ throw new Error(`Unable to find a unique project name for "${baseName}". All generated variations already exist.`);
135
+ }
136
+ exports.findAvailableProjectNameAsync = findAvailableProjectNameAsync;
@@ -0,0 +1,8 @@
1
+ import { AppFragment } from '../../graphql/generated';
2
+ import { PackageManager } from '../../onboarding/installDependencies';
3
+ export declare function cleanAndPrefix(_string: string, type: 'user' | 'app' | 'scheme'): string;
4
+ export declare function generateAppConfigAsync(projectDir: string, app: AppFragment): Promise<void>;
5
+ export declare function generateEasConfigAsync(projectDir: string): Promise<void>;
6
+ export declare function updatePackageJsonAsync(projectDir: string): Promise<void>;
7
+ export declare function copyProjectTemplatesAsync(projectDir: string): Promise<void>;
8
+ export declare function updateReadmeAsync(projectDir: string, packageManager: PackageManager): Promise<void>;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateReadmeAsync = exports.copyProjectTemplatesAsync = exports.updatePackageJsonAsync = exports.generateEasConfigAsync = exports.generateAppConfigAsync = exports.cleanAndPrefix = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const eas_json_1 = require("@expo/eas-json");
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
+ const path_1 = tslib_1.__importDefault(require("path"));
9
+ const ts_deepmerge_1 = tslib_1.__importDefault(require("ts-deepmerge"));
10
+ const api_1 = require("../../api");
11
+ const log_1 = tslib_1.__importStar(require("../../log"));
12
+ const easCli_1 = require("../../utils/easCli");
13
+ // Android package names must start with a lowercase letter
14
+ // schemes must start with a lowercase letter and can only contain lowercase letters, digits, "+", "." or "-"
15
+ function cleanAndPrefix(_string, type) {
16
+ let string = _string;
17
+ let pattern = /[^A-Za-z0-9]/g;
18
+ if (type === 'scheme') {
19
+ string = _string.toLowerCase();
20
+ pattern = /[^a-z0-9+.-]/g;
21
+ }
22
+ const prefix = /^[^a-z]/.test(string) ? type : '';
23
+ const cleaned = string.replaceAll(pattern, '');
24
+ return prefix + cleaned;
25
+ }
26
+ exports.cleanAndPrefix = cleanAndPrefix;
27
+ async function generateAppConfigAsync(projectDir, app) {
28
+ const user = cleanAndPrefix(app.ownerAccount.name, 'user');
29
+ const slug = cleanAndPrefix(app.slug, 'app');
30
+ const scheme = cleanAndPrefix(app.name ?? app.slug, 'scheme');
31
+ const bundleIdentifier = `com.${user}.${slug}`;
32
+ const updateUrl = (0, api_1.getEASUpdateURL)(app.id, /* manifestHostOverride */ null);
33
+ const { expo: baseExpoConfig } = await fs_extra_1.default.readJson(path_1.default.join(projectDir, 'app.json'));
34
+ const expoConfig = {
35
+ name: app.name ?? app.slug,
36
+ slug: app.slug,
37
+ scheme,
38
+ extra: {
39
+ eas: {
40
+ projectId: app.id,
41
+ },
42
+ },
43
+ owner: app.ownerAccount.name,
44
+ updates: {
45
+ url: updateUrl,
46
+ },
47
+ runtimeVersion: {
48
+ policy: 'appVersion',
49
+ },
50
+ ios: {
51
+ bundleIdentifier,
52
+ },
53
+ android: {
54
+ package: bundleIdentifier,
55
+ },
56
+ };
57
+ const mergedConfig = (0, ts_deepmerge_1.default)(baseExpoConfig, expoConfig);
58
+ const appJsonPath = path_1.default.join(projectDir, 'app.json');
59
+ await fs_extra_1.default.writeJson(appJsonPath, { expo: mergedConfig }, { spaces: 2 });
60
+ log_1.default.withTick(`Generated ${chalk_1.default.bold('app.json')}. ${(0, log_1.learnMore)('https://docs.expo.dev/versions/latest/config/app/')}`);
61
+ log_1.default.log();
62
+ }
63
+ exports.generateAppConfigAsync = generateAppConfigAsync;
64
+ async function generateEasConfigAsync(projectDir) {
65
+ const easBuildGitHubConfig = {
66
+ android: {
67
+ image: 'latest',
68
+ },
69
+ ios: {
70
+ image: 'latest',
71
+ },
72
+ };
73
+ const easJson = {
74
+ cli: {
75
+ version: `>= ${easCli_1.easCliVersion}`,
76
+ appVersionSource: eas_json_1.AppVersionSource.REMOTE,
77
+ },
78
+ build: {
79
+ development: {
80
+ developmentClient: true,
81
+ distribution: 'internal',
82
+ ...easBuildGitHubConfig,
83
+ },
84
+ 'development-simulator': {
85
+ extends: 'development',
86
+ ios: {
87
+ simulator: true,
88
+ },
89
+ },
90
+ preview: {
91
+ distribution: 'internal',
92
+ channel: 'main',
93
+ ...easBuildGitHubConfig,
94
+ },
95
+ production: {
96
+ channel: 'production',
97
+ autoIncrement: true,
98
+ ...easBuildGitHubConfig,
99
+ },
100
+ },
101
+ submit: {
102
+ production: {},
103
+ },
104
+ };
105
+ const easJsonPath = path_1.default.join(projectDir, 'eas.json');
106
+ await fs_extra_1.default.writeJson(easJsonPath, easJson, { spaces: 2 });
107
+ log_1.default.withTick(`Generated ${chalk_1.default.bold('eas.json')}. ${(0, log_1.learnMore)('https://docs.expo.dev/build-reference/eas-json/')}`);
108
+ log_1.default.log();
109
+ }
110
+ exports.generateEasConfigAsync = generateEasConfigAsync;
111
+ async function updatePackageJsonAsync(projectDir) {
112
+ const packageJsonPath = path_1.default.join(projectDir, 'package.json');
113
+ const packageJson = await fs_extra_1.default.readJson(packageJsonPath);
114
+ if (!packageJson.scripts) {
115
+ packageJson.scripts = {};
116
+ }
117
+ packageJson.scripts.preview = 'npx eas-cli@latest workflow:run publish-preview-update.yml';
118
+ packageJson.scripts['development-builds'] =
119
+ 'npx eas-cli@latest workflow:run create-development-builds.yml';
120
+ packageJson.scripts.deploy = 'npx eas-cli@latest workflow:run deploy-to-production.yml';
121
+ await fs_extra_1.default.writeJson(packageJsonPath, packageJson, { spaces: 2 });
122
+ log_1.default.withTick('Updated package.json with scripts');
123
+ log_1.default.log();
124
+ }
125
+ exports.updatePackageJsonAsync = updatePackageJsonAsync;
126
+ async function copyProjectTemplatesAsync(projectDir) {
127
+ const templatesSourceDir = path_1.default.join(__dirname, 'templates', '.eas', 'workflows');
128
+ const easWorkflowsTargetDir = path_1.default.join(projectDir, '.eas', 'workflows');
129
+ await fs_extra_1.default.copy(templatesSourceDir, easWorkflowsTargetDir, {
130
+ overwrite: true,
131
+ errorOnExist: false,
132
+ });
133
+ log_1.default.withTick('Created EAS workflow files');
134
+ log_1.default.log();
135
+ }
136
+ exports.copyProjectTemplatesAsync = copyProjectTemplatesAsync;
137
+ async function updateReadmeAsync(projectDir, packageManager) {
138
+ const readmeTemplatePath = path_1.default.join(__dirname, 'templates', 'readme-additions.md');
139
+ const projectReadmePath = path_1.default.join(projectDir, 'README.md');
140
+ const readmeAdditions = await fs_extra_1.default.readFile(readmeTemplatePath, 'utf8');
141
+ const existingReadme = await fs_extra_1.default.readFile(projectReadmePath, 'utf8');
142
+ const targetSection = '## Get started';
143
+ const sectionIndex = existingReadme.indexOf(targetSection);
144
+ let mergedReadme;
145
+ if (sectionIndex !== -1) {
146
+ // Find the next ## section after "## Get started"
147
+ const afterTargetSection = existingReadme.substring(sectionIndex);
148
+ const nextSectionMatch = afterTargetSection.match(/\n## /);
149
+ let endIndex = existingReadme.length;
150
+ if (nextSectionMatch?.index !== undefined) {
151
+ // Replace from "## Get started" to the next "##" section
152
+ endIndex = sectionIndex + nextSectionMatch.index;
153
+ }
154
+ const beforeSection = existingReadme.substring(0, sectionIndex).trim();
155
+ const afterSection = existingReadme.substring(endIndex);
156
+ mergedReadme = beforeSection + '\n\n' + readmeAdditions.trim() + '\n\n' + afterSection;
157
+ }
158
+ else {
159
+ // No "Get started" section found, append the template to the existing README
160
+ mergedReadme = existingReadme.trim() + '\n\n' + readmeAdditions.trim();
161
+ }
162
+ mergedReadme = mergedReadme.replaceAll('npm run', `${packageManager} run`);
163
+ await fs_extra_1.default.writeFile(projectReadmePath, mergedReadme);
164
+ log_1.default.withTick('Updated README.md with EAS configuration details');
165
+ log_1.default.log();
166
+ }
167
+ exports.updateReadmeAsync = updateReadmeAsync;
@@ -0,0 +1,21 @@
1
+ name: Create development builds
2
+
3
+ jobs:
4
+ android_development_build:
5
+ name: Build Android
6
+ type: build
7
+ params:
8
+ platform: android
9
+ profile: development
10
+ ios_device_development_build:
11
+ name: Build iOS device
12
+ type: build
13
+ params:
14
+ platform: ios
15
+ profile: development
16
+ ios_simulator_development_build:
17
+ name: Build iOS simulator
18
+ type: build
19
+ params:
20
+ platform: ios
21
+ profile: development-simulator
@@ -0,0 +1,68 @@
1
+ name: Deploy to production
2
+
3
+ on:
4
+ push:
5
+ branches: ['main']
6
+
7
+ jobs:
8
+ fingerprint:
9
+ name: Fingerprint
10
+ type: fingerprint
11
+ get_android_build:
12
+ name: Check for existing android build
13
+ needs: [fingerprint]
14
+ type: get-build
15
+ params:
16
+ fingerprint_hash: ${{ needs.fingerprint.outputs.android_fingerprint_hash }}
17
+ profile: production
18
+ get_ios_build:
19
+ name: Check for existing ios build
20
+ needs: [fingerprint]
21
+ type: get-build
22
+ params:
23
+ fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
24
+ profile: production
25
+ build_android:
26
+ name: Build Android
27
+ needs: [get_android_build]
28
+ if: ${{ !needs.get_android_build.outputs.build_id }}
29
+ type: build
30
+ params:
31
+ platform: android
32
+ profile: production
33
+ build_ios:
34
+ name: Build iOS
35
+ needs: [get_ios_build]
36
+ if: ${{ !needs.get_ios_build.outputs.build_id }}
37
+ type: build
38
+ params:
39
+ platform: ios
40
+ profile: production
41
+ submit_android_build:
42
+ name: Submit Android Build
43
+ needs: [build_android]
44
+ type: submit
45
+ params:
46
+ build_id: ${{ needs.build_android.outputs.build_id }}
47
+ submit_ios_build:
48
+ name: Submit iOS Build
49
+ needs: [build_ios]
50
+ type: submit
51
+ params:
52
+ build_id: ${{ needs.build_ios.outputs.build_id }}
53
+ publish_android_update:
54
+ name: Publish Android update
55
+ needs: [get_android_build]
56
+ if: ${{ needs.get_android_build.outputs.build_id }}
57
+ type: update
58
+ params:
59
+ branch: production
60
+ platform: android
61
+ publish_ios_update:
62
+ name: Publish iOS update
63
+ needs: [get_ios_build]
64
+ if: ${{ needs.get_ios_build.outputs.build_id }}
65
+ type: update
66
+ params:
67
+ branch: production
68
+ platform: ios
@@ -0,0 +1,12 @@
1
+ name: Publish preview update
2
+
3
+ on:
4
+ push:
5
+ branches: ['*']
6
+
7
+ jobs:
8
+ publish_preview_update:
9
+ name: Publish preview update
10
+ type: update
11
+ params:
12
+ branch: ${{ github.ref_name || 'test' }}
@@ -0,0 +1,36 @@
1
+ ## Get started
2
+
3
+ To start the app, in your terminal run:
4
+
5
+ ```bash
6
+ npm run start
7
+ ```
8
+
9
+ In the output, you'll find options to open the app in:
10
+
11
+ - [a development build](https://docs.expo.dev/develop/development-builds/introduction/)
12
+ - [an Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
13
+ - [an iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
14
+ - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
15
+
16
+ You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
17
+
18
+ ## Workflows
19
+
20
+ This project is configured to use [EAS Workflows](https://docs.expo.dev/eas/workflows/get-started/) to automate some development and release processes. These commands are set up in [`package.json`](./package.json) and can be run using NPM scripts in your terminal.
21
+
22
+ ### Previews
23
+
24
+ Run `npm run preview` to [publish a preview update](https://docs.expo.dev/eas/workflows/examples/publish-preview-update/) of your project, which can be viewed in Expo Go or in a development build.
25
+
26
+ ### Development Builds
27
+
28
+ Run `npm run development-builds` to [create a development build](https://docs.expo.dev/eas/workflows/examples/create-development-builds/). Note - you'll need to follow the [Prerequisites](https://docs.expo.dev/eas/workflows/examples/create-development-builds/#prerequisites) to ensure you have the correct emulator setup on your machine.
29
+
30
+ ### Production Deployments
31
+
32
+ Run `npm run deploy` to [deploy to production](https://docs.expo.dev/eas/workflows/examples/deploy-to-production/). Note - you'll need to follow the [Prerequisites](https://docs.expo.dev/eas/workflows/examples/deploy-to-production/#prerequisites) to ensure you're set up to submit to the Apple and Google stores.
33
+
34
+ ## Hosting
35
+
36
+ Expo offers hosting for websites and API functions via EAS Hosting. See the [Getting Started](https://docs.expo.dev/eas/hosting/get-started/) guide to learn more.
@@ -2,30 +2,34 @@ import EasCommand from '../../commandUtils/EasCommand';
2
2
  import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
3
3
  import { AppFragment } from '../../graphql/generated';
4
4
  import { PackageManager } from '../../onboarding/installDependencies';
5
- import { Choice } from '../../prompts';
6
5
  import { Actor } from '../../user/User';
7
- export declare function promptForTargetDirectoryAsync(targetProjectDirFromArgs?: string): Promise<string>;
8
- export declare function cloneTemplateAsync(targetProjectDir: string): Promise<string>;
9
- export declare function installProjectDependenciesAsync(projectDir: string): Promise<PackageManager>;
10
- export declare function getAccountChoices(actor: Actor, namesWithSufficientPermissions: Set<string>): Choice[];
11
- export declare function createProjectAsync(graphqlClient: ExpoGraphqlClient, actor: Actor, projectDir: string): Promise<string>;
12
- export declare function stripInvalidCharactersForBundleIdentifier(string: string): string;
13
- export declare function generateConfigFilesAsync(projectDir: string, app: AppFragment): Promise<void>;
14
- export declare function generateAppConfigAsync(projectDir: string, app: AppFragment): Promise<void>;
15
- export declare function generateEasConfigAsync(projectDir: string): Promise<void>;
16
- export declare function updatePackageJsonAsync(projectDir: string): Promise<void>;
17
- export declare function copyProjectTemplatesAsync(projectDir: string): Promise<void>;
18
- export declare function mergeReadmeAsync(projectDir: string): Promise<void>;
19
- export declare function initializeGitRepositoryAsync(projectDir: string): Promise<void>;
20
- export declare const formatScriptCommand: (script: string, packageManager: PackageManager) => string;
6
+ export declare function generateConfigsAsync(args: {
7
+ path?: string;
8
+ }, actor: Actor, graphqlClient: ExpoGraphqlClient): Promise<{
9
+ projectName: string;
10
+ projectDirectory: string;
11
+ projectAccount: string;
12
+ }>;
13
+ export declare function createProjectAsync({ graphqlClient, actor, projectDirectory, projectAccount, projectName, }: {
14
+ graphqlClient: ExpoGraphqlClient;
15
+ actor: Actor;
16
+ projectDirectory: string;
17
+ projectAccount: string;
18
+ projectName: string;
19
+ }): Promise<string>;
20
+ export declare function generateProjectFilesAsync(projectDir: string, app: AppFragment, packageManager: PackageManager): Promise<void>;
21
21
  export default class New extends EasCommand {
22
22
  static aliases: string[];
23
23
  static description: string;
24
- static flags: {};
25
- static hidden: boolean;
26
24
  static args: {
27
25
  name: string;
26
+ description: string;
27
+ required: boolean;
28
28
  }[];
29
+ static flags: {
30
+ 'package-manager': import("@oclif/core/lib/interfaces").OptionFlag<"npm" | "pnpm" | "bun" | "yarn">;
31
+ };
32
+ static hidden: boolean;
29
33
  static contextDefinition: {
30
34
  loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
31
35
  };