@patchstack/connect 0.5.3 → 0.5.5

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/protect.cjs CHANGED
@@ -38,8 +38,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
38
38
  // src/pulse-token.ts
39
39
  function buildTokenUrl(manifestEndpoint) {
40
40
  const url = new URL(manifestEndpoint);
41
- const path8 = url.pathname.replace(/\/$/, "");
42
- url.pathname = path8.endsWith("/manifest") ? `${path8.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
41
+ const path9 = url.pathname.replace(/\/$/, "");
42
+ url.pathname = path9.endsWith("/manifest") ? `${path9.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
43
43
  url.search = "";
44
44
  url.hash = "";
45
45
  return url.toString();
@@ -158,6 +158,46 @@ var init_types = __esm({
158
158
  }
159
159
  code;
160
160
  cause;
161
+ /**
162
+ * For a `VALIDATION_ERROR`, the request fields the server refused, as it named them. Read from the
163
+ * structured `errors` object a validation response carries, so a caller deciding what to do about a
164
+ * refusal keys on the field rather than on the wording of a sentence.
165
+ */
166
+ fields = [];
167
+ };
168
+ }
169
+ });
170
+
171
+ // src/hosting.ts
172
+ function detectHostingPlatform(env = process.env) {
173
+ for (const rule of RULES) {
174
+ const evidence = rule.any.filter((name) => present(env, name));
175
+ if (evidence.length > 0) {
176
+ return { platform: rule.platform, evidence };
177
+ }
178
+ }
179
+ return { platform: null, evidence: [] };
180
+ }
181
+ var RULES, present;
182
+ var init_hosting = __esm({
183
+ "src/hosting.ts"() {
184
+ "use strict";
185
+ RULES = [
186
+ { platform: "netlify", any: ["NETLIFY", "NETLIFY_BUILD_BASE", "DEPLOY_PRIME_URL"] },
187
+ { platform: "vercel", any: ["VERCEL", "VERCEL_ENV", "VERCEL_URL"] },
188
+ { platform: "cloudflare", any: ["CF_PAGES", "CF_PAGES_URL", "CLOUDFLARE_ACCOUNT_ID"] },
189
+ { platform: "aws", any: ["AWS_APP_ID", "AWS_LAMBDA_FUNCTION_NAME", "AWS_EXECUTION_ENV"] },
190
+ { platform: "render", any: ["RENDER", "RENDER_SERVICE_ID", "RENDER_EXTERNAL_URL"] },
191
+ { platform: "railway", any: ["RAILWAY_ENVIRONMENT", "RAILWAY_ENVIRONMENT_NAME", "RAILWAY_PROJECT_ID"] },
192
+ { platform: "fly", any: ["FLY_APP_NAME", "FLY_REGION", "FLY_ALLOC_ID"] },
193
+ { platform: "heroku", any: ["DYNO", "HEROKU_APP_NAME"] },
194
+ { platform: "google-cloud", any: ["K_SERVICE", "GAE_APPLICATION", "GAE_SERVICE"] },
195
+ { platform: "deno-deploy", any: ["DENO_DEPLOYMENT_ID"] },
196
+ { platform: "azure", any: ["WEBSITE_SITE_NAME", "WEBSITE_INSTANCE_ID"] }
197
+ ];
198
+ present = (env, name) => {
199
+ const value = env[name];
200
+ return value !== void 0 && value !== "";
161
201
  };
162
202
  }
163
203
  });
@@ -183,14 +223,22 @@ function authFailureMessage(status, config) {
183
223
  }
184
224
  return null;
185
225
  }
186
- function buildManifestBody(config, payload) {
226
+ function buildManifestBody(config, payload, env = process.env) {
227
+ const hosting = config.environment === "local" ? null : detectHostingPlatform(env);
187
228
  return {
188
229
  ...payload,
189
230
  environment: config.environment,
190
231
  ...typeof config.siteUrl === "string" && config.siteUrl !== "" ? { url: config.siteUrl } : {},
191
- ...typeof config.siteName === "string" && config.siteName !== "" ? { name: config.siteName } : {}
232
+ ...typeof config.siteName === "string" && config.siteName !== "" ? { name: config.siteName } : {},
233
+ ...hosting !== null && hosting.platform !== null ? { hosting } : {}
192
234
  };
193
235
  }
236
+ function validationFields(body) {
237
+ if (typeof body !== "object" || body === null) return [];
238
+ const errors = body.errors;
239
+ if (typeof errors !== "object" || errors === null || Array.isArray(errors)) return [];
240
+ return Object.keys(errors);
241
+ }
194
242
  async function postManifest(config, payload) {
195
243
  const url = buildEndpointUrl(config.endpoint, config.siteUuid);
196
244
  const timeoutMs = config.timeoutMs;
@@ -235,10 +283,12 @@ async function postManifest(config, payload) {
235
283
  );
236
284
  }
237
285
  if (response.status === 422) {
238
- throw new PatchstackError(
286
+ const refused2 = new PatchstackError(
239
287
  body?.message ?? "Patchstack rejected the manifest payload (validation failed).",
240
288
  "VALIDATION_ERROR"
241
289
  );
290
+ refused2.fields = validationFields(body);
291
+ throw refused2;
242
292
  }
243
293
  const refused = authFailureMessage(response.status, config);
244
294
  if (refused !== null) {
@@ -266,6 +316,7 @@ var init_client = __esm({
266
316
  "src/client.ts"() {
267
317
  "use strict";
268
318
  init_types();
319
+ init_hosting();
269
320
  init_pulse_token();
270
321
  init_build_id();
271
322
  DEFAULT_ENDPOINT = "https://api.patchstack.com/monitor/pulse/manifest";
@@ -274,6 +325,85 @@ var init_client = __esm({
274
325
  }
275
326
  });
276
327
 
328
+ // src/environment.ts
329
+ function detectHostedBuilder(cwd) {
330
+ let declared;
331
+ try {
332
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(import_node_path.default.join(cwd, "package.json"), "utf8"));
333
+ declared = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
334
+ } catch {
335
+ return null;
336
+ }
337
+ const names = Object.keys(declared);
338
+ for (const rule of HOSTED_BUILDER_PACKAGES) {
339
+ const hit = names.some(
340
+ (name) => rule.exact.includes(name) || rule.prefixes.some((prefix) => name.startsWith(prefix))
341
+ );
342
+ if (hit) return rule.builder;
343
+ }
344
+ return null;
345
+ }
346
+ function inferEnvironment(env = process.env, builder = null) {
347
+ for (const discriminator of DISCRIMINATORS) {
348
+ const verdict = discriminator.read(env);
349
+ if (verdict !== null) {
350
+ return { environment: verdict.environment, evidence: [`${discriminator.platform}: ${verdict.evidence}`] };
351
+ }
352
+ }
353
+ if (builder !== null) {
354
+ return {
355
+ environment: "production",
356
+ evidence: [`${builder}: a build in a ${builder} project is its publish step`]
357
+ };
358
+ }
359
+ return { environment: "local", evidence: [] };
360
+ }
361
+ var import_node_fs, import_node_path, set, DISCRIMINATORS, HOSTED_BUILDER_PACKAGES;
362
+ var init_environment = __esm({
363
+ "src/environment.ts"() {
364
+ "use strict";
365
+ import_node_fs = require("fs");
366
+ import_node_path = __toESM(require("path"), 1);
367
+ set = (value) => value !== void 0 && value !== "";
368
+ DISCRIMINATORS = [
369
+ {
370
+ platform: "vercel",
371
+ read: (env) => {
372
+ if (!set(env.VERCEL) || !set(env.VERCEL_ENV)) return null;
373
+ return env.VERCEL_ENV === "production" ? { environment: "production", evidence: "VERCEL_ENV=production" } : { environment: "sandbox", evidence: `VERCEL_ENV=${env.VERCEL_ENV}` };
374
+ }
375
+ },
376
+ {
377
+ platform: "netlify",
378
+ read: (env) => {
379
+ if (env.NETLIFY !== "true" || !set(env.CONTEXT)) return null;
380
+ return env.CONTEXT === "production" ? { environment: "production", evidence: "CONTEXT=production" } : { environment: "sandbox", evidence: `CONTEXT=${env.CONTEXT}` };
381
+ }
382
+ },
383
+ {
384
+ platform: "render",
385
+ read: (env) => {
386
+ if (env.RENDER !== "true") return null;
387
+ return env.IS_PULL_REQUEST === "true" ? { environment: "sandbox", evidence: "IS_PULL_REQUEST=true" } : { environment: "production", evidence: "RENDER=true, not a pull request" };
388
+ }
389
+ },
390
+ {
391
+ platform: "railway",
392
+ read: (env) => {
393
+ if (!set(env.RAILWAY_ENVIRONMENT_NAME)) return null;
394
+ return env.RAILWAY_ENVIRONMENT_NAME === "production" ? { environment: "production", evidence: "RAILWAY_ENVIRONMENT_NAME=production" } : { environment: "sandbox", evidence: `RAILWAY_ENVIRONMENT_NAME=${env.RAILWAY_ENVIRONMENT_NAME}` };
395
+ }
396
+ }
397
+ ];
398
+ HOSTED_BUILDER_PACKAGES = [
399
+ // `lovable-tagger` covers projects from before ~Aug 2026; current templates ship the
400
+ // `@lovable.dev/*` scoped tooling instead.
401
+ { builder: "lovable", exact: ["lovable-tagger"], prefixes: ["@lovable.dev/"] },
402
+ { builder: "replit", exact: [], prefixes: ["@replit/"] }
403
+ ];
404
+ }
405
+ });
406
+
277
407
  // src/site-url.ts
278
408
  function isUnpublishableHost(hostname) {
279
409
  const host = hostname.toLowerCase().replace(/\.+$/, "");
@@ -378,13 +508,13 @@ async function readIfPresent(file) {
378
508
  }
379
509
  }
380
510
  async function detectSiteName(cwd) {
381
- for (const shell of ["index.html", import_node_path.default.join("public", "index.html")]) {
382
- const html = await readIfPresent(import_node_path.default.join(cwd, shell));
511
+ for (const shell of ["index.html", import_node_path2.default.join("public", "index.html")]) {
512
+ const html = await readIfPresent(import_node_path2.default.join(cwd, shell));
383
513
  if (html === null) continue;
384
514
  const name = nameFromHtmlTitle(html);
385
515
  if (name !== null) return { name, source: "index.html" };
386
516
  }
387
- const manifest = await readIfPresent(import_node_path.default.join(cwd, "package.json"));
517
+ const manifest = await readIfPresent(import_node_path2.default.join(cwd, "package.json"));
388
518
  if (manifest !== null) {
389
519
  try {
390
520
  const parsed = JSON.parse(manifest);
@@ -397,12 +527,12 @@ async function detectSiteName(cwd) {
397
527
  }
398
528
  return null;
399
529
  }
400
- var import_promises, import_node_path, NAME_MAX_LENGTH, TEMPLATE_PACKAGE_NAMES, TEMPLATE_TITLES, NAMED_ENTITIES2;
530
+ var import_promises, import_node_path2, NAME_MAX_LENGTH, TEMPLATE_PACKAGE_NAMES, TEMPLATE_TITLES, NAMED_ENTITIES2;
401
531
  var init_site_name = __esm({
402
532
  "src/site-name.ts"() {
403
533
  "use strict";
404
534
  import_promises = require("fs/promises");
405
- import_node_path = __toESM(require("path"), 1);
535
+ import_node_path2 = __toESM(require("path"), 1);
406
536
  NAME_MAX_LENGTH = 191;
407
537
  TEMPLATE_PACKAGE_NAMES = /* @__PURE__ */ new Set([
408
538
  // Lovable
@@ -485,11 +615,13 @@ async function resolveConfig(options) {
485
615
  const environmentRaw = fromEnv.environment ?? fromFile.environment;
486
616
  if (environmentRaw !== void 0 && !isEnvironment(environmentRaw)) {
487
617
  throw new PatchstackError(
488
- `Environment must be "production" or "sandbox"; got "${environmentRaw}".`,
618
+ `Environment must be "production", "sandbox" or "local"; got "${environmentRaw}".`,
489
619
  "CONFIG_INVALID"
490
620
  );
491
621
  }
492
- const environment = environmentRaw ?? DEFAULT_ENVIRONMENT;
622
+ const inferred = environmentRaw === void 0 ? inferEnvironment(process.env, detectHostedBuilder(options.cwd)) : null;
623
+ const environment = environmentRaw ?? inferred.environment;
624
+ const environmentEvidence = inferred?.evidence ?? [];
493
625
  if (siteUuid !== null && siteUuid.length > 0 && !isUuid(siteUuid)) {
494
626
  throw new PatchstackError(
495
627
  `Site UUID "${siteUuid}" does not look like a valid UUID.`,
@@ -515,6 +647,7 @@ async function resolveConfig(options) {
515
647
  endpoint,
516
648
  timeoutMs,
517
649
  environment,
650
+ environmentEvidence,
518
651
  widget: fromFile.widget !== false,
519
652
  claimToken
520
653
  };
@@ -527,7 +660,7 @@ async function readConfigFile(cwd) {
527
660
  return readJsonFile(cwd, CONFIG_FILENAME);
528
661
  }
529
662
  async function readJsonFile(cwd, filename) {
530
- const target = import_node_path2.default.join(cwd, filename);
663
+ const target = import_node_path3.default.join(cwd, filename);
531
664
  let raw;
532
665
  try {
533
666
  raw = await (0, import_promises2.readFile)(target, "utf8");
@@ -580,21 +713,21 @@ function isUuid(value) {
580
713
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
581
714
  }
582
715
  function isEnvironment(value) {
583
- return value === "production" || value === "sandbox";
716
+ return value === "production" || value === "sandbox" || value === "local";
584
717
  }
585
- var import_promises2, import_node_path2, CONFIG_FILENAME, SECRET_FILENAME, DEFAULT_ENVIRONMENT;
718
+ var import_promises2, import_node_path3, CONFIG_FILENAME, SECRET_FILENAME;
586
719
  var init_config = __esm({
587
720
  "src/config.ts"() {
588
721
  "use strict";
589
722
  import_promises2 = require("fs/promises");
590
- import_node_path2 = __toESM(require("path"), 1);
723
+ import_node_path3 = __toESM(require("path"), 1);
591
724
  init_types();
592
725
  init_client();
726
+ init_environment();
593
727
  init_site_url();
594
728
  init_site_name();
595
729
  CONFIG_FILENAME = ".patchstackrc.json";
596
730
  SECRET_FILENAME = ".patchstackrc.local.json";
597
- DEFAULT_ENVIRONMENT = "production";
598
731
  }
599
732
  });
600
733
 
@@ -602,7 +735,7 @@ var init_config = __esm({
602
735
  async function readDeclaredDependencyNames(cwd) {
603
736
  let raw;
604
737
  try {
605
- raw = await (0, import_promises3.readFile)(import_node_path3.default.join(cwd, "package.json"), "utf8");
738
+ raw = await (0, import_promises3.readFile)(import_node_path4.default.join(cwd, "package.json"), "utf8");
606
739
  } catch {
607
740
  return [];
608
741
  }
@@ -631,8 +764,8 @@ async function readDeclaredDependencyNames(cwd) {
631
764
  return [...names];
632
765
  }
633
766
  function missingDependencies(declared, packages) {
634
- const present = new Set(packages.map((entry) => entry.name));
635
- return declared.filter((name) => !present.has(name));
767
+ const present2 = new Set(packages.map((entry) => entry.name));
768
+ return declared.filter((name) => !present2.has(name));
636
769
  }
637
770
  function disagreements(packages, other) {
638
771
  const otherVersions = /* @__PURE__ */ new Map();
@@ -651,12 +784,12 @@ function disagreements(packages, other) {
651
784
  }
652
785
  return conflicts;
653
786
  }
654
- var import_promises3, import_node_path3;
787
+ var import_promises3, import_node_path4;
655
788
  var init_consistency = __esm({
656
789
  "src/parsers/consistency.ts"() {
657
790
  "use strict";
658
791
  import_promises3 = require("fs/promises");
659
- import_node_path3 = __toESM(require("path"), 1);
792
+ import_node_path4 = __toESM(require("path"), 1);
660
793
  }
661
794
  });
662
795
 
@@ -874,7 +1007,7 @@ function extractFromV1(deps, acc = [], depth = 0) {
874
1007
  return acc;
875
1008
  }
876
1009
  function extractNameFromPath(pkgPath) {
877
- const segments = pkgPath.split("node_modules" + import_node_path4.default.sep === pkgPath ? import_node_path4.default.sep : "/");
1010
+ const segments = pkgPath.split("node_modules" + import_node_path5.default.sep === pkgPath ? import_node_path5.default.sep : "/");
878
1011
  const parts = pkgPath.split("/");
879
1012
  const nmIndex = parts.lastIndexOf("node_modules");
880
1013
  if (nmIndex === -1 || nmIndex >= parts.length - 1) {
@@ -895,19 +1028,19 @@ function isDirectV2(pkgPath) {
895
1028
  const nmCount = parts.filter((p) => p === "node_modules").length;
896
1029
  return nmCount === 1;
897
1030
  }
898
- var import_promises5, import_node_path4;
1031
+ var import_promises5, import_node_path5;
899
1032
  var init_npm = __esm({
900
1033
  "src/parsers/npm.ts"() {
901
1034
  "use strict";
902
1035
  import_promises5 = require("fs/promises");
903
- import_node_path4 = __toESM(require("path"), 1);
1036
+ import_node_path5 = __toESM(require("path"), 1);
904
1037
  init_types();
905
1038
  }
906
1039
  });
907
1040
 
908
1041
  // src/parsers/node_modules.ts
909
1042
  async function walkNodeModules(cwd) {
910
- const root = import_node_path5.default.join(cwd, "node_modules");
1043
+ const root = import_node_path6.default.join(cwd, "node_modules");
911
1044
  try {
912
1045
  const info = await (0, import_promises6.stat)(root);
913
1046
  if (!info.isDirectory()) {
@@ -950,7 +1083,7 @@ async function walk(dir, depth, seen, root) {
950
1083
  }
951
1084
  const perEntry = await mapLimit(names, async (name) => {
952
1085
  if (name.startsWith(".") && !PACKAGE_STORE_DIRS.has(name)) return [];
953
- const fullPath = import_node_path5.default.join(dir, name);
1086
+ const fullPath = import_node_path6.default.join(dir, name);
954
1087
  const resolved = await claim(fullPath, seen, depth);
955
1088
  if (resolved === null) return [];
956
1089
  if (PACKAGE_STORE_DIRS.has(name)) return walk(fullPath, depth, seen, root);
@@ -963,7 +1096,7 @@ async function walk(dir, depth, seen, root) {
963
1096
  }
964
1097
  const scoped = await mapLimit(subNames, async (sub) => {
965
1098
  if (sub.startsWith(".")) return [];
966
- const scopedDir = import_node_path5.default.join(fullPath, sub);
1099
+ const scopedDir = import_node_path6.default.join(fullPath, sub);
967
1100
  const scopedReal = await claim(scopedDir, seen, depth);
968
1101
  if (scopedReal === null) return [];
969
1102
  return packageAndNested(scopedDir, scopedReal, depth, seen, root);
@@ -990,13 +1123,13 @@ async function mapLimit(items, fn) {
990
1123
  await Promise.all(workers);
991
1124
  return results;
992
1125
  }
993
- function installLocation(root, pkgDir, impl = import_node_path5.default) {
1126
+ function installLocation(root, pkgDir, impl = import_node_path6.default) {
994
1127
  return impl.relative(root, pkgDir).split(impl.sep).join("/");
995
1128
  }
996
1129
  async function readPackage(pkgDir, depth, root) {
997
1130
  let raw;
998
1131
  try {
999
- raw = await (0, import_promises6.readFile)(import_node_path5.default.join(pkgDir, "package.json"), "utf8");
1132
+ raw = await (0, import_promises6.readFile)(import_node_path6.default.join(pkgDir, "package.json"), "utf8");
1000
1133
  } catch {
1001
1134
  return null;
1002
1135
  }
@@ -1015,7 +1148,7 @@ async function readPackage(pkgDir, depth, root) {
1015
1148
  return { name: parsed.name, version: parsed.version, path: installLocation(root, pkgDir), direct: depth === 0 };
1016
1149
  }
1017
1150
  async function walkNested(pkgDir, depth, seen, root) {
1018
- const nested = import_node_path5.default.join(pkgDir, "node_modules");
1151
+ const nested = import_node_path6.default.join(pkgDir, "node_modules");
1019
1152
  if (await claim(nested, seen, depth + 1) === null) {
1020
1153
  return [];
1021
1154
  }
@@ -1037,12 +1170,12 @@ async function claim(dir, seen, depth) {
1037
1170
  seen.set(resolved, depth);
1038
1171
  return resolved;
1039
1172
  }
1040
- var import_promises6, import_node_path5, PACKAGE_STORE_DIRS, CONCURRENCY;
1173
+ var import_promises6, import_node_path6, PACKAGE_STORE_DIRS, CONCURRENCY;
1041
1174
  var init_node_modules = __esm({
1042
1175
  "src/parsers/node_modules.ts"() {
1043
1176
  "use strict";
1044
1177
  import_promises6 = require("fs/promises");
1045
- import_node_path5 = __toESM(require("path"), 1);
1178
+ import_node_path6 = __toESM(require("path"), 1);
1046
1179
  init_types();
1047
1180
  PACKAGE_STORE_DIRS = /* @__PURE__ */ new Set([".bun", ".pnpm", ".store"]);
1048
1181
  CONCURRENCY = 32;
@@ -1329,7 +1462,7 @@ async function parseYarnLockfile(lockfilePath, report) {
1329
1462
  "LOCKFILE_PARSE_ERROR"
1330
1463
  );
1331
1464
  }
1332
- const directNames = await readDirectDepNames(import_node_path6.default.dirname(lockfilePath));
1465
+ const directNames = await readDirectDepNames(import_node_path7.default.dirname(lockfilePath));
1333
1466
  const entries = [];
1334
1467
  const seen = /* @__PURE__ */ new Set();
1335
1468
  for (const block of blocks) {
@@ -1494,7 +1627,7 @@ async function readDirectDepNames(cwd) {
1494
1627
  const names = /* @__PURE__ */ new Set();
1495
1628
  let raw;
1496
1629
  try {
1497
- raw = await (0, import_promises8.readFile)(import_node_path6.default.join(cwd, "package.json"), "utf8");
1630
+ raw = await (0, import_promises8.readFile)(import_node_path7.default.join(cwd, "package.json"), "utf8");
1498
1631
  } catch {
1499
1632
  return names;
1500
1633
  }
@@ -1519,12 +1652,12 @@ async function readDirectDepNames(cwd) {
1519
1652
  }
1520
1653
  return names;
1521
1654
  }
1522
- var import_promises8, import_node_path6, NON_PACKAGE_KEYS, NON_REGISTRY_PROTOCOLS;
1655
+ var import_promises8, import_node_path7, NON_PACKAGE_KEYS, NON_REGISTRY_PROTOCOLS;
1523
1656
  var init_yarn = __esm({
1524
1657
  "src/parsers/yarn.ts"() {
1525
1658
  "use strict";
1526
1659
  import_promises8 = require("fs/promises");
1527
- import_node_path6 = __toESM(require("path"), 1);
1660
+ import_node_path7 = __toESM(require("path"), 1);
1528
1661
  init_types();
1529
1662
  init_report();
1530
1663
  NON_PACKAGE_KEYS = /* @__PURE__ */ new Set(["__metadata"]);
@@ -1536,7 +1669,7 @@ var init_yarn = __esm({
1536
1669
  async function detectLockfile(cwd) {
1537
1670
  const probed = await Promise.all(
1538
1671
  LOCKFILE_CANDIDATES.map(async (candidate) => {
1539
- const filePath = import_node_path7.default.join(cwd, candidate.filename);
1672
+ const filePath = import_node_path8.default.join(cwd, candidate.filename);
1540
1673
  return { ...candidate, filePath, present: await exists(filePath) };
1541
1674
  })
1542
1675
  );
@@ -1647,7 +1780,7 @@ function staleWarning(source, missing) {
1647
1780
  async function presentLockfiles(cwd) {
1648
1781
  const probed = await Promise.all(
1649
1782
  LOCKFILE_CANDIDATES.map(async (candidate) => {
1650
- const filePath = import_node_path7.default.join(cwd, candidate.filename);
1783
+ const filePath = import_node_path8.default.join(cwd, candidate.filename);
1651
1784
  return { ...candidate, filePath, present: await exists(filePath) };
1652
1785
  })
1653
1786
  );
@@ -1677,12 +1810,12 @@ async function exists(filePath) {
1677
1810
  return false;
1678
1811
  }
1679
1812
  }
1680
- var import_promises9, import_node_path7, LOCKFILE_CANDIDATES;
1813
+ var import_promises9, import_node_path8, LOCKFILE_CANDIDATES;
1681
1814
  var init_parsers = __esm({
1682
1815
  "src/parsers/index.ts"() {
1683
1816
  "use strict";
1684
1817
  import_promises9 = require("fs/promises");
1685
- import_node_path7 = __toESM(require("path"), 1);
1818
+ import_node_path8 = __toESM(require("path"), 1);
1686
1819
  init_types();
1687
1820
  init_consistency();
1688
1821
  init_bun();
@@ -3125,12 +3258,12 @@ function isRegexForm(pattern) {
3125
3258
  const parts = REGEX_FORM.exec(pattern);
3126
3259
  return parts !== null && REGEX_SYNTAX.test(parts[1]);
3127
3260
  }
3128
- function pathMatches(pattern, path8) {
3261
+ function pathMatches(pattern, path9) {
3129
3262
  if (isRegexForm(pattern)) {
3130
3263
  const re = safeRegExp(pattern);
3131
- return re ? re.test(path8) : false;
3264
+ return re ? re.test(path9) : false;
3132
3265
  }
3133
- const target = foldPathForScope(path8);
3266
+ const target = foldPathForScope(path9);
3134
3267
  const folded = foldPathForScope(pattern);
3135
3268
  if (folded.includes("*")) {
3136
3269
  const trailing = folded.endsWith("/*");
@@ -4773,8 +4906,8 @@ function extractHttpTarget(args) {
4773
4906
  const host = normalizeHost(first.hostname || first.host) || "localhost";
4774
4907
  const protocol = first.protocol || "http:";
4775
4908
  const port = first.port ? `:${first.port}` : "";
4776
- const path8 = first.path || "/";
4777
- return { url: `${protocol}//${host}${port}${path8}`, host, method: first.method || "GET" };
4909
+ const path9 = first.path || "/";
4910
+ return { url: `${protocol}//${host}${port}${path9}`, host, method: first.method || "GET" };
4778
4911
  }
4779
4912
  } catch {
4780
4913
  }
@@ -5140,12 +5273,12 @@ var fsMod;
5140
5273
  async function loadFs() {
5141
5274
  if (fsMod !== void 0) return fsMod;
5142
5275
  try {
5143
- const [fs, path8] = await Promise.all([import("fs"), import("path")]);
5276
+ const [fs, path9] = await Promise.all([import("fs"), import("path")]);
5144
5277
  fsMod = {
5145
5278
  readFileSync: fs.readFileSync,
5146
5279
  writeFileSync: fs.writeFileSync,
5147
5280
  mkdirSync: fs.mkdirSync,
5148
- join: path8.join
5281
+ join: path9.join
5149
5282
  };
5150
5283
  } catch {
5151
5284
  fsMod = null;
@@ -5533,13 +5666,13 @@ var MAX_CAPTURED_VALUE_CHARS = 512;
5533
5666
  var MAX_QUERY_KEYS = 10;
5534
5667
  var MAX_METHOD_CHARS = 16;
5535
5668
  var MAX_BODY_BYTES2 = 64 * 1024;
5536
- function queryKeysOf(path8) {
5537
- if (typeof path8 !== "string") return { keys: [], total: 0 };
5538
- const start = path8.indexOf("?");
5669
+ function queryKeysOf(path9) {
5670
+ if (typeof path9 !== "string") return { keys: [], total: 0 };
5671
+ const start = path9.indexOf("?");
5539
5672
  if (start === -1) return { keys: [], total: 0 };
5540
5673
  let names;
5541
5674
  try {
5542
- names = [...new URLSearchParams(path8.slice(start + 1)).keys()];
5675
+ names = [...new URLSearchParams(path9.slice(start + 1)).keys()];
5543
5676
  } catch {
5544
5677
  return { keys: [], total: 0 };
5545
5678
  }
@@ -5678,10 +5811,10 @@ function revisionOf(rule) {
5678
5811
  if (typeof revision === "number" && Number.isFinite(revision)) return String(revision);
5679
5812
  return null;
5680
5813
  }
5681
- function routeOf(path8) {
5682
- if (typeof path8 !== "string" || path8 === "") return null;
5683
- const cut = path8.search(/[?#]/);
5684
- return cut === -1 ? path8 : path8.slice(0, cut);
5814
+ function routeOf(path9) {
5815
+ if (typeof path9 !== "string" || path9 === "") return null;
5816
+ const cut = path9.search(/[?#]/);
5817
+ return cut === -1 ? path9 : path9.slice(0, cut);
5685
5818
  }
5686
5819
  function createDetectionReporter(opts) {
5687
5820
  const siteUuid = opts.siteUuid ?? process.env?.PATCHSTACK_SITE_UUID;
@@ -6985,8 +7118,8 @@ async function createProtection(options = {}) {
6985
7118
  hardened = true;
6986
7119
  try {
6987
7120
  if (res.headersSent || typeof res.setHeader !== "function") return null;
6988
- const set = typeof res.getHeaders === "function" ? res.getHeaders() : {};
6989
- const headers = effective && effective.headers ? { ...set, ...effective.headers } : set;
7121
+ const set2 = typeof res.getHeaders === "function" ? res.getHeaders() : {};
7122
+ const headers = effective && effective.headers ? { ...set2, ...effective.headers } : set2;
6990
7123
  const status = effective && effective.status !== void 0 ? effective.status : res.statusCode;
6991
7124
  const r = screenText("", { status, headers }, reqCtx, hardensWithoutBody);
6992
7125
  answeredWithoutBody = true;
@@ -7389,11 +7522,11 @@ function resolveMode(options, bundle) {
7389
7522
  var CREDENTIAL_FILES = [".patchstackrc.local.json", ".patchstackrc.json"];
7390
7523
  async function readCredentialField(options, field) {
7391
7524
  if (typeof process === "undefined" || typeof process.cwd !== "function") return void 0;
7392
- let readFileSync;
7525
+ let readFileSync2;
7393
7526
  let join;
7394
7527
  try {
7395
7528
  const [fs, pathMod] = await Promise.all([import("fs"), import("path")]);
7396
- readFileSync = fs.readFileSync;
7529
+ readFileSync2 = fs.readFileSync;
7397
7530
  join = pathMod.join;
7398
7531
  } catch {
7399
7532
  return void 0;
@@ -7401,7 +7534,7 @@ async function readCredentialField(options, field) {
7401
7534
  const cwd = options?.cwd ?? process.cwd();
7402
7535
  for (const filename of CREDENTIAL_FILES) {
7403
7536
  try {
7404
- const value = JSON.parse(readFileSync(join(cwd, filename), "utf8"))?.[field];
7537
+ const value = JSON.parse(readFileSync2(join(cwd, filename), "utf8"))?.[field];
7405
7538
  if (typeof value === "string" && value.length > 0) return value;
7406
7539
  } catch {
7407
7540
  }
@@ -7698,8 +7831,8 @@ function applyHeaderMutation(headers, rule) {
7698
7831
  const ensure = rule.ensure === true;
7699
7832
  for (const [name, value] of Object.entries(rule.set_headers ?? {})) {
7700
7833
  const key = String(name).toLowerCase();
7701
- const present = headers[key] != null && headers[key] !== "";
7702
- if (ensure && present) continue;
7834
+ const present2 = headers[key] != null && headers[key] !== "";
7835
+ if (ensure && present2) continue;
7703
7836
  headers[key] = String(value);
7704
7837
  }
7705
7838
  return;
@@ -7822,20 +7955,20 @@ function requestMetaFromContext(reqCtx) {
7822
7955
  }
7823
7956
  function requestMeta(shaped, request) {
7824
7957
  const client = shaped?._clientIp ?? { ip: null, source: "unavailable" };
7825
- let path8 = null;
7958
+ let path9 = null;
7826
7959
  let method = null;
7827
7960
  let userAgent = null;
7828
7961
  if (request) {
7829
7962
  try {
7830
7963
  const u = new URL(request.url);
7831
- path8 = u.pathname + u.search;
7964
+ path9 = u.pathname + u.search;
7832
7965
  } catch {
7833
- path8 = typeof request.url === "string" ? request.url : null;
7966
+ path9 = typeof request.url === "string" ? request.url : null;
7834
7967
  }
7835
7968
  method = request.method ?? null;
7836
7969
  userAgent = request.headers?.get?.("user-agent") ?? null;
7837
7970
  }
7838
- return { method, path: path8, ip: client.ip, clientIpSource: client.source, userAgent, event: eventFor(request) };
7971
+ return { method, path: path9, ip: client.ip, clientIpSource: client.source, userAgent, event: eventFor(request) };
7839
7972
  }
7840
7973
  function nodeRequestMeta(req, client) {
7841
7974
  if (!req) return {};