runcloud 0.2.154 → 0.2.155
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/dist/commands/appStoreEvaluate.js +32 -15
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/runcloud-0.2.155.tgz +0 -0
- package/runcloud-0.2.154.tgz +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, statSync, } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
const PREVIEW_APP_ID = 'app.newly.preview';
|
|
3
4
|
const CONFIG_RULES = {
|
|
4
5
|
app_name: { path: ['expo', 'name'], absent: 'fail' },
|
|
5
6
|
slug: { path: ['expo', 'slug'], absent: 'fail' },
|
|
6
|
-
ios_bundle_id: { path: ['expo', 'ios', 'bundleIdentifier'], absent: '
|
|
7
|
-
android_package: { path: ['expo', 'android', 'package'], absent: '
|
|
7
|
+
ios_bundle_id: { path: ['expo', 'ios', 'bundleIdentifier'], absent: 'info', storeId: /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)+$/ },
|
|
8
|
+
android_package: { path: ['expo', 'android', 'package'], absent: 'info', storeId: /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/ },
|
|
8
9
|
version: { path: ['expo', 'version'], absent: 'warning' },
|
|
9
10
|
scheme: { path: ['expo', 'scheme'], absent: 'info' },
|
|
10
|
-
ios_encryption: { path: ['expo', 'ios', 'infoPlist', 'ITSAppUsesNonExemptEncryption'], absent: 'warning' },
|
|
11
11
|
user_interface_style: { path: ['expo', 'userInterfaceStyle'], absent: 'info' },
|
|
12
12
|
orientation: { path: ['expo', 'orientation'], absent: 'info' },
|
|
13
13
|
ios_supports_tablet: { path: ['expo', 'ios', 'supportsTablet'], absent: 'info' },
|
|
@@ -183,6 +183,8 @@ function evaluateLocalItem(root, appJson, item) {
|
|
|
183
183
|
return evaluateExpoLayout(root, item);
|
|
184
184
|
case 'expo_duplicate_route':
|
|
185
185
|
return evaluateDuplicateRoutes(root, item);
|
|
186
|
+
case 'ios_encryption':
|
|
187
|
+
return evaluateEncryption(appJson, item);
|
|
186
188
|
case 'plugin_permission_missing':
|
|
187
189
|
return evaluatePluginPermissions(root, appJson, item);
|
|
188
190
|
case 'permission_descriptions':
|
|
@@ -202,10 +204,25 @@ function evaluateConfigItem(appJson, item, rule) {
|
|
|
202
204
|
const value = getPath(appJson, rule.path);
|
|
203
205
|
const present = hasValue(value);
|
|
204
206
|
const evidence = `app.json ${rule.path.join('.')} = ${value === undefined ? 'undefined' : JSON.stringify(value)}`;
|
|
207
|
+
if (rule.storeId) {
|
|
208
|
+
const id = stringValue(value);
|
|
209
|
+
if (!id || id.toLowerCase() === PREVIEW_APP_ID)
|
|
210
|
+
return makeItem(item, rule.absent, `${item.label} is assigned when you publish.`, evidence);
|
|
211
|
+
if (!rule.storeId.test(id) || id.length > 255)
|
|
212
|
+
return makeItem(item, 'fail', `${item.label} is not valid. Use a reverse-domain ID like com.yourname.app.`, evidence);
|
|
213
|
+
}
|
|
205
214
|
if (present)
|
|
206
215
|
return makeItem(item, 'pass', `${item.label} is set.`, evidence);
|
|
207
216
|
return makeItem(item, rule.absent, `${item.label} is not set.`, evidence);
|
|
208
217
|
}
|
|
218
|
+
function evaluateEncryption(appJson, item) {
|
|
219
|
+
const plist = getPath(appJson, ['expo', 'ios', 'infoPlist', 'ITSAppUsesNonExemptEncryption']);
|
|
220
|
+
const config = getPath(appJson, ['expo', 'ios', 'config', 'usesNonExemptEncryption']);
|
|
221
|
+
const evidence = `app.json expo.ios.infoPlist.ITSAppUsesNonExemptEncryption = ${JSON.stringify(plist) ?? 'undefined'}, expo.ios.config.usesNonExemptEncryption = ${JSON.stringify(config) ?? 'undefined'}`;
|
|
222
|
+
if (hasValue(plist) || hasValue(config))
|
|
223
|
+
return makeItem(item, 'pass', `${item.label} is set.`, evidence);
|
|
224
|
+
return makeItem(item, 'info', `${item.label} is declared exempt (no non-exempt encryption) when you publish.`, evidence);
|
|
225
|
+
}
|
|
209
226
|
function evaluateRestorePurchases(root, item) {
|
|
210
227
|
const iap = scan(root, /react-native-purchases|expo-in-app-purchases|StoreKit/i);
|
|
211
228
|
if (!iap.length)
|
|
@@ -242,14 +259,14 @@ function evaluateExpoLayout(root, item) {
|
|
|
242
259
|
return makeItem(item, 'fail', 'Expo Router directories without _layout files found.', missing.slice(0, 8).join(', '));
|
|
243
260
|
}
|
|
244
261
|
function evaluateDuplicateRoutes(root, item) {
|
|
245
|
-
const appDir =
|
|
262
|
+
const appDir = routerDir(root);
|
|
246
263
|
if (!existsSync(appDir))
|
|
247
264
|
return makeItem(item, 'pass', 'No Expo Router app directory found.', 'scan: app/ directory absent');
|
|
248
265
|
const routes = new Map();
|
|
249
266
|
for (const file of walkFiles(appDir)) {
|
|
250
267
|
if (!/\.(tsx|ts|jsx|js)$/.test(file) || /(^|\/)_layout\.(tsx|ts|jsx|js)$/.test(toRel(root, file)))
|
|
251
268
|
continue;
|
|
252
|
-
const route = routePath(
|
|
269
|
+
const route = routePath(appDir, file);
|
|
253
270
|
const current = routes.get(route) ?? [];
|
|
254
271
|
current.push(toRel(root, file));
|
|
255
272
|
routes.set(route, current);
|
|
@@ -422,14 +439,10 @@ function unresolvedReason(item) {
|
|
|
422
439
|
return `no deterministic evaluator is registered for ${item.check} item`;
|
|
423
440
|
}
|
|
424
441
|
function targetPlatformsFromAppJson(appJson) {
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
platforms.push('ios');
|
|
430
|
-
if (android)
|
|
431
|
-
platforms.push('android');
|
|
432
|
-
return platforms.length ? platforms : ['ios', 'android'];
|
|
442
|
+
const declared = getPath(appJson, ['expo', 'platforms']);
|
|
443
|
+
if (!Array.isArray(declared))
|
|
444
|
+
return ['ios', 'android'];
|
|
445
|
+
return ['ios', 'android'].filter((platform) => declared.includes(platform));
|
|
433
446
|
}
|
|
434
447
|
function targetsItem(item, targetPlatforms) {
|
|
435
448
|
return item.platform.some((platform) => targetPlatforms.includes(platform));
|
|
@@ -526,8 +539,12 @@ function sourceText(root, dirs) {
|
|
|
526
539
|
function hasLayoutFile(dir) {
|
|
527
540
|
return ['_layout.tsx', '_layout.ts', '_layout.jsx', '_layout.js'].some((name) => existsSync(path.join(dir, name)));
|
|
528
541
|
}
|
|
529
|
-
function
|
|
530
|
-
const
|
|
542
|
+
function routerDir(root) {
|
|
543
|
+
const src = path.join(root, 'src', 'app');
|
|
544
|
+
return safeStat(src)?.isDirectory() ? src : path.join(root, 'app');
|
|
545
|
+
}
|
|
546
|
+
function routePath(appDir, file) {
|
|
547
|
+
const rel = toRel(appDir, file).replace(/\.(tsx|ts|jsx|js)$/, '');
|
|
531
548
|
const parts = rel.split('/').filter((part) => part && !/^\(.+\)$/.test(part));
|
|
532
549
|
if (parts[parts.length - 1] === 'index')
|
|
533
550
|
parts.pop();
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = '0.2.
|
|
1
|
+
export const CLI_VERSION = '0.2.155';
|
package/package.json
CHANGED
|
Binary file
|
package/runcloud-0.2.154.tgz
DELETED
|
Binary file
|