@stim-cli/core 1.20.0 → 1.20.1
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/{core-Btea8jlo.mjs → core-CzCQ9yWY.mjs} +48 -3
- package/dist/index.mjs +1 -1
- package/dist/state.mjs +101 -88
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import fs, { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpa
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path, { basename, dirname, join } from "node:path";
|
|
5
5
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
6
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
7
|
import { spawnSync } from "node:child_process";
|
|
7
8
|
import { connect, createServer, isIP } from "node:net";
|
|
8
9
|
//#region dir-lock.ts
|
|
@@ -152,6 +153,48 @@ function withDirLock(lockPath, fn, { waitMs = DEFAULT_LOCK_WAIT_MS, pollMs = DEF
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
//#endregion
|
|
156
|
+
//#region state/json-file.ts
|
|
157
|
+
const readScope = new AsyncLocalStorage();
|
|
158
|
+
/**
|
|
159
|
+
* Runs `fn` with each state file read from disk at most once: inside it, including after an `await`, `readStateFile`
|
|
160
|
+
* returns the text of the first read of that path, and a path found missing stays missing. Callers still parse every time, so no two
|
|
161
|
+
* share a mutable object. Only for computations that write none of the files they read.
|
|
162
|
+
*/
|
|
163
|
+
function withStateReadCache(fn) {
|
|
164
|
+
return readScope.run(/* @__PURE__ */ new Map(), fn);
|
|
165
|
+
}
|
|
166
|
+
function readStateFile(path) {
|
|
167
|
+
const cache = readScope.getStore();
|
|
168
|
+
if (!cache) return readFileSync(path, "utf-8");
|
|
169
|
+
const cached = cache.get(path);
|
|
170
|
+
if (cached) {
|
|
171
|
+
if ("missing" in cached) throw cached.missing;
|
|
172
|
+
return cached.text;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const text = readFileSync(path, "utf-8");
|
|
176
|
+
cache.set(path, { text });
|
|
177
|
+
return text;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (error.code === "ENOENT") cache.set(path, { missing: error });
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function readJsonFile(path) {
|
|
184
|
+
return JSON.parse(readStateFile(path));
|
|
185
|
+
}
|
|
186
|
+
function isJsonObject(value) {
|
|
187
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
188
|
+
}
|
|
189
|
+
function readJsonObject(path) {
|
|
190
|
+
try {
|
|
191
|
+
const value = readJsonFile(path);
|
|
192
|
+
return isJsonObject(value) ? value : null;
|
|
193
|
+
} catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
155
198
|
//#region macos-resources.ts
|
|
156
199
|
/** Whether a resource destination is a contained, non-empty path under Contents/Resources. */
|
|
157
200
|
function validMacosResourceDestination(value) {
|
|
@@ -480,7 +523,9 @@ function logSize(file) {
|
|
|
480
523
|
}
|
|
481
524
|
function cachePathSetting(key) {
|
|
482
525
|
try {
|
|
483
|
-
const
|
|
526
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(configDir(), "config.json"), "utf-8"));
|
|
527
|
+
const caches = isJsonObject(parsed) ? parsed.caches : void 0;
|
|
528
|
+
const value = isJsonObject(caches) ? caches[key] : void 0;
|
|
484
529
|
return typeof value === "string" && path.isAbsolute(value) ? value : null;
|
|
485
530
|
} catch {
|
|
486
531
|
return null;
|
|
@@ -557,7 +602,7 @@ function readCacheManifest(file) {
|
|
|
557
602
|
const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
558
603
|
return {
|
|
559
604
|
version: 1,
|
|
560
|
-
caches: Array.isArray(parsed
|
|
605
|
+
caches: (isJsonObject(parsed) && Array.isArray(parsed.caches) ? parsed.caches : []).filter(isJsonObject)
|
|
561
606
|
};
|
|
562
607
|
} catch {
|
|
563
608
|
return {
|
|
@@ -612,4 +657,4 @@ function matchesCache(cache, match) {
|
|
|
612
657
|
return match.layout === void 0 || cache.layout === match.layout;
|
|
613
658
|
}
|
|
614
659
|
//#endregion
|
|
615
|
-
export { storeArtifact as A, workspaceSlug as C, compiledHelper as D, createMetroGateway as E, withDirLock as M, artifactIn as O, workspaceName as S, createMetroBridge as T, sharedStoreRoot as _, buildCacheRoot as a, workspaceId as b, cachePathSetting as c, hostSimulatorArch as d, metroCacheRoot as f, rotatedLogPath as g, rotateLog as h, buildCacheKey as i, validMacosResourceDestination as j, resolveArtifact as k, configDir as l, registerCache as m, METRO_NAMED_CACHE_LAYOUT as n, cacheManifestLockPath as o, readCacheManifest as p, STORE_ROOT_TAG as r, cacheNameSegment as s, LOG_ROTATE_BYTES as t, ensurePrivateDir as u, tagSharedStore as v, workspaceStateDir as w, workspaceLogDir as x, updateCacheManifest as y };
|
|
660
|
+
export { storeArtifact as A, workspaceSlug as C, compiledHelper as D, createMetroGateway as E, readStateFile as F, withStateReadCache as I, withDirLock as L, isJsonObject as M, readJsonFile as N, artifactIn as O, readJsonObject as P, workspaceName as S, createMetroBridge as T, sharedStoreRoot as _, buildCacheRoot as a, workspaceId as b, cachePathSetting as c, hostSimulatorArch as d, metroCacheRoot as f, rotatedLogPath as g, rotateLog as h, buildCacheKey as i, validMacosResourceDestination as j, resolveArtifact as k, configDir as l, registerCache as m, METRO_NAMED_CACHE_LAYOUT as n, cacheManifestLockPath as o, readCacheManifest as p, STORE_ROOT_TAG as r, cacheNameSegment as s, LOG_ROTATE_BYTES as t, ensurePrivateDir as u, tagSharedStore as v, workspaceStateDir as w, workspaceLogDir as x, updateCacheManifest as y };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { S as quotedPath } from "./ownership-claim-O31Y5iIb.mjs";
|
|
2
|
-
import { A as storeArtifact, C as workspaceSlug, D as compiledHelper, E as createMetroGateway,
|
|
2
|
+
import { A as storeArtifact, C as workspaceSlug, D as compiledHelper, E as createMetroGateway, L as withDirLock, O as artifactIn, S as workspaceName, T as createMetroBridge, _ as sharedStoreRoot, a as buildCacheRoot, b as workspaceId, c as cachePathSetting, d as hostSimulatorArch, f as metroCacheRoot, g as rotatedLogPath, h as rotateLog, i as buildCacheKey, j as validMacosResourceDestination, k as resolveArtifact, l as configDir, m as registerCache, n as METRO_NAMED_CACHE_LAYOUT, o as cacheManifestLockPath, p as readCacheManifest, r as STORE_ROOT_TAG, s as cacheNameSegment, t as LOG_ROTATE_BYTES, u as ensurePrivateDir, v as tagSharedStore, w as workspaceStateDir, x as workspaceLogDir, y as updateCacheManifest } from "./core-CzCQ9yWY.mjs";
|
|
3
3
|
export { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, STORE_ROOT_TAG, artifactIn, buildCacheKey, buildCacheRoot, cacheManifestLockPath, cacheNameSegment, cachePathSetting, compiledHelper, configDir, createMetroBridge, createMetroGateway, ensurePrivateDir, hostSimulatorArch, metroCacheRoot, quotedPath, readCacheManifest, registerCache, resolveArtifact, rotateLog, rotatedLogPath, sharedStoreRoot, storeArtifact, tagSharedStore, updateCacheManifest, validMacosResourceDestination, withDirLock, workspaceId, workspaceLogDir, workspaceName, workspaceSlug, workspaceStateDir };
|
package/dist/state.mjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { _ as releaseClaim, f as isClaimRefusal, g as readClaimSet, x as tryAcquireClaim } from "./ownership-claim-O31Y5iIb.mjs";
|
|
2
2
|
import { inspectProcessIdentity } from "./process-identity.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { F as readStateFile, I as withStateReadCache, L as withDirLock, M as isJsonObject, N as readJsonFile, P as readJsonObject, S as workspaceName, g as rotatedLogPath, h as rotateLog, l as configDir, t as LOG_ROTATE_BYTES, u as ensurePrivateDir, w as workspaceStateDir } from "./core-CzCQ9yWY.mjs";
|
|
4
4
|
import { appendFileSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
5
5
|
import { availableParallelism, homedir, loadavg } from "node:os";
|
|
6
6
|
import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
7
7
|
import { createHash, randomBytes } from "node:crypto";
|
|
8
8
|
import { isIP } from "node:net";
|
|
9
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
9
|
import { StringDecoder } from "node:string_decoder";
|
|
11
10
|
//#region state/agent-actions.ts
|
|
12
11
|
const EVENTS_VERSION = 1;
|
|
@@ -307,48 +306,6 @@ function createAgentActionReader({ sessionsDirs, targets: resolveTargets, sinceT
|
|
|
307
306
|
};
|
|
308
307
|
}
|
|
309
308
|
//#endregion
|
|
310
|
-
//#region state/json-file.ts
|
|
311
|
-
const readScope = new AsyncLocalStorage();
|
|
312
|
-
/**
|
|
313
|
-
* Runs `fn` with each state file read from disk at most once: inside it, including after an `await`, `readStateFile`
|
|
314
|
-
* returns the text of the first read of that path, and a path found missing stays missing. Callers still parse every time, so no two
|
|
315
|
-
* share a mutable object. Only for computations that write none of the files they read.
|
|
316
|
-
*/
|
|
317
|
-
function withStateReadCache(fn) {
|
|
318
|
-
return readScope.run(/* @__PURE__ */ new Map(), fn);
|
|
319
|
-
}
|
|
320
|
-
function readStateFile(path) {
|
|
321
|
-
const cache = readScope.getStore();
|
|
322
|
-
if (!cache) return readFileSync(path, "utf-8");
|
|
323
|
-
const cached = cache.get(path);
|
|
324
|
-
if (cached) {
|
|
325
|
-
if ("missing" in cached) throw cached.missing;
|
|
326
|
-
return cached.text;
|
|
327
|
-
}
|
|
328
|
-
try {
|
|
329
|
-
const text = readFileSync(path, "utf-8");
|
|
330
|
-
cache.set(path, { text });
|
|
331
|
-
return text;
|
|
332
|
-
} catch (error) {
|
|
333
|
-
if (error.code === "ENOENT") cache.set(path, { missing: error });
|
|
334
|
-
throw error;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
function readJsonFile(path) {
|
|
338
|
-
return JSON.parse(readStateFile(path));
|
|
339
|
-
}
|
|
340
|
-
function isJsonObject(value) {
|
|
341
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
342
|
-
}
|
|
343
|
-
function readJsonObject(path) {
|
|
344
|
-
try {
|
|
345
|
-
const value = readJsonFile(path);
|
|
346
|
-
return isJsonObject(value) ? value : null;
|
|
347
|
-
} catch {
|
|
348
|
-
return null;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
//#endregion
|
|
352
309
|
//#region state/agent-device-usage.ts
|
|
353
310
|
function agentDeviceUsageFile() {
|
|
354
311
|
return join(configDir(), "agent-device-usage.json");
|
|
@@ -403,8 +360,17 @@ function swiftpmCacheUsageFile() {
|
|
|
403
360
|
}
|
|
404
361
|
function readSwiftpmCacheUsage() {
|
|
405
362
|
const value = readJsonObject(swiftpmCacheUsageFile());
|
|
406
|
-
if (!value
|
|
407
|
-
|
|
363
|
+
if (!value) return null;
|
|
364
|
+
const { version, measuredAt, dir, present, bytes, complete } = value;
|
|
365
|
+
if (version !== 1 || typeof measuredAt !== "string" || !Number.isFinite(Date.parse(measuredAt)) || typeof dir !== "string" || typeof present !== "boolean" || typeof complete !== "boolean" || !(bytes === null || typeof bytes === "number" && Number.isFinite(bytes) && bytes >= 0)) return null;
|
|
366
|
+
return {
|
|
367
|
+
version,
|
|
368
|
+
measuredAt,
|
|
369
|
+
dir,
|
|
370
|
+
present,
|
|
371
|
+
bytes,
|
|
372
|
+
complete
|
|
373
|
+
};
|
|
408
374
|
}
|
|
409
375
|
//#endregion
|
|
410
376
|
//#region state/paths.ts
|
|
@@ -802,23 +768,47 @@ function parseHostedMacosChoice(value) {
|
|
|
802
768
|
};
|
|
803
769
|
}
|
|
804
770
|
function parseHostedMacosDevice(value) {
|
|
805
|
-
if (!isJsonObject(value) || !
|
|
771
|
+
if (!isJsonObject(value) || !hostedMacosAppSlot(value.appSlot) || Object.keys(value).some((key) => ![
|
|
806
772
|
"architecture",
|
|
807
773
|
"macosVersion",
|
|
808
774
|
"appSlot"
|
|
809
775
|
].includes(key))) return null;
|
|
810
|
-
|
|
776
|
+
const choice = parseHostedMacosChoice(value);
|
|
777
|
+
return choice && {
|
|
778
|
+
...choice,
|
|
779
|
+
appSlot: value.appSlot
|
|
780
|
+
};
|
|
811
781
|
}
|
|
812
782
|
const AGENT_PATH = /^\/device-host\/agent\/[a-f0-9-]{36}\/$/;
|
|
813
783
|
const LEASE_NAME = /^[A-Za-z0-9._-]{1,128}$/;
|
|
814
784
|
const LEASE_DEVICE_KEY = /^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)+@[1-9][0-9]{0,9}$/;
|
|
785
|
+
function leaseName(value) {
|
|
786
|
+
return typeof value === "string" && LEASE_NAME.test(value);
|
|
787
|
+
}
|
|
815
788
|
function parseHostedAgentLease(value) {
|
|
816
|
-
if (!isJsonObject(value)
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
789
|
+
if (!isJsonObject(value)) return null;
|
|
790
|
+
const { tenant, runId, clientId, deviceKey, backend } = value;
|
|
791
|
+
if (Object.keys(value).length !== (backend === "ios-instance" || backend === "android-instance" ? 5 : 4) || !leaseName(tenant) || !leaseName(runId) || !leaseName(clientId) || typeof deviceKey !== "string") return null;
|
|
792
|
+
if (backend === "ios-instance") return /^ios:mobile:[a-fA-F0-9-]{36}$/.test(deviceKey) ? {
|
|
793
|
+
tenant,
|
|
794
|
+
runId,
|
|
795
|
+
clientId,
|
|
796
|
+
deviceKey,
|
|
797
|
+
backend
|
|
798
|
+
} : null;
|
|
799
|
+
if (backend === "android-instance") return /^android:mobile:emulator-[0-9]+$/.test(deviceKey) ? {
|
|
800
|
+
tenant,
|
|
801
|
+
runId,
|
|
802
|
+
clientId,
|
|
803
|
+
deviceKey,
|
|
804
|
+
backend
|
|
805
|
+
} : null;
|
|
806
|
+
return backend === void 0 && LEASE_DEVICE_KEY.test(deviceKey) ? {
|
|
807
|
+
tenant,
|
|
808
|
+
runId,
|
|
809
|
+
clientId,
|
|
810
|
+
deviceKey
|
|
811
|
+
} : null;
|
|
822
812
|
}
|
|
823
813
|
/** A grant naming a driver this client does not know is not usable; it parses as null. */
|
|
824
814
|
function parseHostedAgentGrant(value) {
|
|
@@ -1010,7 +1000,7 @@ const SETTINGS = [
|
|
|
1010
1000
|
key: "ios.scheme",
|
|
1011
1001
|
type: STRING,
|
|
1012
1002
|
scopes: ["workspace", "committed"],
|
|
1013
|
-
description: "Shared Xcode scheme to build when the workspace has several"
|
|
1003
|
+
description: "Shared Xcode scheme to build when the workspace has several; the --scheme flag overrides it"
|
|
1014
1004
|
},
|
|
1015
1005
|
{
|
|
1016
1006
|
key: "ios.remote",
|
|
@@ -2062,16 +2052,19 @@ function liveNativeBuilds() {
|
|
|
2062
2052
|
for (const name of names) {
|
|
2063
2053
|
let active;
|
|
2064
2054
|
try {
|
|
2065
|
-
|
|
2055
|
+
const state = JSON.parse(readFileSync(join(dir, name, "state.json"), "utf8"));
|
|
2056
|
+
active = isJsonObject(state) ? state.activeBuild : void 0;
|
|
2066
2057
|
} catch {
|
|
2067
2058
|
continue;
|
|
2068
2059
|
}
|
|
2069
|
-
if (!active
|
|
2060
|
+
if (!isJsonObject(active)) continue;
|
|
2070
2061
|
const { phase, claim, placement } = active;
|
|
2071
2062
|
if (typeof phase !== "string" || !NATIVE_PHASES.has(phase) || placement) continue;
|
|
2072
|
-
if (
|
|
2063
|
+
if (!isJsonObject(claim)) continue;
|
|
2064
|
+
const { root, claimId } = claim;
|
|
2065
|
+
if (typeof root !== "string" || typeof claimId !== "string") continue;
|
|
2073
2066
|
try {
|
|
2074
|
-
if (readClaimSet(
|
|
2067
|
+
if (readClaimSet(root).live.some((holder) => holder.claimId === claimId)) count += 1;
|
|
2075
2068
|
} catch {}
|
|
2076
2069
|
}
|
|
2077
2070
|
return count;
|
|
@@ -2264,10 +2257,15 @@ function ids(value) {
|
|
|
2264
2257
|
function readCreatedDevices() {
|
|
2265
2258
|
try {
|
|
2266
2259
|
const parsed = JSON.parse(readStateFile(createdDevicesFile()));
|
|
2260
|
+
if (!isJsonObject(parsed)) return {
|
|
2261
|
+
ios: /* @__PURE__ */ new Set(),
|
|
2262
|
+
android: /* @__PURE__ */ new Set(),
|
|
2263
|
+
web: /* @__PURE__ */ new Set()
|
|
2264
|
+
};
|
|
2267
2265
|
return {
|
|
2268
|
-
ios: new Set(ids(parsed
|
|
2269
|
-
android: new Set(ids(parsed
|
|
2270
|
-
web: new Set(ids(parsed
|
|
2266
|
+
ios: new Set(ids(parsed.ios)),
|
|
2267
|
+
android: new Set(ids(parsed.android)),
|
|
2268
|
+
web: new Set(ids(parsed.web))
|
|
2271
2269
|
};
|
|
2272
2270
|
} catch {
|
|
2273
2271
|
return {
|
|
@@ -3459,7 +3457,7 @@ const REVIEW_DECISIONS = /* @__PURE__ */ new Set([
|
|
|
3459
3457
|
]);
|
|
3460
3458
|
function pullRequestOf(value) {
|
|
3461
3459
|
if (value === null) return null;
|
|
3462
|
-
if (!
|
|
3460
|
+
if (!isJsonObject(value)) return void 0;
|
|
3463
3461
|
const pr = value;
|
|
3464
3462
|
if (!Number.isInteger(pr.number) || typeof pr.url !== "string" || typeof pr.title !== "string") return void 0;
|
|
3465
3463
|
if (!PR_STATES.has(pr.state) || typeof pr.checkedAt !== "string") return void 0;
|
|
@@ -3524,7 +3522,7 @@ function readBuildDetail(root, claimId) {
|
|
|
3524
3522
|
const file = readJsonObject(workspaceBuildDetailFile(root));
|
|
3525
3523
|
if (!file || file.claimId !== claimId) return null;
|
|
3526
3524
|
const detail = file.detail;
|
|
3527
|
-
if (!
|
|
3525
|
+
if (!isJsonObject(detail)) return null;
|
|
3528
3526
|
const raw = detail;
|
|
3529
3527
|
if (typeof raw.updatedAt !== "string") return null;
|
|
3530
3528
|
return {
|
|
@@ -3541,7 +3539,7 @@ function optionalString(value) {
|
|
|
3541
3539
|
}
|
|
3542
3540
|
/** An agent session as Stim wrote it to its cache or workspace state, or null when it is not one. */
|
|
3543
3541
|
function agentSessionOf(value) {
|
|
3544
|
-
if (!
|
|
3542
|
+
if (!isJsonObject(value)) return null;
|
|
3545
3543
|
const raw = value;
|
|
3546
3544
|
if (!AGENT_TOOLS.includes(raw.tool)) return null;
|
|
3547
3545
|
if (typeof raw.sessionId !== "string" || !raw.sessionId || typeof raw.cwd !== "string" || !raw.cwd) return null;
|
|
@@ -3558,7 +3556,7 @@ function agentSessionOf(value) {
|
|
|
3558
3556
|
if (title) session.title = title;
|
|
3559
3557
|
if (startedAt) session.startedAt = startedAt;
|
|
3560
3558
|
if (lastActiveAt) session.lastActiveAt = lastActiveAt;
|
|
3561
|
-
if (Number.isInteger(raw.pid) && raw.pid > 0) session.pid = raw.pid;
|
|
3559
|
+
if (typeof raw.pid === "number" && Number.isInteger(raw.pid) && raw.pid > 0) session.pid = raw.pid;
|
|
3562
3560
|
if (openUrl) session.openUrl = openUrl;
|
|
3563
3561
|
if (webUrl) session.webUrl = webUrl;
|
|
3564
3562
|
return session;
|
|
@@ -3718,7 +3716,7 @@ function missChange(value) {
|
|
|
3718
3716
|
}
|
|
3719
3717
|
/** A recorded miss reason in the shape status reports, without `baseline.cacheKey`; null when malformed. */
|
|
3720
3718
|
function parseMissReason(value) {
|
|
3721
|
-
if (!
|
|
3719
|
+
if (!isJsonObject(value)) return null;
|
|
3722
3720
|
const record = value;
|
|
3723
3721
|
if (typeof record.kind !== "string" || !MISS_KINDS.has(record.kind) || typeof record.summary !== "string") return null;
|
|
3724
3722
|
const changes = (Array.isArray(record.changes) ? record.changes : []).map(missChange).filter((change) => change !== null).slice(0, MISS_CHANGE_CAP);
|
|
@@ -3727,7 +3725,7 @@ function parseMissReason(value) {
|
|
|
3727
3725
|
kind: record.kind,
|
|
3728
3726
|
summary: record.summary,
|
|
3729
3727
|
changes,
|
|
3730
|
-
changeCount: Number.isInteger(record.changeCount) && record.changeCount >= changes.length ? record.changeCount : changes.length,
|
|
3728
|
+
changeCount: typeof record.changeCount === "number" && Number.isInteger(record.changeCount) && record.changeCount >= changes.length ? record.changeCount : changes.length,
|
|
3731
3729
|
baseline: baseline && typeof baseline.fingerprint === "string" && (baseline.from === "workspace" || baseline.from === "project") ? {
|
|
3732
3730
|
fingerprint: baseline.fingerprint,
|
|
3733
3731
|
from: baseline.from
|
|
@@ -3755,7 +3753,7 @@ function buildDiagnostics(value) {
|
|
|
3755
3753
|
}).toSorted((a, b) => Number(b.file !== null) - Number(a.file !== null)).slice(0, DIAGNOSTIC_CAP);
|
|
3756
3754
|
}
|
|
3757
3755
|
function devicePlacement(value) {
|
|
3758
|
-
if (!
|
|
3756
|
+
if (!isJsonObject(value)) return null;
|
|
3759
3757
|
const record = value;
|
|
3760
3758
|
if (record.decision !== "local" && record.decision !== "hosted" && record.decision !== "waited-locally" && record.decision !== "eas" || typeof record.reason !== "string") return null;
|
|
3761
3759
|
return {
|
|
@@ -3771,7 +3769,7 @@ function readDevicePlacement(state, platform, slot = "default") {
|
|
|
3771
3769
|
return devicePlacement(isJsonObject(device) ? device.devicePlacement : void 0);
|
|
3772
3770
|
}
|
|
3773
3771
|
function lastBuildReport(platform, value) {
|
|
3774
|
-
if (!
|
|
3772
|
+
if (!isJsonObject(value)) return null;
|
|
3775
3773
|
const record = value;
|
|
3776
3774
|
if (record.platform !== platform || record.status !== "ok" && record.status !== "failed") return null;
|
|
3777
3775
|
if (typeof record.startedAt !== "string") return null;
|
|
@@ -4331,24 +4329,39 @@ function deviceHostArea(id) {
|
|
|
4331
4329
|
}
|
|
4332
4330
|
function parseHostedChoice(value) {
|
|
4333
4331
|
if (!isJsonObject(value)) return null;
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4332
|
+
const { deviceTypeId, runtimeId, deviceType, runtime, architecture } = value;
|
|
4333
|
+
if (typeof deviceTypeId !== "string" || !deviceTypeId || typeof runtimeId !== "string" || !runtimeId || typeof deviceType !== "string" || !deviceType || typeof runtime !== "string" || !runtime || architecture !== "arm64" && architecture !== "x86_64") return null;
|
|
4334
|
+
return {
|
|
4335
|
+
deviceTypeId,
|
|
4336
|
+
runtimeId,
|
|
4337
|
+
deviceType,
|
|
4338
|
+
runtime,
|
|
4339
|
+
architecture
|
|
4340
|
+
};
|
|
4342
4341
|
}
|
|
4343
4342
|
function parseHostedDevice(value) {
|
|
4344
|
-
if (!isJsonObject(value) || value.avdName !== void 0
|
|
4345
|
-
|
|
4346
|
-
|
|
4343
|
+
if (!isJsonObject(value) || value.avdName !== void 0) return null;
|
|
4344
|
+
const choice = parseHostedChoice(value);
|
|
4345
|
+
const { udid, name } = value;
|
|
4346
|
+
if (!choice || typeof udid !== "string" || !/^[a-fA-F0-9-]{36}$/.test(udid) || typeof name !== "string") return null;
|
|
4347
|
+
return {
|
|
4348
|
+
...choice,
|
|
4349
|
+
udid,
|
|
4350
|
+
name
|
|
4351
|
+
};
|
|
4347
4352
|
}
|
|
4348
4353
|
function parseHostedAndroidDevice(value) {
|
|
4349
4354
|
if (!isJsonObject(value)) return null;
|
|
4350
|
-
|
|
4351
|
-
|
|
4355
|
+
const { avdName, consolePort, systemImage, deviceProfile, architecture } = value;
|
|
4356
|
+
if (value.udid !== void 0 || typeof avdName !== "string" || !/^stim-[A-Za-z0-9._-]+$/.test(avdName) || !hostedConsolePort(consolePort) || value.serial !== `emulator-${consolePort}` || typeof systemImage !== "string" || !/^system-images;android-\d+;[^;\s]+;(arm64-v8a|x86_64)$/.test(systemImage) || typeof deviceProfile !== "string" || !deviceProfile || architecture !== "arm64-v8a" && architecture !== "x86_64" || !systemImage.endsWith(`;${architecture}`)) return null;
|
|
4357
|
+
return {
|
|
4358
|
+
avdName,
|
|
4359
|
+
serial: `emulator-${consolePort}`,
|
|
4360
|
+
consolePort,
|
|
4361
|
+
systemImage,
|
|
4362
|
+
deviceProfile,
|
|
4363
|
+
architecture
|
|
4364
|
+
};
|
|
4352
4365
|
}
|
|
4353
4366
|
/** Android Emulator -help-port defines the supported even console ports as 5554 through 5584. */
|
|
4354
4367
|
function hostedConsolePort(value) {
|
|
@@ -4645,8 +4658,8 @@ function readHostedApp(session, attempt, workerHome) {
|
|
|
4645
4658
|
function processRecord(value) {
|
|
4646
4659
|
if (!value || typeof value !== "object") return void 0;
|
|
4647
4660
|
const { pid, processToken, startedAtMicros } = value;
|
|
4648
|
-
if (!Number.isSafeInteger(pid) || pid <= 0 || typeof processToken !== "string") return void 0;
|
|
4649
|
-
if (!Number.isSafeInteger(startedAtMicros) || startedAtMicros <= 0) return void 0;
|
|
4661
|
+
if (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid <= 0 || typeof processToken !== "string") return void 0;
|
|
4662
|
+
if (typeof startedAtMicros !== "number" || !Number.isSafeInteger(startedAtMicros) || startedAtMicros <= 0) return void 0;
|
|
4650
4663
|
return {
|
|
4651
4664
|
pid,
|
|
4652
4665
|
processToken,
|
|
@@ -4866,11 +4879,11 @@ const hostedNativeLogsDir = (home, platform) => join(home, `${platform}-logs`);
|
|
|
4866
4879
|
function readHostedNativeLogsCheckpoint(home, platform = "ios") {
|
|
4867
4880
|
try {
|
|
4868
4881
|
const value = JSON.parse(readFileSync(join(hostedNativeLogsDir(home, platform), "checkpoint.json"), "utf8"));
|
|
4869
|
-
if (!isJsonObject(value) || !Number.isSafeInteger(value.until) || value.until < 0 || value.windowMs !== void 0 && (!Number.isSafeInteger(value.windowMs) || value.windowMs < 1e3) || !Array.isArray(value.boundary) || !value.boundary.every((each) => typeof each === "string" && /^[a-f0-9]{64}$/.test(each))) return null;
|
|
4882
|
+
if (!isJsonObject(value) || !Number.isSafeInteger(value.until) || value.until < 0 || value.windowMs !== void 0 && (typeof value.windowMs !== "number" || !Number.isSafeInteger(value.windowMs) || value.windowMs < 1e3) || !Array.isArray(value.boundary) || !value.boundary.every((each) => typeof each === "string" && /^[a-f0-9]{64}$/.test(each))) return null;
|
|
4870
4883
|
return {
|
|
4871
4884
|
until: value.until,
|
|
4872
4885
|
boundary: value.boundary,
|
|
4873
|
-
...typeof value.appAttempt === "string" && Number.isSafeInteger(value.pid) && value.pid > 0 ? {
|
|
4886
|
+
...typeof value.appAttempt === "string" && typeof value.pid === "number" && Number.isSafeInteger(value.pid) && value.pid > 0 ? {
|
|
4874
4887
|
appAttempt: value.appAttempt,
|
|
4875
4888
|
pid: value.pid
|
|
4876
4889
|
} : {},
|
|
@@ -5159,7 +5172,7 @@ function parseSetupJournal(value) {
|
|
|
5159
5172
|
"ok",
|
|
5160
5173
|
"skipped",
|
|
5161
5174
|
"failed"
|
|
5162
|
-
].includes(step.state) && text(step.title) && (step.detail === void 0 || typeof step.detail === "string") && (step.fix === void 0 || typeof step.fix === "string")) || !Array.isArray(value.granted) || !value.granted.every((grant) => isJsonObject(grant) && knownKeys(grant, ["capability", "id"]) && capability(grant.capability) && text(grant.id)) || typeof value.done !== "boolean" || value.exit !== void 0 && (!Number.isInteger(value.exit) || value.exit < 0)) return null;
|
|
5175
|
+
].includes(step.state) && text(step.title) && (step.detail === void 0 || typeof step.detail === "string") && (step.fix === void 0 || typeof step.fix === "string")) || !Array.isArray(value.granted) || !value.granted.every((grant) => isJsonObject(grant) && knownKeys(grant, ["capability", "id"]) && capability(grant.capability) && text(grant.id)) || typeof value.done !== "boolean" || value.exit !== void 0 && (typeof value.exit !== "number" || !Number.isInteger(value.exit) || value.exit < 0)) return null;
|
|
5163
5176
|
return value;
|
|
5164
5177
|
}
|
|
5165
5178
|
function readSetupJournal(hash) {
|