@node9/proxy 2.13.1 → 2.14.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.
@@ -343,6 +343,28 @@ function codexSessionCost(model, tokens, request) {
343
343
  const tierMultiplier = request?.serviceTier === "flex" ? 0.5 : codexModel(model) === "gpt-6-astra" && (request?.serviceTier === "fast" || request?.serviceTier === "priority") ? 2 : 1;
344
344
  return (((input - cached - written) * pin + cached * pcr + written * (pcw || pin)) * inputMultiplier + tokenNumber(tokens.output) * pout * outputMultiplier) * tierMultiplier;
345
345
  }
346
+ function statAndFirstLine(file) {
347
+ const CAP = 4 * 1024 * 1024;
348
+ const CHUNK = 64 * 1024;
349
+ const fd = fs2.openSync(file, "r");
350
+ try {
351
+ const stat = fs2.fstatSync(fd);
352
+ const limit = Math.min(stat.size, CAP);
353
+ const parts = [];
354
+ for (let pos = 0; pos < limit; pos += CHUNK) {
355
+ const buf = Buffer.alloc(Math.min(CHUNK, limit - pos));
356
+ const read = fs2.readSync(fd, buf, 0, buf.length, pos);
357
+ if (read <= 0) break;
358
+ const slice = buf.subarray(0, read);
359
+ const nl = slice.indexOf(10);
360
+ parts.push(nl >= 0 ? slice.subarray(0, nl) : slice);
361
+ if (nl >= 0) break;
362
+ }
363
+ return { stat, first: Buffer.concat(parts).toString("utf8") };
364
+ } finally {
365
+ fs2.closeSync(fd);
366
+ }
367
+ }
346
368
  function listCodexSessionFiles(base = codexSessionsDir()) {
347
369
  const files = [];
348
370
  const walk = (dir) => {
@@ -360,10 +382,10 @@ function listCodexSessionFiles(base = codexSessionsDir()) {
360
382
  const sessions = /* @__PURE__ */ new Map();
361
383
  for (const file of files.sort()) {
362
384
  try {
363
- const stat = fs2.statSync(file);
385
+ const { stat, first: head } = statAndFirstLine(file);
364
386
  let id = "";
365
387
  try {
366
- const first = JSON.parse(fs2.readFileSync(file, "utf8").split("\n", 1)[0]);
388
+ const first = JSON.parse(head);
367
389
  if (first?.type === "session_meta" && typeof first.payload?.id === "string")
368
390
  id = first.payload.id;
369
391
  } catch {
@@ -1067,20 +1089,32 @@ function isProtectedHomePath(rawPath) {
1067
1089
  }
1068
1090
  return true;
1069
1091
  }
1070
- function extractLiteralArgs(callExpr) {
1071
- const args = callExpr.Args || [];
1072
- if (args.length === 0) return { name: "", flags: [], paths: [], words: [] };
1073
- const words = args.map((a) => resolveWordLiteral(a));
1074
- const name = (words[0] ?? "").toLowerCase();
1075
- const flags = [];
1076
- const paths = [];
1077
- for (let i = 1; i < words.length; i++) {
1092
+ function positionedArgs(words, from = 1, to = words.length) {
1093
+ const out = [];
1094
+ let afterFlag = null;
1095
+ for (let i = from; i < to; i++) {
1078
1096
  const v = words[i];
1079
- if (v === null) continue;
1080
- if (v.startsWith("-")) flags.push(v);
1081
- else paths.push(v);
1097
+ if (v === null) {
1098
+ afterFlag = null;
1099
+ continue;
1100
+ }
1101
+ if (v.startsWith("-")) {
1102
+ afterFlag = v;
1103
+ continue;
1104
+ }
1105
+ out.push({ value: v, index: out.length, argv: i, afterFlag });
1106
+ afterFlag = null;
1082
1107
  }
1083
- return { name, flags, paths, words };
1108
+ return out;
1109
+ }
1110
+ function extractLiteralArgs(callExpr) {
1111
+ const rawArgs = callExpr.Args || [];
1112
+ if (rawArgs.length === 0) return { name: "", flags: [], paths: [], words: [], args: [] };
1113
+ const words = rawArgs.map((a) => resolveWordLiteral(a));
1114
+ const name = baseWord(words[0]);
1115
+ const flags = words.slice(1).filter((w) => w !== null && w.startsWith("-"));
1116
+ const args = positionedArgs(words);
1117
+ return { name, flags, paths: args.map((a) => a.value), words, args };
1084
1118
  }
1085
1119
  function resolveWordLiteral(w) {
1086
1120
  const parts = w?.Parts || [];
@@ -1191,6 +1225,9 @@ function analyzeFsOperationImpl(command, depth = 0) {
1191
1225
  if (result?.verdict === "block") return false;
1192
1226
  }
1193
1227
  }
1228
+ for (const p of copySourcePaths(words)) {
1229
+ result = stricter(result, copyVerdictOf(matchSensitivePath2(p)));
1230
+ }
1194
1231
  return true;
1195
1232
  });
1196
1233
  return result;
@@ -1203,6 +1240,133 @@ function stricter(a, b) {
1203
1240
  if (!b) return a;
1204
1241
  return b.verdict === "block" && a.verdict !== "block" ? b : a;
1205
1242
  }
1243
+ function flagInfo(w) {
1244
+ if (w.startsWith("--")) {
1245
+ const eq = w.indexOf("=");
1246
+ return eq < 0 ? { letter: null, long: w, attached: null } : { letter: null, long: w.slice(0, eq), attached: w.slice(eq + 1) };
1247
+ }
1248
+ const m = /^-([a-zA-Z]+)(.*)$/.exec(w);
1249
+ if (!m) return { letter: null, long: null, attached: null };
1250
+ return { letter: m[1][m[1].length - 1], long: null, attached: m[2] === "" ? null : m[2] };
1251
+ }
1252
+ function flagIs(w, names) {
1253
+ if (w === null) return false;
1254
+ const f = flagInfo(w);
1255
+ return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
1256
+ }
1257
+ function operandOf(a, names) {
1258
+ if (!names || a.afterFlag === null) return false;
1259
+ return flagIs(a.afterFlag, names) && flagInfo(a.afterFlag).attached === null;
1260
+ }
1261
+ function resolveCopyShape(words, h) {
1262
+ const verb = baseWord(words[h]);
1263
+ if (!verb) return null;
1264
+ const direct = COPY_VERBS[verb];
1265
+ if (direct) return { shape: direct, last: h };
1266
+ const slots = positionedArgs(words, h + 1);
1267
+ for (let i = 0; i < slots.length; i++) {
1268
+ for (let n = 3; n >= 1; n--) {
1269
+ const part = slots.slice(i, i + n);
1270
+ if (part.length < n) continue;
1271
+ const key = [verb, ...part.map((a) => a.value.toLowerCase())].join(" ");
1272
+ const shape = COPY_VERBS[key];
1273
+ if (shape) return { shape, last: part[n - 1].argv };
1274
+ }
1275
+ if (slots[i].afterFlag === null) return null;
1276
+ }
1277
+ return null;
1278
+ }
1279
+ function findStartPoints(words, h) {
1280
+ const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
1281
+ if (k < 0) return { k, starts: [] };
1282
+ const firstPredicate = words.findIndex(
1283
+ (w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
1284
+ );
1285
+ const end = firstPredicate > h ? firstPredicate : k;
1286
+ return { k, starts: positionalAfter(words, h + 1, end) };
1287
+ }
1288
+ function copySourcePaths(words) {
1289
+ const h = unwrapCommandHead(words);
1290
+ const fi = words.findIndex((w, i) => i <= h && baseWord(w) === "find");
1291
+ if (fi >= 0) {
1292
+ const { k, starts } = findStartPoints(words, fi);
1293
+ if (k < 0) return [];
1294
+ const action = unwrapCommandHead(words.slice(k + 1));
1295
+ return resolveCopyShape(words.slice(k + 1), action) ? starts : [];
1296
+ }
1297
+ if (!COPY_VERB_HEADS.has(baseWord(words[h]))) return [];
1298
+ const r = resolveCopyShape(words, h);
1299
+ if (!r) return [];
1300
+ const { shape, last } = r;
1301
+ const args = positionedArgs(words, last + 1);
1302
+ const tail = words.slice(last + 1);
1303
+ const skipped = (a) => operandOf(a, shape.skipFlags);
1304
+ const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && flagIs(w, ["t", "--target-directory"]));
1305
+ const targetOperand = (a) => targetDir && operandOf(a, ["t", "--target-directory"]);
1306
+ const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
1307
+ const dynamicDest = lastOperand === null;
1308
+ const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
1309
+ if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
1310
+ return [];
1311
+ let src;
1312
+ switch (shape.source) {
1313
+ case "all":
1314
+ src = args;
1315
+ break;
1316
+ case "first":
1317
+ src = targetDir ? args : args.slice(0, 1);
1318
+ break;
1319
+ case "flagOperand": {
1320
+ const inline = tail.filter((w) => w !== null && w.startsWith("--")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && (shape.sourceFlags ?? []).includes(f.long ?? "")).map((f) => f.attached);
1321
+ return [
1322
+ ...args.filter(
1323
+ (a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
1324
+ ).map((a) => a.value),
1325
+ ...inline
1326
+ ];
1327
+ }
1328
+ case "archive":
1329
+ src = archiveInputs(shape.archive, args, tail);
1330
+ break;
1331
+ case "allButLast":
1332
+ src = targetDir || dynamicDest ? args : args.slice(0, -1);
1333
+ break;
1334
+ }
1335
+ return src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
1336
+ }
1337
+ function archiveInputs(kind, args, tail) {
1338
+ const first = args[0];
1339
+ const bareKey = first && first.afterFlag === null && TAR_MODE_WORD.test(first.value);
1340
+ if (kind === "tar") {
1341
+ const flagsText = tail.filter((w) => w !== null && w.startsWith("-")).join(" ");
1342
+ const mode = (bareKey ? first.value : "") + flagsText;
1343
+ const extracting = /x|t/.test(bareKey ? first.value.replace(/f/g, "") : "") || /(^|\s)-[a-zA-Z]*[xt]|--extract|--list|--get/.test(flagsText);
1344
+ const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
1345
+ if (extracting && !writing) return [];
1346
+ void mode;
1347
+ let i = 0;
1348
+ if (bareKey) {
1349
+ i = 1;
1350
+ const next = args[1];
1351
+ if (first.value.includes("f") && next && next.afterFlag === null) i = 2;
1352
+ }
1353
+ return args.slice(i);
1354
+ }
1355
+ if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
1356
+ if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
1357
+ return args.slice(2);
1358
+ }
1359
+ function copyVerdictOf(hit) {
1360
+ if (!hit) return null;
1361
+ const ruleName = COPY_RULE_OF[hit.ruleName];
1362
+ if (!ruleName) return null;
1363
+ return {
1364
+ ruleName,
1365
+ verdict: "review",
1366
+ reason: `Copying ${hit.path} moves a credential out of its jail (project-jail shield)`,
1367
+ path: hit.path
1368
+ };
1369
+ }
1206
1370
  function matchSensitivePath2(p) {
1207
1371
  for (const sp of SENSITIVE_PATH_RULES) {
1208
1372
  if (sp.match(p))
@@ -1210,12 +1374,13 @@ function matchSensitivePath2(p) {
1210
1374
  }
1211
1375
  return null;
1212
1376
  }
1377
+ function baseWord(w) {
1378
+ return (w ?? "").split("/").pop()?.toLowerCase() ?? "";
1379
+ }
1213
1380
  function wrappedReadPaths(words, name) {
1214
1381
  if (name === "find") {
1215
- const k = words.findIndex((w) => w !== null && FIND_EXEC_FLAGS.has(w));
1216
- if (k < 1 || !isReaderWord(words[k + 1] ?? null)) return null;
1217
- const firstPredicate = words.findIndex((w, i) => i > 0 && w !== null && w.startsWith("-"));
1218
- return positionalAfter(words, 1, firstPredicate > 0 ? firstPredicate : k);
1382
+ const { k, starts } = findStartPoints(words, 0);
1383
+ return k > 0 && isReaderWord(words[k + 1] ?? null) ? starts : null;
1219
1384
  }
1220
1385
  if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
1221
1386
  const h = unwrapCommandHead(words);
@@ -1564,7 +1729,7 @@ function matchCanaryArgs(args, values) {
1564
1729
  return null;
1565
1730
  }
1566
1731
  }
1567
- var B58, B58_INDEX, XPRV_VERSIONS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, isReaderWord, positionalAfter, SOURCE_COMMANDS, SSRF_MAX_HOST, METADATA_ADDRESSES, METADATA_HOSTNAMES, v4Octets, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH2, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
1732
+ var B58, B58_INDEX, XPRV_VERSIONS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, SCP_VALUE_FLAGS, RSYNC_SKIP, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, SOURCE_COMMANDS, SSRF_MAX_HOST, METADATA_ADDRESSES, METADATA_HOSTNAMES, v4Octets, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH2, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
1568
1733
  var init_dist = __esm({
1569
1734
  "packages/policy-engine/dist/index.mjs"() {
1570
1735
  "use strict";
@@ -2165,12 +2330,56 @@ var init_dist = __esm({
2165
2330
  "nl",
2166
2331
  "dd"
2167
2332
  ]);
2333
+ SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
2334
+ RSYNC_SKIP = [
2335
+ "e",
2336
+ "--rsh",
2337
+ "--exclude",
2338
+ "--exclude-from",
2339
+ "--include",
2340
+ "--include-from",
2341
+ "--files-from",
2342
+ "f",
2343
+ "--filter"
2344
+ ];
2345
+ COPY_VERBS = {
2346
+ cp: { source: "allButLast", targetDirFlag: true },
2347
+ mv: { source: "allButLast", targetDirFlag: true },
2348
+ install: { source: "allButLast", targetDirFlag: true },
2349
+ ln: { source: "first", targetDirFlag: true },
2350
+ scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS },
2351
+ rsync: { source: "allButLast", skipFlags: RSYNC_SKIP },
2352
+ tar: {
2353
+ source: "archive",
2354
+ archive: "tar",
2355
+ skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
2356
+ },
2357
+ zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
2358
+ ar: { source: "archive", archive: "ar" },
2359
+ "7z": { source: "archive", archive: "7z", skipFlags: ["x", "--exclude"] },
2360
+ gzip: { source: "all" },
2361
+ bzip2: { source: "all" },
2362
+ xz: { source: "all" },
2363
+ "docker cp": { source: "allButLast" },
2364
+ "kubectl cp": { source: "allButLast" },
2365
+ "gsutil cp": { source: "allButLast" },
2366
+ "gsutil rsync": { source: "allButLast" },
2367
+ "rclone copy": { source: "allButLast" },
2368
+ "rclone sync": { source: "allButLast" },
2369
+ "aws s3 cp": { source: "allButLast" },
2370
+ "aws s3 mv": { source: "allButLast" },
2371
+ "aws s3 sync": { source: "allButLast" },
2372
+ "gcloud storage cp": { source: "allButLast" },
2373
+ "az storage blob upload": { source: "flagOperand", sourceFlags: ["f", "--file"] }
2374
+ };
2375
+ TAR_MODE_WORD = /^[a-zA-Z]+$/;
2376
+ COPY_VERB_HEADS = new Set(Object.keys(COPY_VERBS).map((k) => k.split(" ")[0]));
2168
2377
  FS_OP_PRESCREEN_RE = new RegExp(
2169
2378
  // A quote is a separator too: `eval "cat X"` and `sh -c 'cat X'` put the
2170
2379
  // reader right after `"` / `'`, and without these two characters the
2171
2380
  // prescreen rejected every string-wrapped read before the parser ran.
2172
2381
  // Found 2026-09-11 by instrumenting the walk -- no CallExpr was ever visited.
2173
- `(?:^|[\\s|;&("'\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b|(?<!<)<(?!<)`
2382
+ `(?:^|[\\s|;&("'\`\\n/])(?:rm|${[...FS_READ_TOOLS, ...COPY_VERB_HEADS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b|(?<!<)<(?!<)`
2174
2383
  );
2175
2384
  HOME_CACHE_ALLOWLIST = [
2176
2385
  ".cache",
@@ -2349,8 +2558,15 @@ var init_dist = __esm({
2349
2558
  deriveRedirOp("cat <<X\nX"),
2350
2559
  deriveRedirOp("cat <<-X\nX")
2351
2560
  ]);
2352
- isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(w.split("/").pop()?.toLowerCase() ?? "");
2353
- positionalAfter = (words, from, to = words.length) => words.slice(from, to).filter((w) => w !== null && !w.startsWith("-"));
2561
+ FIND_OPTIONS = /* @__PURE__ */ new Set(["-H", "-L", "-P"]);
2562
+ COPY_RULE_OF = {
2563
+ "shield:project-jail:block-read-ssh": "shield:project-jail:review-copy-ssh",
2564
+ "shield:project-jail:block-read-aws": "shield:project-jail:review-copy-aws",
2565
+ "shield:project-jail:block-read-env": "shield:project-jail:review-copy-env",
2566
+ "shield:project-jail:review-read-credentials": "shield:project-jail:review-copy-credentials"
2567
+ };
2568
+ isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
2569
+ positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
2354
2570
  SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
2355
2571
  SSRF_MAX_HOST = 253;
2356
2572
  METADATA_ADDRESSES = /* @__PURE__ */ new Set([
@@ -7278,10 +7494,16 @@ function buildRuleToShieldMap() {
7278
7494
  }
7279
7495
  return map;
7280
7496
  }
7497
+ function shieldOfRule(map, rule) {
7498
+ const exact = map.get(rule);
7499
+ if (exact) return exact;
7500
+ const m = /^shield:([^:]+):/.exec(rule);
7501
+ return m && SHIELDS[m[1]] ? m[1] : void 0;
7502
+ }
7281
7503
  function applyActivityToShields(agg, e, ruleToShield) {
7282
7504
  if (e.kind !== "tool" || !e.checkedBy) return agg;
7283
7505
  if (e.verdict !== "block" && e.verdict !== "review") return agg;
7284
- const shieldName = ruleToShield.get(e.checkedBy);
7506
+ const shieldName = shieldOfRule(ruleToShield, e.checkedBy);
7285
7507
  if (!shieldName) return agg;
7286
7508
  const current = agg.byShield[shieldName] ?? { blocks: 0, reviews: 0 };
7287
7509
  const updated = {
@@ -8277,7 +8499,7 @@ function PeriodShields({
8277
8499
  const byShield = /* @__PURE__ */ new Map();
8278
8500
  if (data) {
8279
8501
  for (const [rule, count] of data.ruleMap) {
8280
- const shield = ruleToShield.get(rule);
8502
+ const shield = shieldOfRule(ruleToShield, rule);
8281
8503
  if (!shield) continue;
8282
8504
  byShield.set(shield, (byShield.get(shield) ?? 0) + count);
8283
8505
  }