stim 1.8.0 → 1.9.0
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 +23 -155
- package/dist/{android-BRgBYzU0.mjs → android-BPGizezh.mjs} +112 -135
- package/dist/{android-DeYdjjBP.mjs → android-DEgo4oCo.mjs} +2 -2
- package/dist/{android-DWssqHQ8.mjs → android-_y4Ohi5z.mjs} +54 -15
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-eiExNLf7.mjs} +21 -14
- package/dist/app-install-Uf3a83Tv.mjs +819 -0
- package/dist/{build-lock-CgtsB6TV.mjs → build-lock-DPXPLgTc.mjs} +120 -24
- package/dist/build-progress-CVqkfPC6.mjs +188 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Dg7OnMrp.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-gByVmIjy.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-Cp9lM3wX.mjs} +187 -57
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-Bq5DcLGn.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-Cip5vUm1.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-KEu0_AXL.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-HyqISM0h.mjs} +1178 -635
- package/dist/{device-RdujjHLB.mjs → device-D4U-xLty.mjs} +13 -20
- package/dist/{device-lease-Ffz_M5t0.mjs → device-lease-Crs-HkJY.mjs} +16 -9
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-CnTAz8X1.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-AQ5rQPqr.mjs} +482 -35
- package/dist/{doctor-BMt156qe.mjs → doctor-B_Ei3bZu.mjs} +95 -107
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-Vfz83GCF.mjs} +22 -16
- package/dist/exec-jIAlgilk.mjs +132 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-Ckw8RQHi.mjs} +763 -126
- package/dist/{guide-BTAlD1_y.mjs → guide-BiAbhs1J.mjs} +891 -501
- package/dist/{guide-status-Craq9z0t.mjs → guide-status-BAMVU0ZA.mjs} +5 -3
- package/dist/{ios-BcCiI4TS.mjs → ios-BL2NFckr.mjs} +43 -20
- package/dist/{ios-BP04pY5f.mjs → ios-BzUJWk1K.mjs} +141 -175
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-D972i9wf.mjs} +149 -52
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-DPsSm0v_.mjs} +3 -2
- package/dist/launch-verify-Q_OtW1Rf.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-CI9NQSK7.mjs} +18 -13
- package/dist/{logs-query-BGL-Pl12.mjs → logs-query-Cqma3WIu.mjs} +36 -28
- package/dist/{metro-C7bcJ0uo.mjs → metro-DrLHaMn2.mjs} +78 -8
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-CmLQSIRj.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-9uFNRwfe.mjs} +36 -3
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D15Op8vN.mjs} +3 -3
- package/dist/{ownership-wolE-0Do.mjs → ownership-DCQPuWEc.mjs} +26 -7
- package/dist/{ports-BIbJaKNW.mjs → ports-BNKoWVWZ.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-DS112DYB.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-ZNJUo1pl.mjs} +12 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DWkkcIxV.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-B_lctBR3.mjs} +8 -7
- package/dist/server-expo-CeILEu86.mjs +2 -0
- package/dist/settings-BKNh5rl4.mjs +376 -0
- package/dist/{settings-BXXorVM2.mjs → settings-D030k0t4.mjs} +464 -152
- package/dist/settings.schema.json +989 -0
- package/dist/{teardown-BJqEzPo_.mjs → sim-pool-KaIsp2Ft.mjs} +14 -419
- package/dist/simslim-B_LsGLuJ.mjs +259 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-DU9A-gYw.mjs} +4 -4
- package/dist/spawn-claims-Dn3C_N6w.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-DYkkKF0s.mjs} +27 -31
- package/dist/{state-DZobzxLW.mjs → state-NcJzMEBF.mjs} +5 -3
- package/dist/{stats-CLg5RuDS.mjs → stats-B63-JVAY.mjs} +4 -4
- package/dist/{stats-BYcZ6n1h.mjs → stats-DG9e66Rz.mjs} +66 -5
- package/dist/status-S6ehL4Ui.mjs +932 -0
- package/dist/{stop-C8JW6kKp.mjs → stop-BO28HGqF.mjs} +101 -25
- package/dist/{stop-B1kOpYei.mjs → stop-T1R-cZRz.mjs} +2 -2
- package/dist/supervisor-run.mjs +52 -34
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-DWaiRD0e.mjs} +14 -9
- package/dist/{workspace-state-BT5E3SA2.mjs → workspace-state-DF2gCFhx.mjs} +52 -29
- package/dist/worktree-DKhSF0UX.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-LGB-UwgG.mjs} +603 -59
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-R_cUlE7s.mjs} +62 -41
- package/dist/{xcode-B6YaWeg0.mjs → xcode-BZqyxh3e.mjs} +216 -58
- package/package.json +5 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/build-slots-C-oAHRT1.mjs +0 -151
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
import { d as getConfigPath, g as loadConfig, m as getRepoSettings, p as getProjectSettings } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import { isAbsolute } from "node:path";
|
|
1
|
+
import { d as getConfigPath, g as loadConfig, m as getRepoSettings, p as getProjectSettings } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { _ as repoRoot, s as gitCommonDir } from "./worktree-R_cUlE7s.mjs";
|
|
5
3
|
import { existsSync, readFileSync, realpathSync, statSync } from "fs";
|
|
6
|
-
import { isAbsolute
|
|
4
|
+
import { isAbsolute, join, relative, resolve, sep } from "path";
|
|
5
|
+
import { isAbsolute as isAbsolute$1 } from "node:path";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
7
|
//#region src/optimizations.ts
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"optimizations.android": "object",
|
|
20
|
-
"optimizations.android.compilerCache": "string",
|
|
21
|
-
"optimizations.android.casToolchain": "path",
|
|
22
|
-
"optimizations.android.pch": "string",
|
|
23
|
-
"optimizations.android.gradleBuildCache": "boolean",
|
|
24
|
-
"optimizations.android.targetAbiOnly": "boolean"
|
|
25
|
-
};
|
|
8
|
+
const ANDROID_COMPILER_CACHE_CHOICES = [
|
|
9
|
+
"auto",
|
|
10
|
+
"ccache",
|
|
11
|
+
"cas",
|
|
12
|
+
"none"
|
|
13
|
+
];
|
|
14
|
+
const ANDROID_PCH_CHOICES = [
|
|
15
|
+
"auto",
|
|
16
|
+
"on",
|
|
17
|
+
"off"
|
|
18
|
+
];
|
|
26
19
|
function compilerCacheFallbackMessage({ fallback, compilerCache, file = null }) {
|
|
27
20
|
const origin = fallback.fromEnvironment ? "the environment" : file;
|
|
28
21
|
const backend = compilerCache === "none" ? "Android builds use no compiler cache, because optimizations.android.compilerCache is \"none\"." : "Android builds fall back to ccache when it is available.";
|
|
@@ -48,18 +41,13 @@ function resolveOptimizations(settings = {}, env = process.env) {
|
|
|
48
41
|
if (typeof raw !== "string" || !choices.includes(raw)) throw new Error(`Invalid optimizations.${path}. Expected ${choices.join(", ")}.`);
|
|
49
42
|
return raw;
|
|
50
43
|
}
|
|
51
|
-
const compiler = choice("android.compilerCache",
|
|
52
|
-
"auto",
|
|
53
|
-
"ccache",
|
|
54
|
-
"cas",
|
|
55
|
-
"none"
|
|
56
|
-
], "auto");
|
|
44
|
+
const compiler = choice("android.compilerCache", ANDROID_COMPILER_CACHE_CHOICES, "auto");
|
|
57
45
|
const fromEnvironment = Boolean(env.STIM_ANDROID_CAS_TOOLCHAIN);
|
|
58
46
|
const manifest = env.STIM_ANDROID_CAS_TOOLCHAIN || optimizationValue(settings, "android.casToolchain");
|
|
59
47
|
let fallback = null;
|
|
60
48
|
let toolchain = null;
|
|
61
49
|
if (manifest !== void 0) {
|
|
62
|
-
if (typeof manifest === "string" && isAbsolute(manifest) && !/[\r\n\0]/.test(manifest)) toolchain = manifest;
|
|
50
|
+
if (typeof manifest === "string" && isAbsolute$1(manifest) && !/[\r\n\0]/.test(manifest)) toolchain = manifest;
|
|
63
51
|
else fallback = {
|
|
64
52
|
key: fromEnvironment ? "STIM_ANDROID_CAS_TOOLCHAIN" : "optimizations.android.casToolchain",
|
|
65
53
|
reason: `is ${JSON.stringify(manifest)}, which is not an absolute path to a toolchain JSON manifest`,
|
|
@@ -92,11 +80,7 @@ function resolveOptimizations(settings = {}, env = process.env) {
|
|
|
92
80
|
compilerCache,
|
|
93
81
|
casToolchain: toolchain,
|
|
94
82
|
compilerCacheFallback: fallback,
|
|
95
|
-
pch: choice("android.pch",
|
|
96
|
-
"auto",
|
|
97
|
-
"on",
|
|
98
|
-
"off"
|
|
99
|
-
], "auto"),
|
|
83
|
+
pch: choice("android.pch", ANDROID_PCH_CHOICES, "auto"),
|
|
100
84
|
gradleBuildCache: optimizationBoolean(settings, "android.gradleBuildCache"),
|
|
101
85
|
targetAbiOnly: optimizationBoolean(settings, "android.targetAbiOnly")
|
|
102
86
|
}
|
|
@@ -177,6 +161,409 @@ function detectProviders(onPath) {
|
|
|
177
161
|
return MANAGED_PROVIDERS.filter((p) => onPath(p));
|
|
178
162
|
}
|
|
179
163
|
//#endregion
|
|
164
|
+
//#region src/workspace/settings-registry.ts
|
|
165
|
+
const SETTING_SCOPES = [
|
|
166
|
+
"machine",
|
|
167
|
+
"workspace",
|
|
168
|
+
"repo",
|
|
169
|
+
"committed"
|
|
170
|
+
];
|
|
171
|
+
const REMOTE_DEVICE_BACKENDS = ["proxy", "eas"];
|
|
172
|
+
const IOS_SIMULATOR_APPS = [
|
|
173
|
+
"xcode",
|
|
174
|
+
"siniulator",
|
|
175
|
+
"stim-desktop"
|
|
176
|
+
];
|
|
177
|
+
const PROJECT = [
|
|
178
|
+
"workspace",
|
|
179
|
+
"repo",
|
|
180
|
+
"committed"
|
|
181
|
+
];
|
|
182
|
+
const EVERY = [
|
|
183
|
+
"machine",
|
|
184
|
+
"workspace",
|
|
185
|
+
"repo",
|
|
186
|
+
"committed"
|
|
187
|
+
];
|
|
188
|
+
const MACHINE = ["machine"];
|
|
189
|
+
const STRING = { kind: "string" };
|
|
190
|
+
const PATH = { kind: "path" };
|
|
191
|
+
const ABSOLUTE_PATH = {
|
|
192
|
+
kind: "path",
|
|
193
|
+
absolute: true
|
|
194
|
+
};
|
|
195
|
+
const RELATIVE_PATH = {
|
|
196
|
+
kind: "path",
|
|
197
|
+
relative: true
|
|
198
|
+
};
|
|
199
|
+
const BOOLEAN = { kind: "boolean" };
|
|
200
|
+
const OBJECT = { kind: "object" };
|
|
201
|
+
const REMOTE = {
|
|
202
|
+
kind: "choice",
|
|
203
|
+
choices: REMOTE_DEVICE_BACKENDS
|
|
204
|
+
};
|
|
205
|
+
const PARKED_MAX = {
|
|
206
|
+
kind: "number",
|
|
207
|
+
integer: true,
|
|
208
|
+
minimum: 0
|
|
209
|
+
};
|
|
210
|
+
const CAPACITY = {
|
|
211
|
+
kind: "number",
|
|
212
|
+
integer: true,
|
|
213
|
+
minimum: 0
|
|
214
|
+
};
|
|
215
|
+
function optimization(key, description, type = BOOLEAN) {
|
|
216
|
+
return {
|
|
217
|
+
key: `optimizations.${key}`,
|
|
218
|
+
type,
|
|
219
|
+
scopes: EVERY,
|
|
220
|
+
description,
|
|
221
|
+
...type.kind === "boolean" ? { default: true } : {}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const SETTINGS = [
|
|
225
|
+
optimization("buildCache", "Read and write native build artifacts"),
|
|
226
|
+
optimization("remoteBuildCache", "Use remote artifact providers"),
|
|
227
|
+
optimization("releaseBundleSwap", "Swap current JS into cached release builds"),
|
|
228
|
+
optimization("metroSharedCache", "Append Stim's shared Metro cache store"),
|
|
229
|
+
optimization("metroWarmup", "Prefetch the development bundle during ios and android"),
|
|
230
|
+
optimization("ios.compilationCache", "Xcode compilation caching"),
|
|
231
|
+
{
|
|
232
|
+
key: "optimizations.ios.swiftCompilationCache",
|
|
233
|
+
type: BOOLEAN,
|
|
234
|
+
scopes: EVERY,
|
|
235
|
+
description: "Swift compilation caching; unset detects toolchain support"
|
|
236
|
+
},
|
|
237
|
+
optimization("ios.prefixMapping", "Clang source and DerivedData prefix mapping"),
|
|
238
|
+
{
|
|
239
|
+
...optimization("android.compilerCache", "Android compiler cache backend", {
|
|
240
|
+
kind: "choice",
|
|
241
|
+
choices: ANDROID_COMPILER_CACHE_CHOICES
|
|
242
|
+
}),
|
|
243
|
+
default: "auto"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
...optimization("android.casToolchain", "Absolute path to the Android CAS toolchain manifest", ABSOLUTE_PATH),
|
|
247
|
+
env: "STIM_ANDROID_CAS_TOOLCHAIN"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
...optimization("android.pch", "Android precompiled headers", {
|
|
251
|
+
kind: "choice",
|
|
252
|
+
choices: ANDROID_PCH_CHOICES
|
|
253
|
+
}),
|
|
254
|
+
default: "auto"
|
|
255
|
+
},
|
|
256
|
+
optimization("android.gradleBuildCache", "Gradle build cache"),
|
|
257
|
+
optimization("android.targetAbiOnly", "Narrow Debug builds to the device ABI"),
|
|
258
|
+
{
|
|
259
|
+
key: "ios.deviceType",
|
|
260
|
+
type: STRING,
|
|
261
|
+
scopes: PROJECT,
|
|
262
|
+
description: "Simulator model for owned simulators"
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
key: "ios.runtime",
|
|
266
|
+
type: STRING,
|
|
267
|
+
scopes: PROJECT,
|
|
268
|
+
description: "iOS runtime owned simulators are created on"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
key: "ios.configuration",
|
|
272
|
+
type: STRING,
|
|
273
|
+
scopes: PROJECT,
|
|
274
|
+
default: "Debug",
|
|
275
|
+
description: "Xcode configuration to build, such as Debug or Release"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
key: "ios.remote",
|
|
279
|
+
type: REMOTE,
|
|
280
|
+
scopes: PROJECT,
|
|
281
|
+
description: "Default remote backend for iOS"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
key: "ios.simslimProfile",
|
|
285
|
+
type: RELATIVE_PATH,
|
|
286
|
+
scopes: PROJECT,
|
|
287
|
+
description: "SimSlim JSON profile under the app"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
key: "ios.signingIdentity",
|
|
291
|
+
type: STRING,
|
|
292
|
+
scopes: PROJECT,
|
|
293
|
+
description: "Keychain identity used to re-seal a device build"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
key: "ios.signingIdentitySha1",
|
|
297
|
+
type: {
|
|
298
|
+
kind: "string",
|
|
299
|
+
pattern: "^[0-9A-Fa-f]{40}$",
|
|
300
|
+
patternHelp: "a 40-character hex SHA-1 hash"
|
|
301
|
+
},
|
|
302
|
+
scopes: PROJECT,
|
|
303
|
+
description: "SHA-1 of the signing identity, when two share a name"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
key: "ios.lanHost",
|
|
307
|
+
type: {
|
|
308
|
+
kind: "string",
|
|
309
|
+
pattern: "^(?!-)[A-Za-z0-9-]+(?:\\.(?!-)[A-Za-z0-9-]+)*$",
|
|
310
|
+
patternHelp: "a bare address or hostname, never a URL, scheme, or port"
|
|
311
|
+
},
|
|
312
|
+
scopes: PROJECT,
|
|
313
|
+
description: "Address a phone uses to reach this workspace's Metro"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
key: "android.systemImage",
|
|
317
|
+
type: STRING,
|
|
318
|
+
scopes: PROJECT,
|
|
319
|
+
description: "SDK system image for owned AVDs"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
key: "android.dataPartitionSizeGb",
|
|
323
|
+
type: {
|
|
324
|
+
kind: "number",
|
|
325
|
+
integer: true,
|
|
326
|
+
minimum: 6,
|
|
327
|
+
maximum: 16384
|
|
328
|
+
},
|
|
329
|
+
scopes: PROJECT,
|
|
330
|
+
default: 8,
|
|
331
|
+
description: "Data partition size of a new owned AVD, in GiB"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
key: "android.avdConfigFile",
|
|
335
|
+
type: RELATIVE_PATH,
|
|
336
|
+
scopes: PROJECT,
|
|
337
|
+
description: "AVD config.ini fragment under the app"
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
key: "android.avdConfig",
|
|
341
|
+
type: OBJECT,
|
|
342
|
+
scopes: PROJECT,
|
|
343
|
+
description: "Validated AVD config values"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
key: "android.variant",
|
|
347
|
+
type: STRING,
|
|
348
|
+
scopes: PROJECT,
|
|
349
|
+
description: "Gradle build variant"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
key: "android.keystore",
|
|
353
|
+
type: PATH,
|
|
354
|
+
scopes: PROJECT,
|
|
355
|
+
description: "Keystore a re-packed release APK is signed with"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
key: "android.keystorePassword",
|
|
359
|
+
type: STRING,
|
|
360
|
+
scopes: PROJECT,
|
|
361
|
+
sensitive: true,
|
|
362
|
+
description: "Keystore password, or an apksigner env: or file: reference"
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
key: "android.remote",
|
|
366
|
+
type: REMOTE,
|
|
367
|
+
scopes: PROJECT,
|
|
368
|
+
description: "Default remote backend for Android"
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
key: "metro.tunnel",
|
|
372
|
+
type: {
|
|
373
|
+
kind: "choice",
|
|
374
|
+
choices: TUNNEL_MODES
|
|
375
|
+
},
|
|
376
|
+
scopes: PROJECT,
|
|
377
|
+
default: "auto",
|
|
378
|
+
description: "How a remote device reaches Metro"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
key: "metro.ngrokUrl",
|
|
382
|
+
type: STRING,
|
|
383
|
+
scopes: PROJECT,
|
|
384
|
+
description: "Stable ngrok URL for the managed tunnel"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
key: "metro.publicUrl",
|
|
388
|
+
type: STRING,
|
|
389
|
+
scopes: PROJECT,
|
|
390
|
+
description: "Existing public Metro URL"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
key: "metro.warmupUrl.ios",
|
|
394
|
+
type: { kind: "bundle-url" },
|
|
395
|
+
scopes: PROJECT,
|
|
396
|
+
description: "Bundle URL `stim ios` prefetches to warm Metro"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
key: "metro.warmupUrl.android",
|
|
400
|
+
type: { kind: "bundle-url" },
|
|
401
|
+
scopes: PROJECT,
|
|
402
|
+
description: "Bundle URL `stim android` prefetches to warm Metro"
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
key: "worktree.exclude",
|
|
406
|
+
type: { kind: "strings" },
|
|
407
|
+
scopes: ["repo", "committed"],
|
|
408
|
+
committedAt: "repository",
|
|
409
|
+
description: "Ignored paths `worktree warm` skips"
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
key: "worktree.defaultBranch",
|
|
413
|
+
type: STRING,
|
|
414
|
+
scopes: ["repo", "committed"],
|
|
415
|
+
committedAt: "repository",
|
|
416
|
+
description: "Branch `worktree warm --refresh` expects the source checkout on"
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
key: "cache.provider",
|
|
420
|
+
type: STRING,
|
|
421
|
+
scopes: PROJECT,
|
|
422
|
+
description: "Second-tier cache provider module"
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
key: "cache.options",
|
|
426
|
+
type: OBJECT,
|
|
427
|
+
scopes: PROJECT,
|
|
428
|
+
description: "Options passed to the cache provider"
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
key: "iosSimulatorApp",
|
|
432
|
+
type: {
|
|
433
|
+
kind: "choice",
|
|
434
|
+
choices: IOS_SIMULATOR_APPS
|
|
435
|
+
},
|
|
436
|
+
scopes: MACHINE,
|
|
437
|
+
default: "xcode",
|
|
438
|
+
description: "App that displays an owned iOS simulator"
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
key: "concurrency.maxBuilds",
|
|
442
|
+
type: CAPACITY,
|
|
443
|
+
scopes: MACHINE,
|
|
444
|
+
default: 0,
|
|
445
|
+
env: "STIM_MAX_BUILDS",
|
|
446
|
+
description: "Concurrent native builds; 0 means no limit"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
key: "concurrency.maxDevices",
|
|
450
|
+
type: CAPACITY,
|
|
451
|
+
scopes: MACHINE,
|
|
452
|
+
default: 0,
|
|
453
|
+
env: "STIM_MAX_DEVICES",
|
|
454
|
+
description: "Booted owned devices; 0 means no limit"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
key: "pool.iosParkedMax",
|
|
458
|
+
type: PARKED_MAX,
|
|
459
|
+
scopes: MACHINE,
|
|
460
|
+
default: 3,
|
|
461
|
+
env: "STIM_POOL_IOS_PARKED_MAX",
|
|
462
|
+
scopedHomeValue: 0,
|
|
463
|
+
description: "Parked simulators kept for adoption; 0 turns parking off"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
key: "pool.androidParkedMax",
|
|
467
|
+
type: PARKED_MAX,
|
|
468
|
+
scopes: MACHINE,
|
|
469
|
+
default: 3,
|
|
470
|
+
env: "STIM_POOL_ANDROID_PARKED_MAX",
|
|
471
|
+
scopedHomeValue: 0,
|
|
472
|
+
description: "Parked emulators kept for adoption; 0 turns parking off"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
key: "caches.buildCache",
|
|
476
|
+
type: ABSOLUTE_PATH,
|
|
477
|
+
scopes: MACHINE,
|
|
478
|
+
env: "STIM_BUILD_CACHE",
|
|
479
|
+
description: "Absolute path of the shared build cache"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
key: "caches.metroCache",
|
|
483
|
+
type: ABSOLUTE_PATH,
|
|
484
|
+
scopes: MACHINE,
|
|
485
|
+
env: "STIM_METRO_CACHE",
|
|
486
|
+
description: "Absolute parent path of the Metro transform caches"
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
key: "tempDir",
|
|
490
|
+
type: ABSOLUTE_PATH,
|
|
491
|
+
scopes: MACHINE,
|
|
492
|
+
env: "STIM_TMPDIR",
|
|
493
|
+
description: "Absolute directory for large temporary copies"
|
|
494
|
+
}
|
|
495
|
+
];
|
|
496
|
+
const BY_KEY = new Map(SETTINGS.map((setting) => [setting.key, setting]));
|
|
497
|
+
function settingDefinition(key) {
|
|
498
|
+
return BY_KEY.get(key) ?? null;
|
|
499
|
+
}
|
|
500
|
+
function isLayeredSetting(setting) {
|
|
501
|
+
return setting.scopes.some((scope) => scope !== "machine");
|
|
502
|
+
}
|
|
503
|
+
const SETTING_GROUPS = [...new Set(SETTINGS.filter(isLayeredSetting).flatMap((setting) => setting.key.split(".").slice(0, -1).map((_, index, parts) => parts.slice(0, index + 1).join("."))))];
|
|
504
|
+
function isPlainObject$1(value) {
|
|
505
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
506
|
+
}
|
|
507
|
+
function bundleUrlAccepts(value, key) {
|
|
508
|
+
if (typeof value !== "string" || !/^(https?:\/\/|\/(?!\/))/.test(value) || /[\s\\#]/.test(value)) return false;
|
|
509
|
+
try {
|
|
510
|
+
const url = new URL(value, "http://localhost");
|
|
511
|
+
return /\.bundle\/*$/.test(url.pathname) && url.searchParams.get("platform") === key.split(".").at(-1);
|
|
512
|
+
} catch {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
function expectedShape(type) {
|
|
517
|
+
switch (type.kind) {
|
|
518
|
+
case "boolean": return "true or false";
|
|
519
|
+
case "string": return "a string";
|
|
520
|
+
case "path": return "a string path";
|
|
521
|
+
case "strings": return "an array of strings";
|
|
522
|
+
case "number": return "a number";
|
|
523
|
+
case "choice": return `one of: ${type.choices.join(", ")}`;
|
|
524
|
+
case "object": return "an object";
|
|
525
|
+
case "bundle-url": return "an HTTP(S) URL or /path ending in .bundle with a matching platform query and no fragment";
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function acceptsShape(setting, value) {
|
|
529
|
+
const { type } = setting;
|
|
530
|
+
switch (type.kind) {
|
|
531
|
+
case "boolean": return typeof value === "boolean";
|
|
532
|
+
case "string":
|
|
533
|
+
case "path": return typeof value === "string";
|
|
534
|
+
case "strings": return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
535
|
+
case "number": return typeof value === "number";
|
|
536
|
+
case "choice": return typeof value === "string" && type.choices.includes(value);
|
|
537
|
+
case "object": return isPlainObject$1(value);
|
|
538
|
+
case "bundle-url": return bundleUrlAccepts(value, setting.key);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
function numberBounds(type) {
|
|
542
|
+
const noun = type.integer ? "a whole number" : "a number";
|
|
543
|
+
if (type.minimum !== void 0 && type.maximum !== void 0) return `${noun} from ${type.minimum} through ${type.maximum}`;
|
|
544
|
+
if (type.minimum !== void 0) return `${noun}, ${type.minimum} or more`;
|
|
545
|
+
return noun;
|
|
546
|
+
}
|
|
547
|
+
function settingValueError(setting, value) {
|
|
548
|
+
const { type } = setting;
|
|
549
|
+
if (!acceptsShape(setting, value)) return type.kind === "number" ? numberBounds(type) : expectedShape(type);
|
|
550
|
+
if (type.kind === "number") {
|
|
551
|
+
const number = value;
|
|
552
|
+
if (!Number.isFinite(number) || type.integer && !Number.isSafeInteger(number) || type.minimum !== void 0 && number < type.minimum || type.maximum !== void 0 && number > type.maximum) return numberBounds(type);
|
|
553
|
+
}
|
|
554
|
+
if (type.kind === "path") {
|
|
555
|
+
const path = value;
|
|
556
|
+
if (type.absolute && !isAbsolute$1(path)) return "an absolute path";
|
|
557
|
+
if (type.relative && (path.trim() === "" || isAbsolute$1(path))) return "a relative path inside the app directory";
|
|
558
|
+
}
|
|
559
|
+
if (type.kind === "string" && type.pattern && !new RegExp(type.pattern).test(value)) return type.patternHelp ?? `a string matching ${type.pattern}`;
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
const SENSITIVE_REFERENCE = /^(env|file):\S/;
|
|
563
|
+
function isSensitiveReference(value) {
|
|
564
|
+
return typeof value === "string" && SENSITIVE_REFERENCE.test(value);
|
|
565
|
+
}
|
|
566
|
+
//#endregion
|
|
180
567
|
//#region src/workspace/settings.ts
|
|
181
568
|
function isPlainObject(v) {
|
|
182
569
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
@@ -190,77 +577,10 @@ function mergeSettingsLayers(layers) {
|
|
|
190
577
|
}
|
|
191
578
|
return out;
|
|
192
579
|
}
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
expected: "true or false",
|
|
196
|
-
accepts: (value) => typeof value === "boolean"
|
|
197
|
-
},
|
|
198
|
-
string: {
|
|
199
|
-
expected: "a string",
|
|
200
|
-
accepts: (value) => typeof value === "string"
|
|
201
|
-
},
|
|
202
|
-
path: {
|
|
203
|
-
expected: "a string path",
|
|
204
|
-
accepts: (value) => typeof value === "string"
|
|
205
|
-
},
|
|
206
|
-
strings: {
|
|
207
|
-
expected: "an array of strings",
|
|
208
|
-
accepts: (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string")
|
|
209
|
-
},
|
|
210
|
-
number: {
|
|
211
|
-
expected: "a number",
|
|
212
|
-
accepts: (value) => typeof value === "number"
|
|
213
|
-
},
|
|
214
|
-
object: {
|
|
215
|
-
expected: "an object",
|
|
216
|
-
accepts: isPlainObject
|
|
217
|
-
},
|
|
218
|
-
"bundle-url": {
|
|
219
|
-
expected: "an HTTP(S) URL or /path ending in .bundle with a matching platform query and no fragment",
|
|
220
|
-
accepts: (value, key) => {
|
|
221
|
-
if (typeof value !== "string" || !/^(https?:\/\/|\/(?!\/))/.test(value) || /[\s\\#]/.test(value)) return false;
|
|
222
|
-
try {
|
|
223
|
-
const url = new URL(value, "http://localhost");
|
|
224
|
-
return /\.bundle\/*$/.test(url.pathname) && url.searchParams.get("platform") === key.split(".").at(-1);
|
|
225
|
-
} catch {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
const SETTING_SHAPES = {
|
|
232
|
-
...OPTIMIZATION_SHAPES,
|
|
233
|
-
"ios.deviceType": "string",
|
|
234
|
-
"ios.runtime": "string",
|
|
235
|
-
"ios.configuration": "string",
|
|
236
|
-
"ios.remote": "string",
|
|
237
|
-
"ios.simslimProfile": "path",
|
|
238
|
-
"ios.signingIdentity": "string",
|
|
239
|
-
"ios.signingIdentitySha1": "string",
|
|
240
|
-
"ios.lanHost": "string",
|
|
241
|
-
"android.systemImage": "string",
|
|
242
|
-
"android.dataPartitionSizeGb": "number",
|
|
243
|
-
"android.avdConfigFile": "path",
|
|
244
|
-
"android.avdConfig": "object",
|
|
245
|
-
"android.variant": "string",
|
|
246
|
-
"android.keystore": "path",
|
|
247
|
-
"android.keystorePassword": "string",
|
|
248
|
-
"android.remote": "string",
|
|
249
|
-
"metro.tunnel": "string",
|
|
250
|
-
"metro.ngrokUrl": "string",
|
|
251
|
-
"metro.publicUrl": "string",
|
|
252
|
-
"metro.warmupUrl": "object",
|
|
253
|
-
"metro.warmupUrl.ios": "bundle-url",
|
|
254
|
-
"metro.warmupUrl.android": "bundle-url",
|
|
255
|
-
"worktree.exclude": "strings",
|
|
256
|
-
"worktree.defaultBranch": "string",
|
|
257
|
-
"cache.provider": "string",
|
|
258
|
-
"cache.options": "object",
|
|
259
|
-
caches: "strings"
|
|
260
|
-
};
|
|
261
|
-
const KNOWN_SETTINGS = new Set(Object.keys(SETTING_SHAPES));
|
|
580
|
+
const LAYERED_SETTINGS = SETTINGS.filter(isLayeredSetting);
|
|
581
|
+
const KNOWN_SETTINGS = /* @__PURE__ */ new Set([...LAYERED_SETTINGS.map((setting) => setting.key), ...SETTING_GROUPS]);
|
|
262
582
|
const SETTINGS_WITH_RESOLVE_TIME_FALLBACK = /* @__PURE__ */ new Set(["optimizations.android.casToolchain"]);
|
|
263
|
-
const PATH_SETTINGS = Object.freeze(
|
|
583
|
+
const PATH_SETTINGS = Object.freeze(LAYERED_SETTINGS.filter((setting) => setting.type.kind === "path").map((setting) => setting.key));
|
|
264
584
|
function settingValueAt(settings, path) {
|
|
265
585
|
let node = settings;
|
|
266
586
|
for (const segment of path.split(".")) {
|
|
@@ -271,20 +591,25 @@ function settingValueAt(settings, path) {
|
|
|
271
591
|
}
|
|
272
592
|
function settingShapeErrors(settings) {
|
|
273
593
|
const errors = [];
|
|
274
|
-
for (const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
594
|
+
for (const group of SETTING_GROUPS) {
|
|
595
|
+
const value = settingValueAt(settings, group);
|
|
596
|
+
if (value === void 0 || isPlainObject(value)) continue;
|
|
597
|
+
errors.push(`Invalid ${group} setting ${JSON.stringify(value)}. Expected an object.`);
|
|
598
|
+
}
|
|
599
|
+
for (const setting of LAYERED_SETTINGS) {
|
|
600
|
+
if (SETTINGS_WITH_RESOLVE_TIME_FALLBACK.has(setting.key)) continue;
|
|
601
|
+
const value = settingValueAt(settings, setting.key);
|
|
602
|
+
if (value === void 0 || acceptsShape(setting, value)) continue;
|
|
603
|
+
errors.push(`Invalid ${setting.key} setting ${JSON.stringify(value)}. Expected ${expectedShape(setting.type)}.`);
|
|
281
604
|
}
|
|
282
605
|
return errors;
|
|
283
606
|
}
|
|
284
607
|
const SETTING_SHAPE_REMEDY = "Run `stim guide settings` for the shape each setting takes.";
|
|
608
|
+
const MIN_ANDROID_DATA_PARTITION_SIZE_GB = 6;
|
|
609
|
+
const DEFAULT_ANDROID_DATA_PARTITION_SIZE_GB = 8;
|
|
285
610
|
const MAX_ANDROID_DATA_PARTITION_SIZE_GB = 16384;
|
|
286
611
|
function validateAndroidDataPartitionSizeGb(raw) {
|
|
287
|
-
if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw <
|
|
612
|
+
if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw < MIN_ANDROID_DATA_PARTITION_SIZE_GB || raw > MAX_ANDROID_DATA_PARTITION_SIZE_GB) throw new Error(`Invalid android.dataPartitionSizeGb setting ${JSON.stringify(raw)}. Expected an integer from ${MIN_ANDROID_DATA_PARTITION_SIZE_GB} through ${MAX_ANDROID_DATA_PARTITION_SIZE_GB} GiB.`);
|
|
288
613
|
return raw;
|
|
289
614
|
}
|
|
290
615
|
function androidDataPartitionSizeBytes(sizeGb) {
|
|
@@ -296,7 +621,7 @@ function androidDataPartitionSizeGbRaw(settings) {
|
|
|
296
621
|
}
|
|
297
622
|
function androidDataPartitionSizeGbSetting(settings) {
|
|
298
623
|
const raw = androidDataPartitionSizeGbRaw(settings);
|
|
299
|
-
if (raw === void 0) return
|
|
624
|
+
if (raw === void 0) return DEFAULT_ANDROID_DATA_PARTITION_SIZE_GB;
|
|
300
625
|
return validateAndroidDataPartitionSizeGb(raw);
|
|
301
626
|
}
|
|
302
627
|
function androidDataPartitionSizeGbSettingError(settings) {
|
|
@@ -425,18 +750,18 @@ function parseAndroidAvdConfigIni(contents) {
|
|
|
425
750
|
return entries;
|
|
426
751
|
}
|
|
427
752
|
function pathEscapesRoot(root, path) {
|
|
428
|
-
const child = relative
|
|
429
|
-
return child === ".." || child.startsWith(`..${sep
|
|
753
|
+
const child = relative(root, path);
|
|
754
|
+
return child === ".." || child.startsWith(`..${sep}`) || isAbsolute(child);
|
|
430
755
|
}
|
|
431
756
|
function androidAvdConfigSetting(settings, settingsRoot) {
|
|
432
757
|
if (!isPlainObject(settings) || !isPlainObject(settings.android)) return {};
|
|
433
758
|
const android = settings.android;
|
|
434
759
|
let entries = {};
|
|
435
760
|
if ("avdConfigFile" in android) {
|
|
436
|
-
if (typeof android.avdConfigFile !== "string" || !android.avdConfigFile.trim() || android.avdConfigFile !== android.avdConfigFile.trim() || /[\r\n\0]/.test(android.avdConfigFile) || isAbsolute
|
|
761
|
+
if (typeof android.avdConfigFile !== "string" || !android.avdConfigFile.trim() || android.avdConfigFile !== android.avdConfigFile.trim() || /[\r\n\0]/.test(android.avdConfigFile) || isAbsolute(android.avdConfigFile)) throw new Error("Invalid android.avdConfigFile setting. Expected a relative file path inside the app directory.");
|
|
437
762
|
try {
|
|
438
763
|
const root = realpathSync(settingsRoot);
|
|
439
|
-
const candidate = resolve
|
|
764
|
+
const candidate = resolve(root, android.avdConfigFile);
|
|
440
765
|
if (pathEscapesRoot(root, candidate)) throw new Error("path escapes the settings root");
|
|
441
766
|
const path = realpathSync(candidate);
|
|
442
767
|
if (pathEscapesRoot(root, path)) throw new Error("symlink target escapes the settings root");
|
|
@@ -470,10 +795,10 @@ function androidAvdConfigSettingError(settings, projectPath) {
|
|
|
470
795
|
function iosSimSlimProfileSetting(settings, settingsRoot) {
|
|
471
796
|
if (!isPlainObject(settings) || !isPlainObject(settings.ios) || !("simslimProfile" in settings.ios)) return null;
|
|
472
797
|
const value = settings.ios.simslimProfile;
|
|
473
|
-
if (typeof value !== "string" || !value.trim() || value !== value.trim() || /[\r\n\0]/.test(value) || isAbsolute
|
|
798
|
+
if (typeof value !== "string" || !value.trim() || value !== value.trim() || /[\r\n\0]/.test(value) || isAbsolute(value)) throw new Error("Invalid ios.simslimProfile setting. Expected a relative JSON file path inside the app directory.");
|
|
474
799
|
try {
|
|
475
800
|
const root = realpathSync(settingsRoot);
|
|
476
|
-
const candidate = resolve
|
|
801
|
+
const candidate = resolve(root, value);
|
|
477
802
|
if (pathEscapesRoot(root, candidate)) throw new Error("path escapes the settings root");
|
|
478
803
|
const path = realpathSync(candidate);
|
|
479
804
|
if (pathEscapesRoot(root, path)) throw new Error("symlink target escapes the settings root");
|
|
@@ -526,6 +851,7 @@ function unknownSettingKeys(settings, prefix = "") {
|
|
|
526
851
|
const unknown = [];
|
|
527
852
|
for (const [key, value] of Object.entries(settings)) {
|
|
528
853
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
854
|
+
if (path === "$schema") continue;
|
|
529
855
|
if (KNOWN_SETTINGS.has(path) && (!isPlainObject(value) || ![...KNOWN_SETTINGS].some((k) => k.startsWith(`${path}.`)))) continue;
|
|
530
856
|
if (isPlainObject(value) && [...KNOWN_SETTINGS].some((k) => k.startsWith(`${path}.`))) {
|
|
531
857
|
unknown.push(...unknownSettingKeys(value, path));
|
|
@@ -537,7 +863,7 @@ function unknownSettingKeys(settings, prefix = "") {
|
|
|
537
863
|
}
|
|
538
864
|
function readCommittedSettings(directory) {
|
|
539
865
|
if (!directory) return {};
|
|
540
|
-
const p = join
|
|
866
|
+
const p = join(directory, ".stim.json");
|
|
541
867
|
if (!existsSync(p)) return {};
|
|
542
868
|
try {
|
|
543
869
|
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
@@ -560,7 +886,7 @@ function settingsLayers({ projectPath, gitCommonDir, repoRoot }) {
|
|
|
560
886
|
settings: getRepoSettings(gitCommonDir)
|
|
561
887
|
} : null,
|
|
562
888
|
committedDir ? {
|
|
563
|
-
file: join
|
|
889
|
+
file: join(committedDir, ".stim.json"),
|
|
564
890
|
settings: readCommittedSettings(committedDir)
|
|
565
891
|
} : null,
|
|
566
892
|
machine?.optimizations === void 0 ? null : {
|
|
@@ -617,23 +943,23 @@ function resolveCacheProviderConfig({ projectPath, gitCommonDir, repoRoot }) {
|
|
|
617
943
|
baseDir: projectPath ?? null
|
|
618
944
|
}
|
|
619
945
|
];
|
|
620
|
-
|
|
621
|
-
let baseDir = null;
|
|
622
|
-
for (const layer of layers) {
|
|
946
|
+
const references = layers.map((layer) => {
|
|
623
947
|
const reference = cacheBlock(layer.settings)?.provider;
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
const options = mergeSettingsLayers(layers.map((layer) => {
|
|
631
|
-
const block = cacheBlock(layer.settings)?.options;
|
|
632
|
-
return isPlainObject(block) ? block : null;
|
|
633
|
-
}));
|
|
948
|
+
return typeof reference === "string" && reference.trim() !== "" ? reference.trim() : null;
|
|
949
|
+
});
|
|
950
|
+
const selected = layers.findIndex((layer, index) => references[index] !== null && layer.baseDir !== null);
|
|
951
|
+
if (selected === -1) return null;
|
|
952
|
+
const provider = references[selected];
|
|
953
|
+
const baseDir = layers[selected].baseDir;
|
|
634
954
|
return {
|
|
635
955
|
provider,
|
|
636
|
-
options,
|
|
956
|
+
options: mergeSettingsLayers(layers.map((layer, index) => {
|
|
957
|
+
const namesProvider = references[index] === provider && layer.baseDir === baseDir;
|
|
958
|
+
const overridesAbove = index < selected && references[index] === null;
|
|
959
|
+
if (!namesProvider && !overridesAbove) return null;
|
|
960
|
+
const block = cacheBlock(layer.settings)?.options;
|
|
961
|
+
return isPlainObject(block) ? block : null;
|
|
962
|
+
})),
|
|
637
963
|
baseDir
|
|
638
964
|
};
|
|
639
965
|
}
|
|
@@ -644,7 +970,6 @@ function cacheProviderSettingError(settings) {
|
|
|
644
970
|
if ("options" in block && !isPlainObject(block.options)) return `Invalid cache.options setting ${JSON.stringify(block.options)}. Expected an object.`;
|
|
645
971
|
return null;
|
|
646
972
|
}
|
|
647
|
-
const REMOTE_DEVICE_BACKENDS = ["proxy", "eas"];
|
|
648
973
|
function remoteIosSetting(settings) {
|
|
649
974
|
return remoteSetting(settings, "ios");
|
|
650
975
|
}
|
|
@@ -657,14 +982,6 @@ function remoteSetting(settings, platform) {
|
|
|
657
982
|
const remote = block.remote;
|
|
658
983
|
return typeof remote === "string" && REMOTE_DEVICE_BACKENDS.includes(remote) ? remote : null;
|
|
659
984
|
}
|
|
660
|
-
function remoteDeviceSettingError(settings) {
|
|
661
|
-
for (const platform of ["ios", "android"]) {
|
|
662
|
-
const block = settings[platform];
|
|
663
|
-
if (!isPlainObject(block) || !("remote" in block)) continue;
|
|
664
|
-
if (remoteSetting(settings, platform) === null) return `Invalid ${platform}.remote setting ${JSON.stringify(block.remote)}. Expected one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}.`;
|
|
665
|
-
}
|
|
666
|
-
return null;
|
|
667
|
-
}
|
|
668
985
|
function tunnelModeSetting(settings) {
|
|
669
986
|
const block = settings.metro;
|
|
670
987
|
if (typeof block !== "object" || block === null) return null;
|
|
@@ -673,12 +990,7 @@ function tunnelModeSetting(settings) {
|
|
|
673
990
|
}
|
|
674
991
|
function metroTunnelSettingError(settings) {
|
|
675
992
|
const block = settings.metro;
|
|
676
|
-
if (!isPlainObject(block)) return null;
|
|
677
|
-
if ("tunnel" in block) {
|
|
678
|
-
const mode = block.tunnel;
|
|
679
|
-
if (typeof mode !== "string" || !TUNNEL_MODES.includes(mode)) return `Invalid metro.tunnel setting ${JSON.stringify(mode)}. Expected one of: ${TUNNEL_MODES.join(", ")}.`;
|
|
680
|
-
}
|
|
681
|
-
if (!("ngrokUrl" in block)) return null;
|
|
993
|
+
if (!isPlainObject(block) || !("ngrokUrl" in block)) return null;
|
|
682
994
|
if (block.tunnel !== "ngrok") return "metro.ngrokUrl requires metro.tunnel to be \"ngrok\".";
|
|
683
995
|
if (normalizedHttpsUrl(block.ngrokUrl) === null) return "metro.ngrokUrl must be a valid HTTPS URL.";
|
|
684
996
|
return null;
|
|
@@ -708,4 +1020,4 @@ function normalizedHttpsUrl(raw) {
|
|
|
708
1020
|
}
|
|
709
1021
|
}
|
|
710
1022
|
//#endregion
|
|
711
|
-
export {
|
|
1023
|
+
export { settingFile as A, isSensitiveReference as B, projectOptimizations as C, remoteIosSetting as D, remoteAndroidSetting as E, unknownSettingKeys as F, planMetroReach as G, settingValueError as H, IOS_SIMULATOR_APPS as I, optimizationBuildProfile as J, artifactCachePolicy as K, REMOTE_DEVICE_BACKENDS as L, settingShapeErrors as M, settingsLayers as N, resolveCacheProviderConfig as O, tunnelModeSetting as P, SETTINGS as R, projectMetroSharedCache as S, readCommittedSettings as T, PUBLIC_METRO_ENV as U, settingDefinition as V, detectProviders as W, resolveOptimizations as Y, iosSimSlimProfileSetting as _, androidAvdConfigSetting as a, metroWarmupUrlSetting as b, androidDataPartitionSizeGbSetting as c, iosLanHostSetting as d, iosLanHostSettingError as f, iosSigningIdentitySha1SettingError as g, iosSigningIdentitySha1Setting as h, SETTING_SHAPE_REMEDY as i, settingOrigin as j, resolveSettings as k, androidDataPartitionSizeGbSettingError as l, iosSigningIdentitySettingError as m, PATH_SETTINGS as n, androidAvdConfigSettingError as o, iosSigningIdentitySetting as p, compilerCacheFallbackMessage as q, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as r, androidDataPartitionSizeBytes as s, ANDROID_AVD_CONFIG_HELP as t, cacheProviderSettingError as u, mergeSettingsLayers as v, publicUrlSetting as w, ngrokUrlSetting as x, metroTunnelSettingError as y, SETTING_SCOPES as z };
|