eas-build-cache-provider 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # eas-build-cache-provider
2
+
3
+ A build cache provider plugin for the Expo CLI
@@ -0,0 +1,9 @@
1
+ import { SpawnResult } from '@expo/spawn-async';
2
+ type RunOptions = any;
3
+ export declare function isSpawnResultError(obj: any): obj is Error & SpawnResult;
4
+ export declare function isDevClientBuild({ runOptions, projectRoot, }: {
5
+ runOptions: RunOptions;
6
+ projectRoot: string;
7
+ }): boolean;
8
+ export declare function hasDirectDevClientDependency(projectRoot: string): boolean;
9
+ export {};
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasDirectDevClientDependency = exports.isDevClientBuild = exports.isSpawnResultError = void 0;
4
+ const config_1 = require("@expo/config");
5
+ function isSpawnResultError(obj) {
6
+ return (obj &&
7
+ 'message' in obj &&
8
+ obj.status !== undefined &&
9
+ obj.stdout !== undefined &&
10
+ obj.stderr !== undefined);
11
+ }
12
+ exports.isSpawnResultError = isSpawnResultError;
13
+ function isDevClientBuild({ runOptions, projectRoot, }) {
14
+ if (!hasDirectDevClientDependency(projectRoot)) {
15
+ return false;
16
+ }
17
+ if ('variant' in runOptions && runOptions.variant !== undefined) {
18
+ return runOptions.variant === 'debug';
19
+ }
20
+ if ('configuration' in runOptions && runOptions.configuration !== undefined) {
21
+ return runOptions.configuration === 'Debug';
22
+ }
23
+ return true;
24
+ }
25
+ exports.isDevClientBuild = isDevClientBuild;
26
+ function hasDirectDevClientDependency(projectRoot) {
27
+ const { dependencies = {}, devDependencies = {} } = (0, config_1.getPackageJson)(projectRoot);
28
+ return !!dependencies['expo-dev-client'] || !!devDependencies['expo-dev-client'];
29
+ }
30
+ exports.hasDirectDevClientDependency = hasDirectDevClientDependency;
@@ -0,0 +1,3 @@
1
+ type RemoteBuildCachePlugin = any;
2
+ declare const EASRemoteBuildCacheProvider: RemoteBuildCachePlugin;
3
+ export default EASRemoteBuildCacheProvider;
package/build/index.js ADDED
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ const helpers_1 = require("./helpers");
9
+ const log_1 = tslib_1.__importDefault(require("./log"));
10
+ async function resolveRemoteBuildCacheAsync({ projectRoot, platform, fingerprintHash, runOptions, }) {
11
+ const easJsonPath = path_1.default.join(projectRoot, 'eas.json');
12
+ if (!(await fs_extra_1.default.exists(easJsonPath))) {
13
+ log_1.default.debug('eas.json not found, skip checking for remote builds');
14
+ return null;
15
+ }
16
+ log_1.default.log((0, chalk_1.default) `{whiteBright \u203A} {bold Searching builds with matching fingerprint on EAS servers}`);
17
+ try {
18
+ const results = await (0, spawn_async_1.default)('npx', [
19
+ 'eas-cli',
20
+ 'build:download',
21
+ `--platform=${platform}`,
22
+ `--fingerprint=${fingerprintHash}`,
23
+ '--non-interactive',
24
+ (0, helpers_1.isDevClientBuild)({ runOptions, projectRoot }) ? '--dev-client' : '--no-dev-client',
25
+ '--json',
26
+ ], {
27
+ cwd: projectRoot,
28
+ });
29
+ log_1.default.log((0, chalk_1.default) `{whiteBright \u203A} {bold Successfully downloaded cached build}`);
30
+ // {
31
+ // "path": "/var/folders/03/lppcpcnn61q3mz5ckzmzd8w80000gn/T/eas-cli-nodejs/eas-build-run-cache/c0f9ba9c-0cf1-4c5c-8566-b28b7971050f_22f1bbfa-1c09-4b67-9e4a-721906546b58.app"
32
+ // }
33
+ const json = JSON.parse(results.stdout.trim());
34
+ return json?.path;
35
+ }
36
+ catch (error) {
37
+ log_1.default.debug('eas-cli error:', error);
38
+ // @TODO(2025-04-11): remove this in a future release
39
+ if ((0, helpers_1.isSpawnResultError)(error) && error.stderr.includes('command build:download not found')) {
40
+ log_1.default.warn(`To take advantage of remote build cache, upgrade your eas-cli installation to latest.`);
41
+ }
42
+ return null;
43
+ }
44
+ }
45
+ async function uploadEASRemoteBuildCacheAsync({ projectRoot, platform, fingerprintHash, buildPath, }) {
46
+ const easJsonPath = path_1.default.join(projectRoot, 'eas.json');
47
+ if (!(await fs_extra_1.default.exists(easJsonPath))) {
48
+ log_1.default.debug('eas.json not found, skip uploading builds');
49
+ return null;
50
+ }
51
+ try {
52
+ log_1.default.log((0, chalk_1.default) `{whiteBright \u203A} {bold Uploading build to remote cache}`);
53
+ const results = await (0, spawn_async_1.default)('npx', [
54
+ 'eas-cli',
55
+ 'upload',
56
+ `--platform=${platform}`,
57
+ `--fingerprint=${fingerprintHash}`,
58
+ buildPath ? `--build-path=${buildPath}` : '',
59
+ '--non-interactive',
60
+ '--json',
61
+ ], {
62
+ cwd: projectRoot,
63
+ });
64
+ // {
65
+ // "url": "/var/folders/03/lppcpcnn61q3mz5ckzmzd8w80000gn/T/eas-cli-nodejs/eas-build-run-cache/c0f9ba9c-0cf1-4c5c-8566-b28b7971050f_22f1bbfa-1c09-4b67-9e4a-721906546b58.app"
66
+ // }
67
+ const json = JSON.parse(results.stdout.trim());
68
+ log_1.default.log((0, chalk_1.default) `{whiteBright \u203A} {bold Build successfully uploaded: ${json?.url}}`);
69
+ return json?.url;
70
+ }
71
+ catch (error) {
72
+ log_1.default.debug('eas-cli error:', error);
73
+ }
74
+ return null;
75
+ }
76
+ async function calculateEASFingerprintHashAsync({ projectRoot, platform, }) {
77
+ // prefer using `eas fingerprint:generate` because it automatically upload sources
78
+ try {
79
+ const results = await (0, spawn_async_1.default)('npx', ['eas-cli', 'fingerprint:generate', `--platform=${platform}`, '--json', '--non-interactive'], {
80
+ cwd: projectRoot,
81
+ });
82
+ // {
83
+ // "hash": "203f960b965e154b77dc31c6c42e5582e8d77196"
84
+ // }
85
+ const json = JSON.parse(results.stdout.trim());
86
+ return json?.hash;
87
+ }
88
+ catch (error) {
89
+ log_1.default.debug('eas-cli error:', error);
90
+ }
91
+ return null;
92
+ }
93
+ const EASRemoteBuildCacheProvider = {
94
+ resolveRemoteBuildCache: resolveRemoteBuildCacheAsync,
95
+ uploadRemoteBuildCache: uploadEASRemoteBuildCacheAsync,
96
+ calculateFingerprintHash: calculateEASFingerprintHashAsync,
97
+ };
98
+ exports.default = EASRemoteBuildCacheProvider;
package/build/log.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ export default class Log {
2
+ static readonly isDebug: boolean;
3
+ static log(...args: any[]): void;
4
+ static newLine(): void;
5
+ static addNewLineIfNone(): void;
6
+ static error(...args: any[]): void;
7
+ static warn(...args: any[]): void;
8
+ static debug(...args: any[]): void;
9
+ static gray(...args: any[]): void;
10
+ static warnDeprecatedFlag(flag: string, message: string): void;
11
+ static fail(message: string): void;
12
+ static succeed(message: string): void;
13
+ static withTick(...args: any[]): void;
14
+ static withInfo(...args: any[]): void;
15
+ private static consoleLog;
16
+ private static withTextColor;
17
+ private static isLastLineNewLine;
18
+ private static updateIsLastLineNewLine;
19
+ }
20
+ /**
21
+ * Prints a link for given URL, using text if provided, otherwise text is just the URL.
22
+ * Format links as dim (unless disabled) and with an underline.
23
+ *
24
+ * @example https://expo.dev
25
+ */
26
+ export declare function link(url: string, { text, fallback, dim }?: {
27
+ text?: string;
28
+ dim?: boolean;
29
+ fallback?: string;
30
+ }): string;
31
+ /**
32
+ * Provide a consistent "Learn more" link experience.
33
+ * Format links as dim (unless disabled) with an underline.
34
+ *
35
+ * @example Learn more: https://expo.dev
36
+ */
37
+ export declare function learnMore(url: string, { learnMoreMessage: maybeLearnMoreMessage, dim, }?: {
38
+ learnMoreMessage?: string;
39
+ dim?: boolean;
40
+ }): string;
package/build/log.js ADDED
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.learnMore = exports.link = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const figures_1 = tslib_1.__importDefault(require("figures"));
7
+ const getenv_1 = require("getenv");
8
+ const log_symbols_1 = tslib_1.__importDefault(require("log-symbols"));
9
+ const terminal_link_1 = tslib_1.__importDefault(require("terminal-link"));
10
+ class Log {
11
+ static isDebug = (0, getenv_1.boolish)('EXPO_DEBUG', false);
12
+ static log(...args) {
13
+ Log.consoleLog(...args);
14
+ }
15
+ static newLine() {
16
+ Log.consoleLog();
17
+ }
18
+ static addNewLineIfNone() {
19
+ if (!Log.isLastLineNewLine) {
20
+ Log.newLine();
21
+ }
22
+ }
23
+ static error(...args) {
24
+ Log.consoleLog(...Log.withTextColor(args, chalk_1.default.red));
25
+ }
26
+ static warn(...args) {
27
+ Log.consoleLog(...Log.withTextColor(args, chalk_1.default.yellow));
28
+ }
29
+ static debug(...args) {
30
+ if (Log.isDebug) {
31
+ Log.consoleLog(...args);
32
+ }
33
+ }
34
+ static gray(...args) {
35
+ Log.consoleLog(...Log.withTextColor(args, chalk_1.default.gray));
36
+ }
37
+ static warnDeprecatedFlag(flag, message) {
38
+ Log.warn(`› ${chalk_1.default.bold('--' + flag)} flag is deprecated. ${message}`);
39
+ }
40
+ static fail(message) {
41
+ Log.log(`${chalk_1.default.red(log_symbols_1.default.error)} ${message}`);
42
+ }
43
+ static succeed(message) {
44
+ Log.log(`${chalk_1.default.green(log_symbols_1.default.success)} ${message}`);
45
+ }
46
+ static withTick(...args) {
47
+ Log.consoleLog(chalk_1.default.green(figures_1.default.tick), ...args);
48
+ }
49
+ static withInfo(...args) {
50
+ Log.consoleLog(chalk_1.default.green(figures_1.default.info), ...args);
51
+ }
52
+ static consoleLog(...args) {
53
+ Log.updateIsLastLineNewLine(args);
54
+ // eslint-disable-next-line no-console
55
+ console.log(...args);
56
+ }
57
+ static withTextColor(args, chalkColor) {
58
+ return args.map(arg => chalkColor(arg));
59
+ }
60
+ static isLastLineNewLine = false;
61
+ static updateIsLastLineNewLine(args) {
62
+ if (args.length === 0) {
63
+ Log.isLastLineNewLine = true;
64
+ }
65
+ else {
66
+ const lastArg = args[args.length - 1];
67
+ if (typeof lastArg === 'string' && (lastArg === '' || lastArg.match(/[\r\n]$/))) {
68
+ Log.isLastLineNewLine = true;
69
+ }
70
+ else {
71
+ Log.isLastLineNewLine = false;
72
+ }
73
+ }
74
+ }
75
+ }
76
+ exports.default = Log;
77
+ /**
78
+ * Prints a link for given URL, using text if provided, otherwise text is just the URL.
79
+ * Format links as dim (unless disabled) and with an underline.
80
+ *
81
+ * @example https://expo.dev
82
+ */
83
+ function link(url, { text = url, fallback, dim = true } = {}) {
84
+ // Links can be disabled via env variables https://github.com/jamestalmage/supports-hyperlinks/blob/master/index.js
85
+ const output = (0, terminal_link_1.default)(text, url, {
86
+ fallback: () => fallback ?? (text === url ? chalk_1.default.underline(url) : `${text}: ${chalk_1.default.underline(url)}`),
87
+ });
88
+ return dim ? chalk_1.default.dim(output) : output;
89
+ }
90
+ exports.link = link;
91
+ /**
92
+ * Provide a consistent "Learn more" link experience.
93
+ * Format links as dim (unless disabled) with an underline.
94
+ *
95
+ * @example Learn more: https://expo.dev
96
+ */
97
+ function learnMore(url, { learnMoreMessage: maybeLearnMoreMessage, dim = true, } = {}) {
98
+ return link(url, { text: maybeLearnMoreMessage ?? 'Learn more', dim });
99
+ }
100
+ exports.learnMore = learnMore;
File without changes
package/build/types.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "eas-build-cache-provider",
3
+ "description": "A build cache provider plugin for the Expo CLI",
4
+ "version": "0.0.1",
5
+ "author": "Expo <support@expo.dev>",
6
+ "bugs": "https://github.com/expo/eas-cli/issues",
7
+ "dependencies": {
8
+ "@babel/code-frame": "7.23.5",
9
+ "@expo/config-plugins": "9.0.12",
10
+ "@expo/spawn-async": "^1.7.2",
11
+ "chalk": "4.1.2",
12
+ "fs-extra": "11.2.0",
13
+ "log-symbols": "4.1.0",
14
+ "semver": "7.5.2",
15
+ "terminal-link": "2.1.1",
16
+ "tslib": "2.4.1"
17
+ },
18
+ "devDependencies": {
19
+ "@tsconfig/node18": "18.2.4",
20
+ "@types/babel__code-frame": "7.0.3",
21
+ "@types/fs-extra": "11.0.4",
22
+ "memfs": "3.4.13",
23
+ "rimraf": "3.0.2",
24
+ "typescript": "5.3.3"
25
+ },
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "homepage": "https://github.com/expo/eas-cli",
30
+ "license": "MIT",
31
+ "main": "build/index.js",
32
+ "types": "build/index.d.ts",
33
+ "repository": "expo/eas-cli",
34
+ "scripts": {
35
+ "build": "tsc --project tsconfig.build.json",
36
+ "build-allow-unused": "tsc --project tsconfig.allowUnused.json",
37
+ "watch": "yarn build --watch --preserveWatchOutput",
38
+ "watch-allow-unused": "yarn build-allow-unused --watch --preserveWatchOutput",
39
+ "typecheck": "tsc",
40
+ "prepack": "yarn rebuild",
41
+ "rebuild": "rimraf build && yarn build",
42
+ "test": "jest",
43
+ "clean": "rimraf build node_modules yarn-error.log"
44
+ },
45
+ "files": [
46
+ "/build"
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "volta": {
52
+ "node": "20.11.0",
53
+ "yarn": "1.22.21"
54
+ }
55
+ }