runcloud 0.2.161 → 0.2.163
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 +30 -10
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/runcloud-0.2.163.tgz +0 -0
- package/runcloud-0.2.161.tgz +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, statSync, } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
const PREVIEW_APP_ID = 'app.newly.preview';
|
|
4
|
+
const SCAFFOLD_SCHEME = 'expobase';
|
|
5
|
+
const INBOUND_LINK = /Linking\.createURL|makeRedirectUri|emailRedirectTo|\bredirectTo\s*:|expobase:\/\//;
|
|
4
6
|
const PLACEHOLDER_COPY = /lorem ipsum|example\.com|\bTBD\b|\bTODO\b|\bplaceholder\b/i;
|
|
5
7
|
const INPUT_PLACEHOLDER = /\bplaceholder\??\s*[=:]\s*(\{[^}]*\}|"[^"]*"|'[^']*'|`[^`]*`|[\w.$]+)/gi;
|
|
6
8
|
const PLACEHOLDER_NAME = /\.placeholder\b|\bplaceholder\b(?=\s*[,})\]])/gi;
|
|
@@ -45,6 +47,10 @@ const LIVE_STORE_IDS = new Set([
|
|
|
45
47
|
'apple_content_rights',
|
|
46
48
|
'apple_age_rating',
|
|
47
49
|
'apple_privacy_label',
|
|
50
|
+
'apple_review_notes',
|
|
51
|
+
'apple_review_contact',
|
|
52
|
+
'apple_review_recording',
|
|
53
|
+
'apple_eu_trader_status',
|
|
48
54
|
'google_play_title',
|
|
49
55
|
'google_play_short_description',
|
|
50
56
|
'google_play_description',
|
|
@@ -86,6 +92,7 @@ const TEXT_EXTENSIONS = new Set([
|
|
|
86
92
|
'.swift',
|
|
87
93
|
'.ts',
|
|
88
94
|
'.tsx',
|
|
95
|
+
'.xcprivacy',
|
|
89
96
|
'.xml',
|
|
90
97
|
]);
|
|
91
98
|
const SKIP_DIRS = new Set([
|
|
@@ -154,6 +161,8 @@ function activeItems(manifest) {
|
|
|
154
161
|
return manifest.items.filter((item) => !item.deferred && item.resolvedBy !== 'card');
|
|
155
162
|
}
|
|
156
163
|
function evaluateLocalItem(root, appJson, item) {
|
|
164
|
+
if (item.id === 'scheme')
|
|
165
|
+
return evaluateScheme(root, appJson, item);
|
|
157
166
|
const rule = CONFIG_RULES[item.id];
|
|
158
167
|
if (rule)
|
|
159
168
|
return evaluateConfigItem(appJson, item, rule);
|
|
@@ -200,7 +209,7 @@ function evaluateLocalItem(root, appJson, item) {
|
|
|
200
209
|
case 'permission_descriptions':
|
|
201
210
|
return evaluatePermissionDescriptions(root, appJson, item);
|
|
202
211
|
case 'privacy_manifest':
|
|
203
|
-
return evaluatePrivacyManifest(root, item);
|
|
212
|
+
return evaluatePrivacyManifest(root, appJson, item);
|
|
204
213
|
default:
|
|
205
214
|
if (STORE_REMINDER_IDS.has(item.id)) {
|
|
206
215
|
return makeItem(item, 'info', 'Complete this declaration in Google Play Console.', 'Play Console questionnaire');
|
|
@@ -225,6 +234,14 @@ function evaluateConfigItem(appJson, item, rule) {
|
|
|
225
234
|
return makeItem(item, 'pass', `${item.label} is set.`, evidence);
|
|
226
235
|
return makeItem(item, rule.absent, `${item.label} is not set.`, evidence);
|
|
227
236
|
}
|
|
237
|
+
function evaluateScheme(root, appJson, item) {
|
|
238
|
+
const value = getPath(appJson, ['expo', 'scheme']);
|
|
239
|
+
const schemes = typeof value === 'string' ? [value] : arrayOfStrings(value);
|
|
240
|
+
const shared = schemes.includes(SCAFFOLD_SCHEME) ? scan(root, INBOUND_LINK, { dirs: ['app', 'src', 'components'] }) : [];
|
|
241
|
+
if (!shared.length)
|
|
242
|
+
return evaluateConfigItem(appJson, item, CONFIG_RULES['scheme']);
|
|
243
|
+
return makeItem(item, 'warning', `This app still uses the link name every new Newly app starts with (${SCAFFOLD_SCHEME}). A link back into the app, such as a sign-in email, can open another Newly-built app on the same phone. Give it its own scheme, and update any redirect address saved with your sign-in provider. The next preview then takes several minutes to rebuild.`, `app.json expo.scheme = ${JSON.stringify(value)}\n${evidence(shared)}`);
|
|
244
|
+
}
|
|
228
245
|
function evaluateEncryption(appJson, item) {
|
|
229
246
|
const plist = getPath(appJson, ['expo', 'ios', 'infoPlist', 'ITSAppUsesNonExemptEncryption']);
|
|
230
247
|
const config = getPath(appJson, ['expo', 'ios', 'config', 'usesNonExemptEncryption']);
|
|
@@ -288,16 +305,19 @@ function evaluatePermissionDescriptions(root, appJson, item) {
|
|
|
288
305
|
return makeItem(item, 'pass', 'Used iOS capabilities have usage descriptions.', 'app.json ios.infoPlist cross-check');
|
|
289
306
|
return makeItem(item, 'fail', 'Used iOS capability is missing an NS*UsageDescription.', missing.join('; '));
|
|
290
307
|
}
|
|
291
|
-
function evaluatePrivacyManifest(root, item) {
|
|
292
|
-
|
|
293
|
-
const requiredReasonApi = scan(root, /NSUserDefaults|systemUptime|fileModificationDate|diskSpace|activeInputModes/i);
|
|
294
|
-
const tracking = scan(root, TRACKING_SDK);
|
|
295
|
-
if (hasManifest)
|
|
308
|
+
function evaluatePrivacyManifest(root, appJson, item) {
|
|
309
|
+
if (findByName(root, 'PrivacyInfo.xcprivacy').length > 0)
|
|
296
310
|
return makeItem(item, 'pass', 'PrivacyInfo.xcprivacy is present.', 'scan: PrivacyInfo.xcprivacy found');
|
|
297
|
-
if (
|
|
298
|
-
return makeItem(item, '
|
|
299
|
-
|
|
300
|
-
|
|
311
|
+
if (Object.keys(objectValue(getPath(appJson, ['expo', 'ios', 'privacyManifests']))).length > 0)
|
|
312
|
+
return makeItem(item, 'pass', 'app.json declares the privacy manifest.', 'app.json expo.ios.privacyManifests is set');
|
|
313
|
+
const tracking = scan(root, TRACKING_SDK);
|
|
314
|
+
if (tracking.length) {
|
|
315
|
+
return makeItem(item, 'warning', 'This app uses a tracking SDK and app.json declares no privacy manifest. Add expo.ios.privacyManifests with NSPrivacyTracking and the domains the SDK tracks through, so the manifest matches your App Privacy answers.', evidence(tracking));
|
|
316
|
+
}
|
|
317
|
+
const requiredReasonApi = scan(root, /NSUserDefaults|systemUptime|fileModificationDate|diskSpace|activeInputModes/i);
|
|
318
|
+
if (requiredReasonApi.length) {
|
|
319
|
+
return makeItem(item, 'warning', 'This code uses an API Apple wants a reason for, and app.json declares none. Add the reason under expo.ios.privacyManifests (NSPrivacyAccessedAPITypes).', evidence(requiredReasonApi));
|
|
320
|
+
}
|
|
301
321
|
return makeItem(item, 'pass', 'No required-reason API patterns found and no tracking SDK patterns found.', 'scan: no required privacy manifest signals found');
|
|
302
322
|
}
|
|
303
323
|
function patternItem(root, item, regex, statusOnHit, messageOnHit, messageOnMiss, options = {}) {
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = '0.2.
|
|
1
|
+
export const CLI_VERSION = '0.2.163';
|
package/package.json
CHANGED
|
Binary file
|
package/runcloud-0.2.161.tgz
DELETED
|
Binary file
|