runcloud 0.2.162 → 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 +29 -10
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/runcloud-0.2.163.tgz +0 -0
- package/runcloud-0.2.162.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,9 @@ 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',
|
|
48
53
|
'apple_eu_trader_status',
|
|
49
54
|
'google_play_title',
|
|
50
55
|
'google_play_short_description',
|
|
@@ -87,6 +92,7 @@ const TEXT_EXTENSIONS = new Set([
|
|
|
87
92
|
'.swift',
|
|
88
93
|
'.ts',
|
|
89
94
|
'.tsx',
|
|
95
|
+
'.xcprivacy',
|
|
90
96
|
'.xml',
|
|
91
97
|
]);
|
|
92
98
|
const SKIP_DIRS = new Set([
|
|
@@ -155,6 +161,8 @@ function activeItems(manifest) {
|
|
|
155
161
|
return manifest.items.filter((item) => !item.deferred && item.resolvedBy !== 'card');
|
|
156
162
|
}
|
|
157
163
|
function evaluateLocalItem(root, appJson, item) {
|
|
164
|
+
if (item.id === 'scheme')
|
|
165
|
+
return evaluateScheme(root, appJson, item);
|
|
158
166
|
const rule = CONFIG_RULES[item.id];
|
|
159
167
|
if (rule)
|
|
160
168
|
return evaluateConfigItem(appJson, item, rule);
|
|
@@ -201,7 +209,7 @@ function evaluateLocalItem(root, appJson, item) {
|
|
|
201
209
|
case 'permission_descriptions':
|
|
202
210
|
return evaluatePermissionDescriptions(root, appJson, item);
|
|
203
211
|
case 'privacy_manifest':
|
|
204
|
-
return evaluatePrivacyManifest(root, item);
|
|
212
|
+
return evaluatePrivacyManifest(root, appJson, item);
|
|
205
213
|
default:
|
|
206
214
|
if (STORE_REMINDER_IDS.has(item.id)) {
|
|
207
215
|
return makeItem(item, 'info', 'Complete this declaration in Google Play Console.', 'Play Console questionnaire');
|
|
@@ -226,6 +234,14 @@ function evaluateConfigItem(appJson, item, rule) {
|
|
|
226
234
|
return makeItem(item, 'pass', `${item.label} is set.`, evidence);
|
|
227
235
|
return makeItem(item, rule.absent, `${item.label} is not set.`, evidence);
|
|
228
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
|
+
}
|
|
229
245
|
function evaluateEncryption(appJson, item) {
|
|
230
246
|
const plist = getPath(appJson, ['expo', 'ios', 'infoPlist', 'ITSAppUsesNonExemptEncryption']);
|
|
231
247
|
const config = getPath(appJson, ['expo', 'ios', 'config', 'usesNonExemptEncryption']);
|
|
@@ -289,16 +305,19 @@ function evaluatePermissionDescriptions(root, appJson, item) {
|
|
|
289
305
|
return makeItem(item, 'pass', 'Used iOS capabilities have usage descriptions.', 'app.json ios.infoPlist cross-check');
|
|
290
306
|
return makeItem(item, 'fail', 'Used iOS capability is missing an NS*UsageDescription.', missing.join('; '));
|
|
291
307
|
}
|
|
292
|
-
function evaluatePrivacyManifest(root, item) {
|
|
293
|
-
|
|
294
|
-
const requiredReasonApi = scan(root, /NSUserDefaults|systemUptime|fileModificationDate|diskSpace|activeInputModes/i);
|
|
295
|
-
const tracking = scan(root, TRACKING_SDK);
|
|
296
|
-
if (hasManifest)
|
|
308
|
+
function evaluatePrivacyManifest(root, appJson, item) {
|
|
309
|
+
if (findByName(root, 'PrivacyInfo.xcprivacy').length > 0)
|
|
297
310
|
return makeItem(item, 'pass', 'PrivacyInfo.xcprivacy is present.', 'scan: PrivacyInfo.xcprivacy found');
|
|
298
|
-
if (
|
|
299
|
-
return makeItem(item, '
|
|
300
|
-
|
|
301
|
-
|
|
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
|
+
}
|
|
302
321
|
return makeItem(item, 'pass', 'No required-reason API patterns found and no tracking SDK patterns found.', 'scan: no required privacy manifest signals found');
|
|
303
322
|
}
|
|
304
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.162.tgz
DELETED
|
Binary file
|