@patchstack/connect 0.5.4 → 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/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "fs";
5
- import path15 from "path";
4
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "fs";
5
+ import path16 from "path";
6
6
  import { createRequire as createRequire2 } from "module";
7
7
 
8
8
  // src/parsers/index.ts
@@ -1245,8 +1245,8 @@ function detectHostingPlatform(env = process.env) {
1245
1245
  var TOKEN_SKEW_MS = 6e4;
1246
1246
  function buildTokenUrl(manifestEndpoint) {
1247
1247
  const url = new URL(manifestEndpoint);
1248
- const path16 = url.pathname.replace(/\/$/, "");
1249
- url.pathname = path16.endsWith("/manifest") ? `${path16.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
1248
+ const path17 = url.pathname.replace(/\/$/, "");
1249
+ url.pathname = path17.endsWith("/manifest") ? `${path17.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
1250
1250
  url.search = "";
1251
1251
  url.hash = "";
1252
1252
  return url.toString();
@@ -1385,8 +1385,8 @@ function authFailureMessage(status, config) {
1385
1385
  }
1386
1386
  function buildRulesUrl(manifestEndpoint, siteUuid) {
1387
1387
  const url = new URL(manifestEndpoint);
1388
- const path16 = url.pathname.replace(/\/$/, "");
1389
- url.pathname = path16.endsWith("/manifest") ? `${path16.slice(0, -"/manifest".length)}/rules/${encodeURIComponent(siteUuid)}` : `/monitor/pulse/rules/${encodeURIComponent(siteUuid)}`;
1388
+ const path17 = url.pathname.replace(/\/$/, "");
1389
+ url.pathname = path17.endsWith("/manifest") ? `${path17.slice(0, -"/manifest".length)}/rules/${encodeURIComponent(siteUuid)}` : `/monitor/pulse/rules/${encodeURIComponent(siteUuid)}`;
1390
1390
  url.search = "";
1391
1391
  url.hash = "";
1392
1392
  return url.toString();
@@ -1401,16 +1401,16 @@ function buildSettingsUrl(endpoint, siteUuid) {
1401
1401
  }
1402
1402
  function buildPackageRemovedUrl(manifestEndpoint, siteUuid) {
1403
1403
  const url = new URL(manifestEndpoint);
1404
- const path16 = url.pathname.replace(/\/$/, "");
1405
- url.pathname = path16.endsWith("/manifest") ? `${path16.slice(0, -"/manifest".length)}/package-removed/${encodeURIComponent(siteUuid)}` : `/monitor/pulse/package-removed/${encodeURIComponent(siteUuid)}`;
1404
+ const path17 = url.pathname.replace(/\/$/, "");
1405
+ url.pathname = path17.endsWith("/manifest") ? `${path17.slice(0, -"/manifest".length)}/package-removed/${encodeURIComponent(siteUuid)}` : `/monitor/pulse/package-removed/${encodeURIComponent(siteUuid)}`;
1406
1406
  url.search = "";
1407
1407
  url.hash = "";
1408
1408
  return url.toString();
1409
1409
  }
1410
1410
  function buildInputMapUrl(manifestEndpoint, siteUuid) {
1411
1411
  const url = new URL(manifestEndpoint);
1412
- const path16 = url.pathname.replace(/\/$/, "");
1413
- url.pathname = path16.endsWith("/manifest") ? `${path16.slice(0, -"/manifest".length)}/input-map/${encodeURIComponent(siteUuid)}` : `/monitor/pulse/input-map/${encodeURIComponent(siteUuid)}`;
1412
+ const path17 = url.pathname.replace(/\/$/, "");
1413
+ url.pathname = path17.endsWith("/manifest") ? `${path17.slice(0, -"/manifest".length)}/input-map/${encodeURIComponent(siteUuid)}` : `/monitor/pulse/input-map/${encodeURIComponent(siteUuid)}`;
1414
1414
  url.search = "";
1415
1415
  url.hash = "";
1416
1416
  return url.toString();
@@ -1827,9 +1827,11 @@ function renderDemoTestCommands(url, scenario) {
1827
1827
 
1828
1828
  // src/config.ts
1829
1829
  import { readFile as readFile9, writeFile, chmod } from "fs/promises";
1830
- import path7 from "path";
1830
+ import path8 from "path";
1831
1831
 
1832
1832
  // src/environment.ts
1833
+ import { readFileSync } from "fs";
1834
+ import path6 from "path";
1833
1835
  var set = (value) => value !== void 0 && value !== "";
1834
1836
  var DISCRIMINATORS = [
1835
1837
  {
@@ -1861,13 +1863,42 @@ var DISCRIMINATORS = [
1861
1863
  }
1862
1864
  }
1863
1865
  ];
1864
- function inferEnvironment(env = process.env) {
1866
+ var HOSTED_BUILDER_PACKAGES = [
1867
+ // `lovable-tagger` covers projects from before ~Aug 2026; current templates ship the
1868
+ // `@lovable.dev/*` scoped tooling instead.
1869
+ { builder: "lovable", exact: ["lovable-tagger"], prefixes: ["@lovable.dev/"] },
1870
+ { builder: "replit", exact: [], prefixes: ["@replit/"] }
1871
+ ];
1872
+ function detectHostedBuilder(cwd) {
1873
+ let declared;
1874
+ try {
1875
+ const pkg = JSON.parse(readFileSync(path6.join(cwd, "package.json"), "utf8"));
1876
+ declared = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
1877
+ } catch {
1878
+ return null;
1879
+ }
1880
+ const names = Object.keys(declared);
1881
+ for (const rule of HOSTED_BUILDER_PACKAGES) {
1882
+ const hit = names.some(
1883
+ (name) => rule.exact.includes(name) || rule.prefixes.some((prefix) => name.startsWith(prefix))
1884
+ );
1885
+ if (hit) return rule.builder;
1886
+ }
1887
+ return null;
1888
+ }
1889
+ function inferEnvironment(env = process.env, builder = null) {
1865
1890
  for (const discriminator of DISCRIMINATORS) {
1866
1891
  const verdict = discriminator.read(env);
1867
1892
  if (verdict !== null) {
1868
1893
  return { environment: verdict.environment, evidence: [`${discriminator.platform}: ${verdict.evidence}`] };
1869
1894
  }
1870
1895
  }
1896
+ if (builder !== null) {
1897
+ return {
1898
+ environment: "production",
1899
+ evidence: [`${builder}: a build in a ${builder} project is its publish step`]
1900
+ };
1901
+ }
1871
1902
  return { environment: "local", evidence: [] };
1872
1903
  }
1873
1904
 
@@ -1940,7 +1971,7 @@ function detectSiteUrl(env = process.env) {
1940
1971
 
1941
1972
  // src/site-name.ts
1942
1973
  import { readFile as readFile8 } from "fs/promises";
1943
- import path6 from "path";
1974
+ import path7 from "path";
1944
1975
  var NAME_MAX_LENGTH = 191;
1945
1976
  var TEMPLATE_PACKAGE_NAMES = /* @__PURE__ */ new Set([
1946
1977
  // Lovable
@@ -2017,13 +2048,13 @@ async function readIfPresent(file) {
2017
2048
  }
2018
2049
  }
2019
2050
  async function detectSiteName(cwd) {
2020
- for (const shell of ["index.html", path6.join("public", "index.html")]) {
2021
- const html = await readIfPresent(path6.join(cwd, shell));
2051
+ for (const shell of ["index.html", path7.join("public", "index.html")]) {
2052
+ const html = await readIfPresent(path7.join(cwd, shell));
2022
2053
  if (html === null) continue;
2023
2054
  const name = nameFromHtmlTitle(html);
2024
2055
  if (name !== null) return { name, source: "index.html" };
2025
2056
  }
2026
- const manifest = await readIfPresent(path6.join(cwd, "package.json"));
2057
+ const manifest = await readIfPresent(path7.join(cwd, "package.json"));
2027
2058
  if (manifest !== null) {
2028
2059
  try {
2029
2060
  const parsed = JSON.parse(manifest);
@@ -2076,7 +2107,7 @@ async function resolveConfig(options) {
2076
2107
  "CONFIG_INVALID"
2077
2108
  );
2078
2109
  }
2079
- const inferred = environmentRaw === void 0 ? inferEnvironment(process.env) : null;
2110
+ const inferred = environmentRaw === void 0 ? inferEnvironment(process.env, detectHostedBuilder(options.cwd)) : null;
2080
2111
  const environment = environmentRaw ?? inferred.environment;
2081
2112
  const environmentEvidence = inferred?.evidence ?? [];
2082
2113
  if (siteUuid !== null && siteUuid.length > 0 && !isUuid(siteUuid)) {
@@ -2110,14 +2141,14 @@ async function resolveConfig(options) {
2110
2141
  };
2111
2142
  }
2112
2143
  async function writeConfigFile(cwd, config) {
2113
- const target = path7.join(cwd, CONFIG_FILENAME);
2144
+ const target = path8.join(cwd, CONFIG_FILENAME);
2114
2145
  const content = JSON.stringify(config, null, 2) + "\n";
2115
2146
  await writeFile(target, content, "utf8");
2116
2147
  return target;
2117
2148
  }
2118
2149
  var SECRET_CONFIG_FILENAME = SECRET_FILENAME;
2119
2150
  async function writeSecretFile(cwd, secrets) {
2120
- const target = path7.join(cwd, SECRET_FILENAME);
2151
+ const target = path8.join(cwd, SECRET_FILENAME);
2121
2152
  await writeFile(target, JSON.stringify(secrets, null, 2) + "\n", { encoding: "utf8", mode: 384 });
2122
2153
  try {
2123
2154
  await chmod(target, 384);
@@ -2127,7 +2158,7 @@ async function writeSecretFile(cwd, secrets) {
2127
2158
  return { path: target, ...ignore };
2128
2159
  }
2129
2160
  async function ensureIgnored(cwd, entry) {
2130
- const target = path7.join(cwd, ".gitignore");
2161
+ const target = path8.join(cwd, ".gitignore");
2131
2162
  let existing = "";
2132
2163
  try {
2133
2164
  existing = await readFile9(target, "utf8");
@@ -2160,7 +2191,7 @@ ${entry}
2160
2191
  }
2161
2192
  async function secretFileIgnored(cwd) {
2162
2193
  try {
2163
- const contents = await readFile9(path7.join(cwd, ".gitignore"), "utf8");
2194
+ const contents = await readFile9(path8.join(cwd, ".gitignore"), "utf8");
2164
2195
  if (ignoresEntry(contents, SECRET_FILENAME)) return { ignored: true };
2165
2196
  return { ignored: false, reason: `.gitignore does not cover ${SECRET_FILENAME}` };
2166
2197
  } catch (err) {
@@ -2211,7 +2242,7 @@ async function readConfigFile(cwd) {
2211
2242
  return readJsonFile(cwd, CONFIG_FILENAME);
2212
2243
  }
2213
2244
  async function readJsonFile(cwd, filename) {
2214
- const target = path7.join(cwd, filename);
2245
+ const target = path8.join(cwd, filename);
2215
2246
  let raw;
2216
2247
  try {
2217
2248
  raw = await readFile9(target, "utf8");
@@ -2268,8 +2299,8 @@ function isEnvironment(value) {
2268
2299
  }
2269
2300
 
2270
2301
  // src/mark-build.ts
2271
- import { existsSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "fs";
2272
- import path8 from "path";
2302
+ import { existsSync, readFileSync as readFileSync2, readdirSync, realpathSync, statSync, writeFileSync } from "fs";
2303
+ import path9 from "path";
2273
2304
 
2274
2305
  // src/stack.ts
2275
2306
  var STACK_RULES = [
@@ -2362,6 +2393,24 @@ function isEmptyStack(stack) {
2362
2393
 
2363
2394
  // src/mark-build.ts
2364
2395
  var MARKER_ATTR = "data-patchstack-build";
2396
+ function marksPublishedBuild(environment) {
2397
+ return environment === "production";
2398
+ }
2399
+ var STALE_BUILD_WARNING_MS = 60 * 60 * 1e3;
2400
+ function staleBuildAge(files, startedAt) {
2401
+ let newest = null;
2402
+ for (const file of files) {
2403
+ try {
2404
+ const at = statSync(file).mtimeMs;
2405
+ if (newest === null || at > newest) newest = at;
2406
+ } catch {
2407
+ continue;
2408
+ }
2409
+ }
2410
+ if (newest === null) return null;
2411
+ const age = startedAt - newest;
2412
+ return age > STALE_BUILD_WARNING_MS ? age : null;
2413
+ }
2365
2414
  var BUILD_DIR_CANDIDATES = ["dist", "build", "out", ".output/public", "_site"];
2366
2415
  var FRAMEWORK_BUILD_DIRS = {
2367
2416
  eleventy: ["_site"],
@@ -2382,7 +2431,7 @@ function buildDirCandidates(options = {}) {
2382
2431
  }
2383
2432
  function resolveBuildDir(cwd, override, options = {}) {
2384
2433
  if (override !== void 0 && override !== "") {
2385
- const abs = path8.resolve(cwd, override);
2434
+ const abs = path9.resolve(cwd, override);
2386
2435
  return existsSync(abs) && statSync(abs).isDirectory() ? abs : null;
2387
2436
  }
2388
2437
  let boundary;
@@ -2392,7 +2441,7 @@ function resolveBuildDir(cwd, override, options = {}) {
2392
2441
  return null;
2393
2442
  }
2394
2443
  for (const candidate of buildDirCandidates(options)) {
2395
- const abs = path8.resolve(cwd, candidate);
2444
+ const abs = path9.resolve(cwd, candidate);
2396
2445
  if (!existsSync(abs) || !statSync(abs).isDirectory()) continue;
2397
2446
  let real;
2398
2447
  try {
@@ -2400,7 +2449,7 @@ function resolveBuildDir(cwd, override, options = {}) {
2400
2449
  } catch {
2401
2450
  continue;
2402
2451
  }
2403
- if (real === boundary || real.startsWith(boundary + path8.sep)) {
2452
+ if (real === boundary || real.startsWith(boundary + path9.sep)) {
2404
2453
  return abs;
2405
2454
  }
2406
2455
  }
@@ -2410,7 +2459,7 @@ function findHtmlFiles(dir) {
2410
2459
  const out = [];
2411
2460
  const walk2 = (current) => {
2412
2461
  for (const entry of readdirSync(current, { withFileTypes: true })) {
2413
- const full = path8.join(current, entry.name);
2462
+ const full = path9.join(current, entry.name);
2414
2463
  if (entry.isDirectory()) {
2415
2464
  walk2(full);
2416
2465
  } else if (entry.isFile() && entry.name.toLowerCase().endsWith(".html")) {
@@ -2559,8 +2608,8 @@ function ensureSourceMarker(cwd, shell, framework) {
2559
2608
  if (shell === null) {
2560
2609
  return { shell: null, source: "", action: "no-anchor" };
2561
2610
  }
2562
- const file = path8.resolve(cwd, shell);
2563
- const before = readFileSync(file, "utf8");
2611
+ const file = path9.resolve(cwd, shell);
2612
+ const before = readFileSync2(file, "utf8");
2564
2613
  const result = ensureMarkerInJsxShell(before, framework);
2565
2614
  if (result.source !== before) {
2566
2615
  writeFileSync(file, result.source);
@@ -2569,15 +2618,15 @@ function ensureSourceMarker(cwd, shell, framework) {
2569
2618
  }
2570
2619
 
2571
2620
  // src/guide.ts
2572
- import { existsSync as existsSync13, readFileSync as readFileSync9, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
2573
- import path11 from "path";
2621
+ import { existsSync as existsSync13, readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
2622
+ import path12 from "path";
2574
2623
 
2575
2624
  // src/architecture.ts
2576
- import { existsSync as existsSync2, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
2577
- import path9 from "path";
2625
+ import { existsSync as existsSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
2626
+ import path10 from "path";
2578
2627
 
2579
2628
  // src/map/sources.ts
2580
- import { readFileSync as readFileSync2, readdirSync as readdirSync2, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
2629
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
2581
2630
  import { join as join2, relative, isAbsolute } from "path";
2582
2631
 
2583
2632
  // src/map/ast.ts
@@ -2787,7 +2836,7 @@ function hasEntrySignal(text) {
2787
2836
  }
2788
2837
  function detectFramework(cwd) {
2789
2838
  try {
2790
- const pkg = JSON.parse(readFileSync2(join2(cwd, "package.json"), "utf8"));
2839
+ const pkg = JSON.parse(readFileSync3(join2(cwd, "package.json"), "utf8"));
2791
2840
  const d = { ...pkg.dependencies, ...pkg.devDependencies };
2792
2841
  if (d["@tanstack/react-start"] || d["@tanstack/start"] || d["@tanstack/solid-start"]) return "tanstack-start";
2793
2842
  if (d["next"]) return "next";
@@ -2947,10 +2996,10 @@ function detectDeploymentShapes(cwd, opts = {}) {
2947
2996
  boundary = realpathSync2(boundary);
2948
2997
  } catch {
2949
2998
  }
2950
- const inProject = (path16) => {
2999
+ const inProject = (path17) => {
2951
3000
  if (opts.followOutside) return true;
2952
3001
  try {
2953
- return isInside(realpathSync2(path16), boundary);
3002
+ return isInside(realpathSync2(path17), boundary);
2954
3003
  } catch {
2955
3004
  return false;
2956
3005
  }
@@ -3016,7 +3065,7 @@ function holdsSourceFile(dir) {
3016
3065
  }
3017
3066
 
3018
3067
  // src/map/surface.ts
3019
- import { readFileSync as readFileSync3 } from "fs";
3068
+ import { readFileSync as readFileSync4 } from "fs";
3020
3069
  import { join as join3 } from "path";
3021
3070
  var STATIC_GENERATORS = [
3022
3071
  { dep: "vite", label: "vite" },
@@ -3058,7 +3107,7 @@ var SHAPE_SIGNAL = {
3058
3107
  };
3059
3108
  function readManifest(cwd) {
3060
3109
  try {
3061
- const parsed = JSON.parse(readFileSync3(join3(cwd, "package.json"), "utf8"));
3110
+ const parsed = JSON.parse(readFileSync4(join3(cwd, "package.json"), "utf8"));
3062
3111
  return typeof parsed === "object" && parsed !== null ? parsed : null;
3063
3112
  } catch {
3064
3113
  return null;
@@ -3071,7 +3120,7 @@ function nextExportsStatically(cwd, manifest, ts) {
3071
3120
  for (const file of ["next.config.js", "next.config.mjs", "next.config.ts", "next.config.cjs"]) {
3072
3121
  let text;
3073
3122
  try {
3074
- text = readFileSync3(join3(cwd, file), "utf8");
3123
+ text = readFileSync4(join3(cwd, file), "utf8");
3075
3124
  } catch {
3076
3125
  continue;
3077
3126
  }
@@ -3230,7 +3279,7 @@ var SERVING_CALL = /\b(?:createServer|createSecureServer|Bun\.serve|Deno\.serve|
3230
3279
  var MAX_ENTRY_BYTES = 256 * 1024;
3231
3280
  function readManifest2(cwd) {
3232
3281
  try {
3233
- const parsed = JSON.parse(readFileSync4(path9.join(cwd, "package.json"), "utf8"));
3282
+ const parsed = JSON.parse(readFileSync5(path10.join(cwd, "package.json"), "utf8"));
3234
3283
  return typeof parsed === "object" && parsed !== null ? parsed : {};
3235
3284
  } catch {
3236
3285
  return {};
@@ -3259,16 +3308,16 @@ function staticGenerators(deps) {
3259
3308
  }
3260
3309
  function serverEntries(cwd, manifest) {
3261
3310
  const candidates = new Set(SERVER_ENTRY_CANDIDATES);
3262
- if (typeof manifest.main === "string" && manifest.main !== "" && !path9.isAbsolute(manifest.main)) {
3263
- const main2 = path9.normalize(manifest.main);
3311
+ if (typeof manifest.main === "string" && manifest.main !== "" && !path10.isAbsolute(manifest.main)) {
3312
+ const main2 = path10.normalize(manifest.main);
3264
3313
  if (!main2.startsWith("..")) candidates.add(main2);
3265
3314
  }
3266
3315
  const found = [];
3267
3316
  for (const relative7 of candidates) {
3268
- const file = path9.join(cwd, relative7);
3317
+ const file = path10.join(cwd, relative7);
3269
3318
  try {
3270
3319
  if (!existsSync2(file) || !statSync3(file).isFile()) continue;
3271
- const text = readFileSync4(file, "utf8").slice(0, MAX_ENTRY_BYTES);
3320
+ const text = readFileSync5(file, "utf8").slice(0, MAX_ENTRY_BYTES);
3272
3321
  if (SERVING_CALL.test(text)) found.push(relative7);
3273
3322
  } catch {
3274
3323
  }
@@ -3322,10 +3371,10 @@ function classifyArchitecture(cwd) {
3322
3371
  }
3323
3372
 
3324
3373
  // src/protect/install/util.ts
3325
- import { readFileSync as readFileSync5, existsSync as existsSync3, writeFileSync as writeFileSync2 } from "fs";
3374
+ import { readFileSync as readFileSync6, existsSync as existsSync3, writeFileSync as writeFileSync2 } from "fs";
3326
3375
  import { join as join4, dirname } from "path";
3327
3376
  import { fileURLToPath } from "url";
3328
- var read = (p) => readFileSync5(p, "utf8");
3377
+ var read = (p) => readFileSync6(p, "utf8");
3329
3378
  var log = (msg) => console.log(`patchstack protect: ${msg}`);
3330
3379
  function hasDependency(cwd, name) {
3331
3380
  try {
@@ -3798,7 +3847,7 @@ var nuxtAdapter = {
3798
3847
  };
3799
3848
 
3800
3849
  // src/protect/install/find-app.ts
3801
- import { readFileSync as readFileSync6, existsSync as existsSync7, readdirSync as readdirSync3, lstatSync } from "fs";
3850
+ import { readFileSync as readFileSync7, existsSync as existsSync7, readdirSync as readdirSync3, lstatSync } from "fs";
3802
3851
  import { join as join10, relative as relative2, dirname as dirname3 } from "path";
3803
3852
  var SKIP_DIRS2 = /* @__PURE__ */ new Set([
3804
3853
  "node_modules",
@@ -3844,7 +3893,7 @@ function findAppInstance(cwd, re) {
3844
3893
  else if (/\.(?:ts|js|mjs|cjs)$/.test(name)) {
3845
3894
  let src;
3846
3895
  try {
3847
- src = readFileSync6(p, "utf8");
3896
+ src = readFileSync7(p, "utf8");
3848
3897
  } catch {
3849
3898
  continue;
3850
3899
  }
@@ -3891,7 +3940,7 @@ function declaredEntries(cwd) {
3891
3940
  const paths = /* @__PURE__ */ new Set();
3892
3941
  let pkg;
3893
3942
  try {
3894
- pkg = JSON.parse(readFileSync6(join10(cwd, "package.json"), "utf8"));
3943
+ pkg = JSON.parse(readFileSync7(join10(cwd, "package.json"), "utf8"));
3895
3944
  } catch {
3896
3945
  return paths;
3897
3946
  }
@@ -3921,7 +3970,7 @@ import { writeFileSync as writeFileSync5, existsSync as existsSync10 } from "fs"
3921
3970
  import { join as join13, resolve as resolve2 } from "path";
3922
3971
 
3923
3972
  // src/protect/install/generic.ts
3924
- import { readFileSync as readFileSync7, existsSync as existsSync9, mkdirSync as mkdirSync4, copyFileSync as copyFileSync4, readdirSync as readdirSync4, lstatSync as lstatSync2 } from "fs";
3973
+ import { readFileSync as readFileSync8, existsSync as existsSync9, mkdirSync as mkdirSync4, copyFileSync as copyFileSync4, readdirSync as readdirSync4, lstatSync as lstatSync2 } from "fs";
3925
3974
  import { join as join12, dirname as dirname5 } from "path";
3926
3975
 
3927
3976
  // src/protect/install/source-scope.ts
@@ -4473,7 +4522,7 @@ function guardIsImported(cwd, guardPath) {
4473
4522
  if (st.isDirectory()) walk2(p, depth + 1);
4474
4523
  else if (/\.(?:ts|tsx|js|jsx|mjs|cjs)$/.test(name) && p !== guardPath) {
4475
4524
  try {
4476
- if (importsAndUsesGuard(readFileSync7(p, "utf8"), p, guardDir, packageIsModule)) found = true;
4525
+ if (importsAndUsesGuard(readFileSync8(p, "utf8"), p, guardDir, packageIsModule)) found = true;
4477
4526
  } catch {
4478
4527
  }
4479
4528
  }
@@ -4957,8 +5006,8 @@ function runVerify(cwd) {
4957
5006
  }
4958
5007
 
4959
5008
  // src/widget.ts
4960
- import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
4961
- import path10 from "path";
5009
+ import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
5010
+ import path11 from "path";
4962
5011
  var WIDGET_SCRIPT_URL = "https://cdn.patchstack.com/patchstack-widget.js";
4963
5012
  var WIDGET_MARKER_ATTR = "data-patchstack-connect-widget";
4964
5013
  var WIDGET_NEEDLE = "patchstack-widget";
@@ -4996,7 +5045,7 @@ ${indent}</body>`;
4996
5045
  }
4997
5046
  function findSourceShell(cwd) {
4998
5047
  for (const candidate of SOURCE_SHELL_CANDIDATES) {
4999
- if (existsSync12(path10.join(cwd, candidate))) {
5048
+ if (existsSync12(path11.join(cwd, candidate))) {
5000
5049
  return candidate;
5001
5050
  }
5002
5051
  }
@@ -5007,8 +5056,8 @@ function ensureSourceWidget(cwd, siteUuid) {
5007
5056
  if (shell === null) {
5008
5057
  return { shell: null, action: "no-shell" };
5009
5058
  }
5010
- const file = path10.join(cwd, shell);
5011
- const before = readFileSync8(file, "utf8");
5059
+ const file = path11.join(cwd, shell);
5060
+ const before = readFileSync9(file, "utf8");
5012
5061
  const { html, action } = ensureWidgetInHtml(before, siteUuid);
5013
5062
  if (html !== before) {
5014
5063
  writeFileSync6(file, html);
@@ -5090,7 +5139,7 @@ function detectPackageManager(cwd) {
5090
5139
  return declared;
5091
5140
  }
5092
5141
  for (const { filename, pm } of PM_BY_LOCKFILE) {
5093
- if (existsSync13(path11.join(cwd, filename))) {
5142
+ if (existsSync13(path12.join(cwd, filename))) {
5094
5143
  return pm;
5095
5144
  }
5096
5145
  }
@@ -5101,7 +5150,7 @@ function installCommand(pm) {
5101
5150
  }
5102
5151
  function readPackageJson(cwd) {
5103
5152
  try {
5104
- return JSON.parse(readFileSync9(path11.join(cwd, "package.json"), "utf8"));
5153
+ return JSON.parse(readFileSync10(path12.join(cwd, "package.json"), "utf8"));
5105
5154
  } catch {
5106
5155
  return null;
5107
5156
  }
@@ -5109,7 +5158,7 @@ function readPackageJson(cwd) {
5109
5158
  function installedVersion(cwd, declaredRange) {
5110
5159
  try {
5111
5160
  const pkg = JSON.parse(
5112
- readFileSync9(path11.join(cwd, "node_modules", "@patchstack", "connect", "package.json"), "utf8")
5161
+ readFileSync10(path12.join(cwd, "node_modules", "@patchstack", "connect", "package.json"), "utf8")
5113
5162
  );
5114
5163
  if (typeof pkg.version === "string" && pkg.version.length > 0) {
5115
5164
  return pkg.version;
@@ -5137,7 +5186,7 @@ function findWidgetMarker(cwd, siteUuid) {
5137
5186
  if (budget <= 0 || settled()) {
5138
5187
  return;
5139
5188
  }
5140
- const full = path11.join(dir, entry.name);
5189
+ const full = path12.join(dir, entry.name);
5141
5190
  if (entry.isDirectory()) {
5142
5191
  if (SKIPPED_DIRS.has(entry.name) || entry.name.startsWith(".")) {
5143
5192
  continue;
@@ -5145,7 +5194,7 @@ function findWidgetMarker(cwd, siteUuid) {
5145
5194
  walk2(full, depth + 1);
5146
5195
  continue;
5147
5196
  }
5148
- if (!entry.isFile() || !WIDGET_EXTENSIONS.has(path11.extname(entry.name).toLowerCase())) {
5197
+ if (!entry.isFile() || !WIDGET_EXTENSIONS.has(path12.extname(entry.name).toLowerCase())) {
5149
5198
  continue;
5150
5199
  }
5151
5200
  budget -= 1;
@@ -5153,7 +5202,7 @@ function findWidgetMarker(cwd, siteUuid) {
5153
5202
  if (statSync4(full).size > WIDGET_SCAN_MAX_BYTES) {
5154
5203
  continue;
5155
5204
  }
5156
- const content = readFileSync9(full, "utf8");
5205
+ const content = readFileSync10(full, "utf8");
5157
5206
  if (!content.includes(WIDGET_NEEDLE2)) {
5158
5207
  continue;
5159
5208
  }
@@ -5176,7 +5225,7 @@ function findProductionMarker(cwd, widgetFileHint) {
5176
5225
  return false;
5177
5226
  }
5178
5227
  try {
5179
- return readFileSync9(path11.join(cwd, widgetFileHint), "utf8").includes(PROD_MARKER_NEEDLE);
5228
+ return readFileSync10(path12.join(cwd, widgetFileHint), "utf8").includes(PROD_MARKER_NEEDLE);
5180
5229
  } catch {
5181
5230
  return false;
5182
5231
  }
@@ -5187,7 +5236,7 @@ function resolveWidgetFileHint(cwd, framework) {
5187
5236
  ...GENERIC_WIDGET_FILES
5188
5237
  ];
5189
5238
  for (const candidate of candidates) {
5190
- if (existsSync13(path11.join(cwd, candidate))) {
5239
+ if (existsSync13(path12.join(cwd, candidate))) {
5191
5240
  return candidate;
5192
5241
  }
5193
5242
  }
@@ -5295,7 +5344,7 @@ function renderGuideChecklist(state, useColor) {
5295
5344
  const headerParts = [state.framework, state.packageManager].filter(
5296
5345
  (part) => part !== null
5297
5346
  );
5298
- const name = state.projectName ?? path11.basename(process.cwd());
5347
+ const name = state.projectName ?? path12.basename(process.cwd());
5299
5348
  lines.push(paint(ANSI.bold, `Patchstack setup status \u2014 ${name} (${headerParts.join(" \xB7 ")})`));
5300
5349
  if (state.endpointOverride !== null) {
5301
5350
  lines.push(
@@ -5476,12 +5525,12 @@ function renderGuideChecklist(state, useColor) {
5476
5525
  // src/login.ts
5477
5526
  import { mkdtempSync } from "fs";
5478
5527
  import { tmpdir as tmpdir2 } from "os";
5479
- import path13 from "path";
5528
+ import path14 from "path";
5480
5529
 
5481
5530
  // src/device-flow.ts
5482
- import { readFileSync as readFileSync10, rmSync, writeFileSync as writeFileSync7 } from "fs";
5531
+ import { readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync7 } from "fs";
5483
5532
  import { tmpdir } from "os";
5484
- import path12 from "path";
5533
+ import path13 from "path";
5485
5534
  import { createHash as createHash2 } from "crypto";
5486
5535
  function baseFrom(manifestEndpoint) {
5487
5536
  const url = new URL(manifestEndpoint);
@@ -5493,7 +5542,7 @@ function baseFrom(manifestEndpoint) {
5493
5542
  }
5494
5543
  function pendingPath(siteUuid, intent) {
5495
5544
  const key = createHash2("sha256").update(siteUuid).digest("hex").slice(0, 16);
5496
- return path12.join(tmpdir(), `patchstack-${intent}-${key}.json`);
5545
+ return path13.join(tmpdir(), `patchstack-${intent}-${key}.json`);
5497
5546
  }
5498
5547
  function savePending(siteUuid, intent, pending) {
5499
5548
  writeFileSync7(pendingPath(siteUuid, intent), JSON.stringify(pending), {
@@ -5503,7 +5552,7 @@ function savePending(siteUuid, intent, pending) {
5503
5552
  }
5504
5553
  function readPending(siteUuid, intent) {
5505
5554
  try {
5506
- return JSON.parse(readFileSync10(pendingPath(siteUuid, intent), "utf8"));
5555
+ return JSON.parse(readFileSync11(pendingPath(siteUuid, intent), "utf8"));
5507
5556
  } catch {
5508
5557
  return null;
5509
5558
  }
@@ -5673,7 +5722,7 @@ async function claim2(config, onPrompt, deps = {}) {
5673
5722
  import { relative as relative3 } from "path";
5674
5723
 
5675
5724
  // src/protect/install/runtime/entry.ts
5676
- import { existsSync as existsSync14, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
5725
+ import { existsSync as existsSync14, readFileSync as readFileSync12, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
5677
5726
  import { join as join15, resolve as resolve3, sep } from "path";
5678
5727
  var CONVENTIONAL = [
5679
5728
  "server.js",
@@ -5700,15 +5749,15 @@ var CONVENTIONAL = [
5700
5749
  var LOADABLE = /\.(?:js|mjs|cjs)$/;
5701
5750
  function readPackage2(cwd) {
5702
5751
  try {
5703
- const parsed = JSON.parse(readFileSync11(join15(cwd, "package.json"), "utf8"));
5752
+ const parsed = JSON.parse(readFileSync12(join15(cwd, "package.json"), "utf8"));
5704
5753
  return parsed !== null && typeof parsed === "object" ? parsed : null;
5705
5754
  } catch {
5706
5755
  return null;
5707
5756
  }
5708
5757
  }
5709
- function isFile(path16) {
5758
+ function isFile(path17) {
5710
5759
  try {
5711
- return statSync5(path16).isFile();
5760
+ return statSync5(path17).isFile();
5712
5761
  } catch {
5713
5762
  return false;
5714
5763
  }
@@ -5717,14 +5766,14 @@ function loadable(cwd, candidate) {
5717
5766
  const written = resolve3(cwd, candidate);
5718
5767
  if (!LOADABLE.test(written) || !isFile(written)) return null;
5719
5768
  let root;
5720
- let path16;
5769
+ let path17;
5721
5770
  try {
5722
5771
  root = realpathSync3(cwd);
5723
- path16 = realpathSync3(written);
5772
+ path17 = realpathSync3(written);
5724
5773
  } catch {
5725
5774
  return null;
5726
5775
  }
5727
- if (path16 !== root && !path16.startsWith(root + sep)) return null;
5776
+ if (path17 !== root && !path17.startsWith(root + sep)) return null;
5728
5777
  return written;
5729
5778
  }
5730
5779
  function passable(token) {
@@ -5804,8 +5853,8 @@ function preloadPath() {
5804
5853
  // beside this file, in the repository
5805
5854
  ];
5806
5855
  for (const candidate of candidates) {
5807
- const path16 = fileURLToPath2(candidate);
5808
- if (existsSync15(path16)) return path16;
5856
+ const path17 = fileURLToPath2(candidate);
5857
+ if (existsSync15(path17)) return path17;
5809
5858
  }
5810
5859
  return null;
5811
5860
  }
@@ -6175,7 +6224,7 @@ async function loadTypeScript(cwd) {
6175
6224
  }
6176
6225
 
6177
6226
  // src/map/extract.ts
6178
- import { readFileSync as readFileSync14, realpathSync as realpathSync5 } from "fs";
6227
+ import { readFileSync as readFileSync15, realpathSync as realpathSync5 } from "fs";
6179
6228
  import { createHash as createHash5 } from "crypto";
6180
6229
  import { relative as relative5 } from "path";
6181
6230
 
@@ -6589,7 +6638,7 @@ function dedupeSinks(sinks, owner) {
6589
6638
  }
6590
6639
 
6591
6640
  // src/map/module-graph.ts
6592
- import { readFileSync as readFileSync12, realpathSync as realpathSync4, statSync as statSync6 } from "fs";
6641
+ import { readFileSync as readFileSync13, realpathSync as realpathSync4, statSync as statSync6 } from "fs";
6593
6642
  import { dirname as dirname7, join as join17, relative as relative4, resolve as resolvePath } from "path";
6594
6643
  var RESOLVE_EXTS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
6595
6644
  function createModuleGraph(ts, opts) {
@@ -6598,7 +6647,7 @@ function createModuleGraph(ts, opts) {
6598
6647
  if (cache.has(file)) return cache.get(file) ?? null;
6599
6648
  let entry = null;
6600
6649
  try {
6601
- const text = readFileSync12(file, "utf8");
6650
+ const text = readFileSync13(file, "utf8");
6602
6651
  const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, guessScriptKind(ts, file));
6603
6652
  const bindings = buildModuleBindings(sf, ts);
6604
6653
  entry = { fnSinks: collectLocalSinks(sf, ts, bindings), calleesOf: collectCallees(sf, ts), bindings };
@@ -6697,8 +6746,8 @@ function collectCallees(sf, ts) {
6697
6746
  }
6698
6747
 
6699
6748
  // src/map/coordinates.ts
6700
- function runtimeCoordinate(source, path16) {
6701
- if (/\[\d*\]/.test(path16)) {
6749
+ function runtimeCoordinate(source, path17) {
6750
+ if (/\[\d*\]/.test(path17)) {
6702
6751
  return { runtimeParameter: null, runtimeParameterReason: "array traversal: needs an array_key_value rule, not a dotted parameter" };
6703
6752
  }
6704
6753
  switch (source) {
@@ -6707,15 +6756,15 @@ function runtimeCoordinate(source, path16) {
6707
6756
  case "multipart":
6708
6757
  case "body":
6709
6758
  case "server-fn-data":
6710
- return { runtimeParameter: `post.${path16}` };
6759
+ return { runtimeParameter: `post.${path17}` };
6711
6760
  case "query":
6712
- return { runtimeParameter: `get.${path16}` };
6761
+ return { runtimeParameter: `get.${path17}` };
6713
6762
  case "cookie":
6714
- return { runtimeParameter: `cookie.${path16}` };
6763
+ return { runtimeParameter: `cookie.${path17}` };
6715
6764
  case "file":
6716
- return { runtimeParameter: `files.${path16}` };
6765
+ return { runtimeParameter: `files.${path17}` };
6717
6766
  case "header":
6718
- return { runtimeParameter: `server.HTTP_${path16.toUpperCase().replace(/-/g, "_")}` };
6767
+ return { runtimeParameter: `server.HTTP_${path17.toUpperCase().replace(/-/g, "_")}` };
6719
6768
  case "route-param":
6720
6769
  return { runtimeParameter: null, runtimeParameterReason: "route parameters are not exposed by the runtime resolver" };
6721
6770
  default:
@@ -6747,8 +6796,8 @@ function addressSpaceOf(source) {
6747
6796
  function isProvenFlow(confidence) {
6748
6797
  return confidence === "exact-local" || confidence === "transformed-local";
6749
6798
  }
6750
- function inputIdOf(source, path16) {
6751
- return `${addressSpaceOf(source)}:${path16}`;
6799
+ function inputIdOf(source, path17) {
6800
+ return `${addressSpaceOf(source)}:${path17}`;
6752
6801
  }
6753
6802
  function withCoordinates(fields, source) {
6754
6803
  return fields.map((f) => {
@@ -6958,8 +7007,8 @@ function linkFlows(bodyNode, params, inputs, sinks, ts) {
6958
7007
  if (!bodyNode || sinks.length === 0 || inputs.length === 0) return { flows: [], limitations: [] };
6959
7008
  const CONTAINER_KEYS = /* @__PURE__ */ new Set([...REQ_SOURCES, "data", "input", "payload"]);
6960
7009
  const rootPath = /* @__PURE__ */ new Map();
6961
- const addRoot = (name, path16, space) => {
6962
- if (!rootPath.has(name)) rootPath.set(name, { path: path16, space });
7010
+ const addRoot = (name, path17, space) => {
7011
+ if (!rootPath.has(name)) rootPath.set(name, { path: path17, space });
6963
7012
  };
6964
7013
  for (const p of params ?? []) {
6965
7014
  if (!p?.name) continue;
@@ -7104,8 +7153,8 @@ function dedupeLimitations(list) {
7104
7153
  function join22(base, seg) {
7105
7154
  return base ? `${base}.${seg}` : seg;
7106
7155
  }
7107
- function normalizePath(path16) {
7108
- return path16.replace(/\[\d*\]/g, "").split(".").filter(Boolean).join(".");
7156
+ function normalizePath(path17) {
7157
+ return path17.replace(/\[\d*\]/g, "").split(".").filter(Boolean).join(".");
7109
7158
  }
7110
7159
  function fluentChainCalls(call, ts) {
7111
7160
  let root = call;
@@ -7351,7 +7400,7 @@ function handlerEntry(name, kindLabel, params, body, ts, localSinks, bindings, c
7351
7400
  }
7352
7401
 
7353
7402
  // src/map/imports.ts
7354
- import { readFileSync as readFileSync13 } from "fs";
7403
+ import { readFileSync as readFileSync14 } from "fs";
7355
7404
  import { join as join18 } from "path";
7356
7405
  var MAX_SITES = 5;
7357
7406
  var NPM_NAME = /^(?:@[^/@\s~][^/@\s]*\/)?[^/@\s.~][^/@\s]*$/;
@@ -7363,7 +7412,7 @@ function readPathAliases(cwd) {
7363
7412
  for (const name of ["tsconfig.json", "jsconfig.json"]) {
7364
7413
  let paths;
7365
7414
  try {
7366
- const raw = readFileSync13(join18(cwd, name), "utf8");
7415
+ const raw = readFileSync14(join18(cwd, name), "utf8");
7367
7416
  const parsed = JSON.parse(stripJsonComments(raw));
7368
7417
  paths = parsed.compilerOptions?.paths;
7369
7418
  } catch {
@@ -7742,7 +7791,7 @@ async function extractInputMap(cwd, ts, options = {}) {
7742
7791
  const hopTargets = /* @__PURE__ */ new Set();
7743
7792
  for (const file of files) {
7744
7793
  try {
7745
- const text = readFileSync14(file, "utf8");
7794
+ const text = readFileSync15(file, "utf8");
7746
7795
  const relFile = relative5(cwd, file);
7747
7796
  sourceBytes += text.length;
7748
7797
  if (!hasEntrySignal(text)) {
@@ -7797,7 +7846,7 @@ async function extractInputMap(cwd, ts, options = {}) {
7797
7846
  for (const target of hopTargets) {
7798
7847
  if (entryFiles.has(target)) continue;
7799
7848
  try {
7800
- const text = readFileSync14(target, "utf8");
7849
+ const text = readFileSync15(target, "utf8");
7801
7850
  const sf = ts.createSourceFile(target, text, ts.ScriptTarget.Latest, true, guessScriptKind(ts, target));
7802
7851
  const bindings = buildModuleBindings(sf, ts);
7803
7852
  const called = collectInvocations(sf, ts, bindings, { file: target, owner: relative5(cwd, target), graph });
@@ -7946,7 +7995,7 @@ function getStringFlag(flags, name) {
7946
7995
  }
7947
7996
 
7948
7997
  // src/build-stamp.ts
7949
- import { chmodSync, lstatSync as lstatSync3, readFileSync as readFileSync15, readdirSync as readdirSync6, realpathSync as realpathSync6, renameSync, unlinkSync, writeFileSync as writeFileSync8 } from "fs";
7998
+ import { chmodSync, lstatSync as lstatSync3, readFileSync as readFileSync16, readdirSync as readdirSync6, realpathSync as realpathSync6, renameSync, unlinkSync, writeFileSync as writeFileSync8 } from "fs";
7950
7999
  import { join as join19, relative as relative6, sep as sep2 } from "path";
7951
8000
  var RULES_FILE_NAMES = /* @__PURE__ */ new Set(["rules.json", "patchstack.rules.json"]);
7952
8001
  var SKIP_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "out", "coverage", "tmp", "vendor"]);
@@ -7965,11 +8014,11 @@ function guardImportsRulesFile(dir, rulesName) {
7965
8014
  }
7966
8015
  for (const name of siblings) {
7967
8016
  if (!GUARD_SOURCE.test(name)) continue;
7968
- const path16 = join19(dir, name);
8017
+ const path17 = join19(dir, name);
7969
8018
  try {
7970
- const entry = lstatSync3(path16);
8019
+ const entry = lstatSync3(path17);
7971
8020
  if (!entry.isFile() || entry.isSymbolicLink() || entry.size > MAX_GUARD_SOURCE_BYTES) continue;
7972
- const source = stripComments(readFileSync15(path16, "utf8"));
8021
+ const source = stripComments(readFileSync16(path17, "utf8"));
7973
8022
  if (source.includes("@patchstack/connect/protect") && importsRules.test(source)) return true;
7974
8023
  } catch {
7975
8024
  }
@@ -7990,9 +8039,9 @@ function findRulesFile(cwd) {
7990
8039
  } catch {
7991
8040
  return { kind: "none" };
7992
8041
  }
7993
- const contained = (path16) => {
8042
+ const contained = (path17) => {
7994
8043
  try {
7995
- const real = realpathSync6(path16);
8044
+ const real = realpathSync6(path17);
7996
8045
  return real === root || real.startsWith(root + sep2);
7997
8046
  } catch {
7998
8047
  return false;
@@ -8008,25 +8057,25 @@ function findRulesFile(cwd) {
8008
8057
  }
8009
8058
  for (const name of entries) {
8010
8059
  if (name.startsWith(".")) continue;
8011
- const path16 = join19(dir, name);
8060
+ const path17 = join19(dir, name);
8012
8061
  let entry;
8013
8062
  try {
8014
- entry = lstatSync3(path16);
8063
+ entry = lstatSync3(path17);
8015
8064
  } catch {
8016
8065
  continue;
8017
8066
  }
8018
8067
  if (entry.isSymbolicLink()) continue;
8019
8068
  if (entry.isDirectory()) {
8020
- if (!SKIP_DIRECTORIES.has(name)) walk2(path16, depth + 1);
8069
+ if (!SKIP_DIRECTORIES.has(name)) walk2(path17, depth + 1);
8021
8070
  continue;
8022
8071
  }
8023
8072
  if (!entry.isFile() || !RULES_FILE_NAMES.has(name)) continue;
8024
- if (!contained(path16)) continue;
8073
+ if (!contained(path17)) continue;
8025
8074
  if (!guardImportsRulesFile(dir, name)) continue;
8026
8075
  try {
8027
- if (isRuleBundle(JSON.parse(readFileSync15(path16, "utf8")))) found.push(path16);
8076
+ if (isRuleBundle(JSON.parse(readFileSync16(path17, "utf8")))) found.push(path17);
8028
8077
  } catch {
8029
- unreadable.push(path16);
8078
+ unreadable.push(path17);
8030
8079
  }
8031
8080
  }
8032
8081
  };
@@ -8057,7 +8106,7 @@ function applyBuildStamp(cwd, id) {
8057
8106
  const file = relative6(cwd, location.path);
8058
8107
  let text;
8059
8108
  try {
8060
- text = readFileSync15(location.path, "utf8");
8109
+ text = readFileSync16(location.path, "utf8");
8061
8110
  } catch (err) {
8062
8111
  return { kind: "skipped", reason: `${file} could not be read (${err.message})` };
8063
8112
  }
@@ -8275,8 +8324,8 @@ async function runMap(flags) {
8275
8324
  }
8276
8325
 
8277
8326
  // src/setup.ts
8278
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
8279
- import path14 from "path";
8327
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "fs";
8328
+ import path15 from "path";
8280
8329
  var SCAN_COMMAND = "patchstack-connect scan";
8281
8330
  var MARK_BUILD_COMMAND = "patchstack-connect mark-build";
8282
8331
  function setupProtection(cwd) {
@@ -8301,8 +8350,8 @@ function prependHook(existing, command) {
8301
8350
  return [command, ...remaining].join(" && ");
8302
8351
  }
8303
8352
  function wireBuildScripts(cwd, packageManager) {
8304
- const target = path14.join(cwd, "package.json");
8305
- const raw = readFileSync16(target, "utf8");
8353
+ const target = path15.join(cwd, "package.json");
8354
+ const raw = readFileSync17(target, "utf8");
8306
8355
  const pkg = JSON.parse(raw);
8307
8356
  const scripts = pkg.scripts ?? {};
8308
8357
  const build = scripts.build;
@@ -8411,6 +8460,10 @@ Usage:
8411
8460
  patchstack-connect mark-build [options] Stamp built HTML with a production flag +
8412
8461
  build fingerprint, and ensure the widget
8413
8462
  tag in built pages (run as a postbuild step).
8463
+ The flag marks a page as the LIVE site, so it
8464
+ is stamped only on a production build; a local
8465
+ or preview build gets the widget tag and no
8466
+ marker (and any stale marker is removed).
8414
8467
  Looks in the framework's own output dir, an
8415
8468
  --output the build script names, then dist/,
8416
8469
  build/, out/, .output/public/, _site/ \u2014 inside
@@ -8496,8 +8549,15 @@ Options (for scan, setup, status, and uninstall):
8496
8549
  too. Never written to a file, never printed back
8497
8550
 
8498
8551
  Options (for mark-build):
8499
- --dir <path> Build output directory (default: auto-detect
8500
- dist/ build/ out/ .output/public)
8552
+ --dir <path> Build output directory (default: auto-detect the
8553
+ framework's own output dir, an --output the build
8554
+ script names, then dist/ build/ out/ .output/public/
8555
+ _site/ \u2014 inside the project only)
8556
+ --production Stamp the live-site marker on a build this command
8557
+ cannot tell is a deployment \u2014 publishing a static
8558
+ build by hand from a laptop, say. PATCHSTACK_ENVIRONMENT=production
8559
+ does the same. Never needed on a hosting platform,
8560
+ whose own build is recognised
8501
8561
 
8502
8562
  Options (for demo and demo-guide):
8503
8563
  --url <url> Test endpoint printed at the end
@@ -9171,7 +9231,7 @@ async function runGuide(args) {
9171
9231
  console.log("\u2014\u2014\u2014\u2014 Full reference guide (ships as AGENT-INSTALL.md) \u2014\u2014\u2014\u2014");
9172
9232
  console.log("");
9173
9233
  const guidePath = new URL("../AGENT-INSTALL.md", import.meta.url);
9174
- console.log(readFileSync17(guidePath, "utf8"));
9234
+ console.log(readFileSync18(guidePath, "utf8"));
9175
9235
  return 0;
9176
9236
  }
9177
9237
  async function runSetup(args) {
@@ -9346,7 +9406,7 @@ function describeStack(stack) {
9346
9406
  }
9347
9407
  function readBuildScript(cwd) {
9348
9408
  try {
9349
- const pkg = JSON.parse(readFileSync17(path15.join(cwd, "package.json"), "utf8"));
9409
+ const pkg = JSON.parse(readFileSync18(path16.join(cwd, "package.json"), "utf8"));
9350
9410
  return pkg.scripts?.build;
9351
9411
  } catch {
9352
9412
  return void 0;
@@ -9354,6 +9414,7 @@ function readBuildScript(cwd) {
9354
9414
  }
9355
9415
  async function runMarkBuild(args) {
9356
9416
  const cwd = process.cwd();
9417
+ const startedAt = Date.now();
9357
9418
  let checksum = null;
9358
9419
  let stack = null;
9359
9420
  try {
@@ -9370,6 +9431,8 @@ async function runMarkBuild(args) {
9370
9431
  );
9371
9432
  }
9372
9433
  let widgetUuid = null;
9434
+ let environment = "local";
9435
+ let environmentEvidence = [];
9373
9436
  try {
9374
9437
  const config = await resolveConfig({
9375
9438
  cwd,
@@ -9378,11 +9441,15 @@ async function runMarkBuild(args) {
9378
9441
  if (config.widget) {
9379
9442
  widgetUuid = config.siteUuid;
9380
9443
  }
9444
+ environment = config.environment;
9445
+ environmentEvidence = config.environmentEvidence ?? [];
9381
9446
  } catch (err) {
9382
9447
  console.warn(
9383
9448
  `mark-build: could not resolve the site UUID (${err.message}). Skipping the widget pass.`
9384
9449
  );
9385
9450
  }
9451
+ const forcedProduction = args.flags.get("production") === true;
9452
+ const published = forcedProduction || marksPublishedBuild(environment);
9386
9453
  const buildDirOptions = { framework: stack?.framework ?? null, buildScript: readBuildScript(cwd) };
9387
9454
  const dir = resolveBuildDir(cwd, getStringFlag(args.flags, "dir"), buildDirOptions);
9388
9455
  if (dir === null) {
@@ -9406,11 +9473,20 @@ async function runMarkBuild(args) {
9406
9473
  );
9407
9474
  return 0;
9408
9475
  }
9409
- const snippet = buildInjectionSnippet(checksum, stack);
9476
+ const staleBy = staleBuildAge(files, startedAt);
9477
+ if (staleBy !== null) {
9478
+ console.warn(
9479
+ `mark-build: nothing in ${dir} has been written in the last ${Math.round(staleBy / 6e4)} minute(s), so this looks like output from an earlier build.`
9480
+ );
9481
+ console.warn(
9482
+ "mark-build: run it as a postbuild hook (or straight after the build) so what is stamped is what was just produced."
9483
+ );
9484
+ }
9485
+ const snippet = published ? buildInjectionSnippet(checksum, stack) : "";
9410
9486
  let marked = 0;
9411
9487
  let widgetTouched = 0;
9412
9488
  for (const file of files) {
9413
- const before = readFileSync17(file, "utf8");
9489
+ const before = readFileSync18(file, "utf8");
9414
9490
  let after = injectMarker(before, snippet);
9415
9491
  if (widgetUuid !== null) {
9416
9492
  const ensured = ensureWidgetInHtml(after, widgetUuid);
@@ -9425,8 +9501,21 @@ async function runMarkBuild(args) {
9425
9501
  }
9426
9502
  }
9427
9503
  const stackSummary = stack !== null ? describeStack(stack) : null;
9504
+ if (published) {
9505
+ console.log(
9506
+ `mark-build: marked ${marked} HTML file(s) in ${dir}${checksum !== null ? ` (build ${checksum})` : ""}${widgetTouched > 0 ? `, widget tag ensured in ${widgetTouched}` : ""}${stackSummary !== null ? ` [${stackSummary}]` : ""}.`
9507
+ );
9508
+ return 0;
9509
+ }
9510
+ const because = environmentEvidence.length > 0 ? ` (${environmentEvidence.join("; ")})` : "";
9511
+ console.log(
9512
+ `mark-build: ${environment} build${because} \u2014 production marker withheld from ${files.length} HTML file(s) in ${dir}${widgetTouched > 0 ? `, widget tag ensured in ${widgetTouched}` : ""}${stackSummary !== null ? ` [${stackSummary}]` : ""}.`
9513
+ );
9514
+ console.log(
9515
+ "mark-build: the marker tells Patchstack a page is the live site, so only the build that deploys carries it. Your hosting platform's build stamps it automatically."
9516
+ );
9428
9517
  console.log(
9429
- `mark-build: marked ${marked} HTML file(s) in ${dir}${checksum !== null ? ` (build ${checksum})` : ""}${widgetTouched > 0 ? `, widget tag ensured in ${widgetTouched}` : ""}${stackSummary !== null ? ` [${stackSummary}]` : ""}.`
9518
+ "mark-build: publishing this directory by hand? Re-run with --production (or set PATCHSTACK_ENVIRONMENT=production) so the deployed pages carry it."
9430
9519
  );
9431
9520
  return 0;
9432
9521
  }