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.
@@ -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
- const hasManifest = findByName(root, 'PrivacyInfo.xcprivacy').length > 0;
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 (tracking.length)
299
- return makeItem(item, 'fail', 'Tracking SDK pattern found but no PrivacyInfo.xcprivacy file was found.', evidence(tracking));
300
- if (requiredReasonApi.length)
301
- return makeItem(item, 'warning', 'Required-reason API pattern found but no PrivacyInfo.xcprivacy file was found.', evidence(requiredReasonApi));
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.162';
1
+ export const CLI_VERSION = '0.2.163';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runcloud",
3
- "version": "0.2.162",
3
+ "version": "0.2.163",
4
4
  "description": "Create and control run.cloud remote mobile simulators and cloud sandboxes",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
Binary file
Binary file