@juspay/neurolink 12.44.4 → 12.44.6

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.
@@ -9,7 +9,7 @@ import chalk from "chalk";
9
9
  import ora from "ora";
10
10
  import { buildProxyHealthResponse, createProxyReadinessState, markProxyDrainingForUpdate, markProxyReady, resumeProxyConnections, waitForProxyReadiness, } from "../../proxy/proxyHealth.js";
11
11
  import { logger } from "../../utils/logger.js";
12
- import { applyAllClients, restoreAllClients, } from "../proxy-clients/registry.js";
12
+ import { applyAllClients, applyClientsOnProxyStart, restoreAllClients, } from "../proxy-clients/registry.js";
13
13
  import { resolveProxyConfigPath } from "../../proxy/proxyConfig.js";
14
14
  import { redactUrlsInText, sanitizeForLog, } from "../../utils/logSanitize.js";
15
15
  import { raceWithAbort, withTimeout, } from "../../utils/async/withTimeout.js";
@@ -23,7 +23,7 @@ import { anthropicAccountKeysEqual, createAccountAllowlist, isAccountAllowed, LE
23
23
  import { resolveProxyStatusAccountIdentity } from "../../proxy/codexAccountUsage.js";
24
24
  import { beginProxyRequest, consumeInternalProxyRequest, releaseProxyRequestAccounting, withProxyFinalLogOwnership, getProxyActivitySnapshot, observeProxyFinalLog, takeProxyResponseObservers, trackProxyResponse, } from "../../proxy/proxyActivity.js";
25
25
  import { configureProxyLifecycleLogger, flushProxyLifecycleEvents, persistProxyLifecycleAcceptance, getProxyLifecycleLoggerSnapshot, hashProxyLifecycleSessionId, logProxyLifecycleEvent, } from "../../proxy/proxyLifecycle.js";
26
- import { describeInstallFailure, assertProxyServiceInstallIdle, probeProxyLaunchdPresence, inspectProxyPackage, isProxyServiceEnvironmentKey, parseProxyServiceInstallSettings, installStagedProxyPackage, readProxyPackageSelection, resolveProxyWorkerPackage, selectProxyPackage, writeProxyPackageLauncher, isTransientInstallFailure, resolveGlobalInstaller, validateInstalledVersion, } from "../../proxy/globalInstaller.js";
26
+ import { describeInstallFailure, assertProxyServiceInstallIdle, probeProxyLaunchdPresence, inspectProxyPackage, isProxyServiceEnvironmentKey, parseProxyServiceInstallSettings, installStagedProxyPackage, prepareProxyPackageUpgrade, readProxyPackageSelection, resolveProxyWorkerPackage, selectProxyPackage, writeProxyPackageLauncher, isTransientInstallFailure, resolveGlobalInstaller, validateInstalledVersion, } from "../../proxy/globalInstaller.js";
27
27
  import { startUpdaterWorkerSupervisor } from "../../proxy/updaterSupervisor.js";
28
28
  import { openProxyWorkerLog } from "../../proxy/workerLog.js";
29
29
  import { startRollingProxyServer } from "../../proxy/rollingProxyServer.js";
@@ -2933,9 +2933,7 @@ async function startProxyRuntime(params) {
2933
2933
  logger.always(` ${chalk.bold("Env File:")} ${chalk.cyan(params.loadedEnvFile)}`);
2934
2934
  }
2935
2935
  if (!isDev) {
2936
- for (const result of await applyAllClients(url, {
2937
- configPath: params.configPath,
2938
- })) {
2936
+ for (const result of await applyClientsOnProxyStart(url, { configPath: params.configPath }, managedByLaunchd)) {
2939
2937
  if (result.error) {
2940
2938
  // Visible, not debug-level. A client whose config could not be written
2941
2939
  // will keep talking to its own upstream, which looks like the proxy
@@ -2956,6 +2954,9 @@ async function startProxyRuntime(params) {
2956
2954
  logger.always(chalk.dim(` Restart ${result.displayName} to connect through proxy`));
2957
2955
  }
2958
2956
  }
2957
+ if (managedByLaunchd) {
2958
+ logger.always(" Service startup preserves client settings; use 'neurolink proxy setup' to change client routing.");
2959
+ }
2959
2960
  }
2960
2961
  else {
2961
2962
  logger.always(chalk.dim(" ⊘ Dev mode: skipping client auto-configuration"));
@@ -4270,20 +4271,36 @@ export const proxyGuardCommand = {
4270
4271
  return;
4271
4272
  }
4272
4273
  try {
4273
- // Retain a validated rollback even when migrating from a mutable
4274
- // global package whose on-disk version already differs from live.
4275
- previousPackage = await installStagedProxyPackage({
4276
- version: runningVersion,
4277
- packagesDir: PROXY_PACKAGES_DIR,
4278
- installer,
4279
- });
4274
+ // Keep the exact serving tree, including a same-version local
4275
+ // build. Restaging by version would discard its edits and rollback.
4276
+ if (previousPackage?.version !== runningVersion) {
4277
+ try {
4278
+ const original = inspectProxyPackage(process.argv[1]);
4279
+ if (original.version === runningVersion) {
4280
+ previousPackage = original;
4281
+ }
4282
+ }
4283
+ catch {
4284
+ // A mutable global entry may have disappeared since startup.
4285
+ }
4286
+ }
4287
+ if (previousPackage?.version !== runningVersion) {
4288
+ previousPackage = await installStagedProxyPackage({
4289
+ version: runningVersion,
4290
+ packagesDir: PROXY_PACKAGES_DIR,
4291
+ installer,
4292
+ });
4293
+ }
4280
4294
  if (!isCurrentUpdateOwner()) {
4281
4295
  return;
4282
4296
  }
4283
- candidatePackage = await installStagedProxyPackage({
4297
+ candidatePackage = await prepareProxyPackageUpgrade({
4284
4298
  version: result.latestVersion,
4285
4299
  packagesDir: PROXY_PACKAGES_DIR,
4286
4300
  installer,
4301
+ activePackage: previousPackage,
4302
+ isCurrentOwner: isCurrentUpdateAttemptOwner,
4303
+ onPolyfills: ({ applied, alreadyIncluded }) => logger.always(`[updater] local polyfills: ${applied.length} files applied, ${alreadyIncluded.length} already included in release`),
4287
4304
  onProgress: ({ elapsedMs, outputBytes }) => logger.debug(`[updater] staged install progress elapsedMs=${elapsedMs} outputBytes=${outputBytes}`),
4288
4305
  });
4289
4306
  }
@@ -0,0 +1,4 @@
1
+ import type { CommandModule } from "yargs";
2
+ import type { ProxyPolyfillArgs } from "../../types/index.js";
3
+ /** Record the base of a locally patched package without changing running services. */
4
+ export declare const proxyPolyfillCommand: CommandModule<object, ProxyPolyfillArgs>;
@@ -0,0 +1,55 @@
1
+ import { inspectProxyPackage } from "../../proxy/globalInstaller.js";
2
+ import { captureProxyPackageBaseline } from "../../proxy/proxyPackagePolyfills.js";
3
+ /** Record the base of a locally patched package without changing running services. */
4
+ export const proxyPolyfillCommand = {
5
+ command: "polyfill <action>",
6
+ describe: "Preserve local proxy compatibility edits across staged upgrades",
7
+ builder: (yargs) => yargs
8
+ .positional("action", {
9
+ choices: ["capture"],
10
+ type: "string",
11
+ demandOption: true,
12
+ })
13
+ .option("base", {
14
+ type: "string",
15
+ demandOption: true,
16
+ description: "CLI entry script of the pristine package used for the local edit",
17
+ })
18
+ .option("patched", {
19
+ type: "string",
20
+ demandOption: true,
21
+ description: "CLI entry script of the locally patched package",
22
+ })
23
+ .option("format", {
24
+ choices: ["text", "json"],
25
+ type: "string",
26
+ default: "text",
27
+ })
28
+ .example("neurolink proxy polyfill capture --base /original/dist/cli/index.js --patched /local/dist/cli/index.js", "Record the exact original files so later upgrades can apply only the local diff"),
29
+ handler: async (argv) => {
30
+ try {
31
+ const base = inspectProxyPackage(argv.base);
32
+ const patched = inspectProxyPackage(argv.patched);
33
+ const files = captureProxyPackageBaseline(base, patched);
34
+ const result = {
35
+ captured: true,
36
+ baseVersion: base.version,
37
+ patchedVersion: patched.version,
38
+ files,
39
+ };
40
+ console.info(argv.format === "json"
41
+ ? JSON.stringify(result)
42
+ : `Recorded ${files.length} local proxy polyfill file(s). Upgrades will apply remaining diff hunks, skip included fixes, and retain the current worker on conflicts.`);
43
+ }
44
+ catch (error) {
45
+ const message = error instanceof Error
46
+ ? error.message
47
+ : "Proxy polyfill capture failed";
48
+ console.error(argv.format === "json"
49
+ ? JSON.stringify({ captured: false, message })
50
+ : message);
51
+ process.exitCode = 1;
52
+ }
53
+ },
54
+ };
55
+ //# sourceMappingURL=proxyPolyfill.js.map
@@ -24,6 +24,7 @@ import { TelemetryCommandFactory } from "./commands/telemetry.js";
24
24
  import { proxyStartCommand, proxyStatusCommand, proxyTelemetryCommand, proxySetupCommand, proxyGuardCommand, proxyInstallCommand, proxyUninstallCommand, } from "./commands/proxy.js";
25
25
  import { proxyAnalyzeCommand } from "./commands/proxyAnalyze.js";
26
26
  import { proxyRestartCommand } from "./commands/proxyRestart.js";
27
+ import { proxyPolyfillCommand } from "./commands/proxyPolyfill.js";
27
28
  import { proxyShareCommand } from "./commands/proxyShare.js";
28
29
  import { proxyPeerCommand } from "./commands/proxyPeer.js";
29
30
  import { proxyExposeCommand } from "./commands/proxyExpose.js";
@@ -229,6 +230,7 @@ export function initializeCliParser() {
229
230
  .command(proxyStartCommand)
230
231
  .command(proxyStatusCommand)
231
232
  .command(proxyRestartCommand)
233
+ .command(proxyPolyfillCommand)
232
234
  .command(proxyShareCommand)
233
235
  .command(proxyPeerCommand)
234
236
  .command(proxyExposeCommand)
@@ -239,7 +241,7 @@ export function initializeCliParser() {
239
241
  .command(proxyGuardCommand)
240
242
  .command(proxyInstallCommand)
241
243
  .command(proxyUninstallCommand)
242
- .demandCommand(1, "Please specify a proxy subcommand: start, status, restart, share <create|provision|url|list|status|pause|resume|revoke|topup|set|link|rotate|level|note|notes|receipts|delete>, peer <add|request|sync|receipts|net|redeem|list|status|test|remove|pause|resume|set>, expose, analyze, replay <export|compare>, telemetry <setup|start|stop|status|logs|import-dashboard>, setup, guard, install, or uninstall"),
244
+ .demandCommand(1, "Please specify a proxy subcommand: start, status, restart, polyfill capture, share <create|provision|url|list|status|pause|resume|revoke|topup|set|link|rotate|level|note|notes|receipts|delete>, peer <add|request|sync|receipts|net|redeem|list|status|test|remove|pause|resume|set>, expose, analyze, replay <export|compare>, telemetry <setup|start|stop|status|logs|import-dashboard>, setup, guard, install, or uninstall"),
243
245
  handler: () => { },
244
246
  })
245
247
  // Evaluate Command Group - Using EvaluateCommandFactory
@@ -15,5 +15,7 @@ export declare const PROXY_CLIENT_CONFIGURATORS: readonly CliProxyClientConfigur
15
15
  * while the setup wizard prints a visible warning.
16
16
  */
17
17
  export declare function applyAllClients(proxyBaseUrl: string, options?: CliProxyClientApplyOptions): Promise<CliProxyClientApplyResult[]>;
18
+ /** Service replacements own the server process, not the user's client routing. */
19
+ export declare function applyClientsOnProxyStart(proxyBaseUrl: string, options: CliProxyClientApplyOptions, managedByLaunchd: boolean): Promise<CliProxyClientApplyResult[]>;
18
20
  /** Restore every client's previous configuration. See applyAllClients. */
19
21
  export declare function restoreAllClients(proxyBaseUrl: string): Promise<CliProxyClientRestoreResult[]>;
@@ -77,6 +77,10 @@ export async function applyAllClients(proxyBaseUrl, options) {
77
77
  }
78
78
  return results;
79
79
  }
80
+ /** Service replacements own the server process, not the user's client routing. */
81
+ export async function applyClientsOnProxyStart(proxyBaseUrl, options, managedByLaunchd) {
82
+ return managedByLaunchd ? [] : applyAllClients(proxyBaseUrl, options);
83
+ }
80
84
  /** Restore every client's previous configuration. See applyAllClients. */
81
85
  export async function restoreAllClients(proxyBaseUrl) {
82
86
  const results = [];
@@ -579,9 +579,9 @@ const HAND_DESCRIPTORS = [
579
579
  // `timeoutMs`.
580
580
  timeouts: { decideMs: 10_000 },
581
581
  // The server reads 262,144 input tokens in all and answers an over-long
582
- // request with an explicit 400, never a silent truncation. The state and the
583
- // questions were measured to count toward it; images are billed as input
584
- // tokens and presumably count too. The window below is deliberately lower: a
582
+ // request with an explicit 400, never a silent truncation. The state, the
583
+ // questions and the images were all measured to count toward it, an image at
584
+ // one token for each 32 x 32 tile. The window below is deliberately lower: a
585
585
  // state of 100,000 tokens takes about 7s of the 10s above (interpolated from
586
586
  // those points), and a much larger one would outlast it and be retried into
587
587
  // the same wait. The estimate is about four characters per token. Measured
@@ -70,8 +70,14 @@ function isPerplexityApiHost(baseURL) {
70
70
  * The model server answers input past its limit with a 400, not the 413 the
71
71
  * gateway documents, so the kind comes from the text. `error.code` cannot be
72
72
  * used: it is a string, a number or null depending on which layer answered.
73
+ *
74
+ * The wording depends on what was sent. Text alone is refused with "Input
75
+ * length (262144) exceeds or equals model's maximum context length (262144)",
76
+ * the figure in brackets being the limit and not the size sent; a request with
77
+ * images is refused with "Total input tokens (A text + B vision = C) exceeds
78
+ * maximum context length (262144)". Both are matched.
73
79
  */
74
- const OVER_LENGTH_MESSAGE = /exceeds or equals model's maximum context length/i;
80
+ const OVER_LENGTH_MESSAGE = /exceeds(?: or equals)?(?: model's)? maximum context length/i;
75
81
  /**
76
82
  * Only 401 is `authentication`, and so only 401 trips the breaker. Every other
77
83
  * 4xx is something the caller or an account owner can fix without restarting
@@ -1,4 +1,4 @@
1
- import type { ProxyServiceInstallSettings, ProxyPackageSelection, ProxyStagedInstallOptions, GlobalInstallerExecFile, GlobalInstallerKind, GlobalInstallerResolution, InstalledVersionValidation, ResolveGlobalInstallerOptions, ValidateInstalledVersionOptions } from "../types/index.js";
1
+ import type { ProxyServiceInstallSettings, ProxyPackageSelection, ProxyStagedInstallOptions, ProxyPackageUpgradeOptions, GlobalInstallerExecFile, GlobalInstallerKind, GlobalInstallerResolution, InstalledVersionValidation, ResolveGlobalInstallerOptions, ValidateInstalledVersionOptions } from "../types/index.js";
2
2
  /** Resolve a package manager that can update the installation currently running. */
3
3
  export declare function resolveGlobalInstaller(options?: ResolveGlobalInstallerOptions): GlobalInstallerResolution;
4
4
  export declare function getGlobalInstallArgs(kind: GlobalInstallerKind, packageSpec: string): string[];
@@ -32,6 +32,8 @@ export declare function selectProxyPackage(packagesDir: string, selection: Proxy
32
32
  export declare function writeProxyPackageLauncher(path: string, selection: ProxyPackageSelection, isCurrentOwner?: () => boolean): void;
33
33
  /** Install in a private tree, then publish the immutable directory after validation. */
34
34
  export declare function installStagedProxyPackage(options: ProxyStagedInstallOptions): Promise<ProxyPackageSelection>;
35
+ /** Preserve local runtime diff hunks before any launcher or live selection changes. */
36
+ export declare function prepareProxyPackageUpgrade(options: ProxyPackageUpgradeOptions): Promise<ProxyPackageSelection>;
35
37
  /** Only operator runtime settings survive reinstall, never worker IPC identity. */
36
38
  export declare function isProxyServiceEnvironmentKey(name: string): boolean;
37
39
  /** Parse plutil JSON without exposing credentials or invoking the saved launcher. */
@@ -1,9 +1,10 @@
1
1
  import { execFileSync as nodeExecFileSync, spawn as nodeSpawn, } from "node:child_process";
2
2
  import { accessSync, constants, existsSync, realpathSync, readFileSync, mkdirSync, writeFileSync, renameSync, chmodSync, rmSync, } from "node:fs";
3
- import { mkdir, mkdtemp, rename, rm, writeFile } from "node:fs/promises";
3
+ import { cp, mkdir, mkdtemp, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
- import { randomUUID } from "node:crypto";
5
+ import { createHash, randomUUID } from "node:crypto";
6
6
  import { basename, dirname, isAbsolute, join, resolve, relative, } from "node:path";
7
+ import { changedProxyRuntimeFiles, proxyPackageRoot, readProxyPackageBaseline, reconcileProxyPackagePolyfills, snapshotProxyPackage, writeProxyPackageBaseline, writeProxyPolyfilledFile, } from "./proxyPackagePolyfills.js";
7
8
  function runText(execFileSync, bin, args) {
8
9
  return String(execFileSync(bin, args, {
9
10
  encoding: "utf8",
@@ -373,7 +374,10 @@ export function selectProxyPackage(packagesDir, selection, isCurrentOwner) {
373
374
  const state = {
374
375
  schemaVersion: 1,
375
376
  active: selection,
376
- previous: current.active && current.active.version !== selection.version
377
+ previous: current.active &&
378
+ (current.active.version !== selection.version ||
379
+ current.active.entryScript !== selection.entryScript ||
380
+ current.active.nodePath !== selection.nodePath)
377
381
  ? current.active
378
382
  : current.previous,
379
383
  };
@@ -539,7 +543,8 @@ export async function installStagedProxyPackage(options) {
539
543
  }
540
544
  });
541
545
  });
542
- validate(staging);
546
+ const stagedSelection = validate(staging);
547
+ writeProxyPackageBaseline(stagedSelection, snapshotProxyPackage(stagedSelection));
543
548
  await rename(staging, destination);
544
549
  return validate(destination);
545
550
  }
@@ -547,6 +552,148 @@ export async function installStagedProxyPackage(options) {
547
552
  await rm(staging, { recursive: true, force: true });
548
553
  }
549
554
  }
555
+ /** Registry comparison must never inherit an existing directory's dependencies. */
556
+ async function installFreshProxyRegistryPackage(options) {
557
+ if (!/^\d+\.\d+\.\d+$/.test(options.version)) {
558
+ throw new Error("Invalid proxy package version");
559
+ }
560
+ await mkdir(options.packagesDir, { recursive: true, mode: 0o700 });
561
+ const container = await mkdtemp(join(options.packagesDir, `.registry-${options.version}-`));
562
+ try {
563
+ const selection = await installStagedProxyPackage({
564
+ ...options,
565
+ packagesDir: container,
566
+ });
567
+ return { selection, container };
568
+ }
569
+ catch (error) {
570
+ await rm(container, { recursive: true, force: true });
571
+ throw error;
572
+ }
573
+ }
574
+ /** Preserve local runtime diff hunks before any launcher or live selection changes. */
575
+ export async function prepareProxyPackageUpgrade(options) {
576
+ const assertOwner = () => assertPackageSelectionOwner(options.isCurrentOwner);
577
+ assertOwner();
578
+ const active = options.activePackage;
579
+ let baseline = readProxyPackageBaseline(active);
580
+ if (!baseline) {
581
+ // Legacy packages need a clean registry comparison. Never invent a baseline
582
+ // from edited files: an unknown local build must remain serving until its
583
+ // operator records the actual base with `proxy polyfill capture`.
584
+ const original = await installFreshProxyRegistryPackage({
585
+ ...options,
586
+ version: active.version,
587
+ });
588
+ let retainReference = false;
589
+ try {
590
+ assertOwner();
591
+ baseline = readProxyPackageBaseline(original.selection);
592
+ if (!baseline) {
593
+ throw new Error("Pristine registry package baseline is missing");
594
+ }
595
+ if (changedProxyRuntimeFiles(baseline, snapshotProxyPackage(active)).length) {
596
+ retainReference = true;
597
+ throw new Error(`Active proxy contains local changes without a recorded base; upgrade retained the serving package. Record its actual original package with 'proxy polyfill capture --base <original-entry> --patched <local-entry>'. Downloaded registry reference: ${original.selection.entryScript}`);
598
+ }
599
+ writeProxyPackageBaseline(active, baseline);
600
+ }
601
+ finally {
602
+ if (!retainReference) {
603
+ await rm(original.container, { recursive: true, force: true });
604
+ }
605
+ }
606
+ }
607
+ const local = snapshotProxyPackage(active);
608
+ // Also rejects unsupported local dependency/entrypoint changes.
609
+ changedProxyRuntimeFiles(baseline, local);
610
+ const fresh = await installFreshProxyRegistryPackage(options);
611
+ try {
612
+ const candidate = fresh.selection;
613
+ assertOwner();
614
+ const candidateBase = readProxyPackageBaseline(candidate);
615
+ if (!candidateBase ||
616
+ changedProxyRuntimeFiles(candidateBase, snapshotProxyPackage(candidate))
617
+ .length) {
618
+ throw new Error("Candidate proxy package has no trustworthy pristine baseline");
619
+ }
620
+ const { files, report } = reconcileProxyPackagePolyfills(baseline, local, candidateBase);
621
+ const assertLocalUnchanged = () => {
622
+ assertOwner();
623
+ if (JSON.stringify(snapshotProxyPackage(active)) !== JSON.stringify(local)) {
624
+ throw new Error("Active proxy files changed while preparing the upgrade; activation refused");
625
+ }
626
+ };
627
+ assertLocalUnchanged();
628
+ if (!report.applied.length) {
629
+ const destination = join(options.packagesDir, `${options.version}-release-${randomUUID()}`);
630
+ await rename(resolve(proxyPackageRoot(candidate.entryScript), "../../.."), destination);
631
+ const selected = inspectProxyPackage(join(destination, "node_modules", "@juspay", "neurolink", candidateBase.entryRelative));
632
+ assertOwner();
633
+ options.onPolyfills?.(report);
634
+ return selected;
635
+ }
636
+ const digest = createHash("sha256")
637
+ .update(JSON.stringify({ version: options.version, files }))
638
+ .digest("hex")
639
+ .slice(0, 16);
640
+ const destination = join(options.packagesDir, `${options.version}-polyfills-${digest}-${randomUUID()}`);
641
+ const candidateRoot = proxyPackageRoot(candidate.entryScript);
642
+ const expected = { ...candidateBase.files };
643
+ for (const [path, content] of Object.entries(files)) {
644
+ if (content === null) {
645
+ delete expected[path];
646
+ }
647
+ else {
648
+ expected[path] = content;
649
+ }
650
+ }
651
+ const validateCopy = (root) => {
652
+ const selection = inspectProxyPackage(join(root, "node_modules", "@juspay", "neurolink", candidateBase.entryRelative));
653
+ const snapshot = snapshotProxyPackage(selection);
654
+ if (selection.version !== options.version ||
655
+ snapshot.manifest !== candidateBase.manifest ||
656
+ Object.keys({ ...snapshot.files, ...expected }).some((path) => snapshot.files[path] !== expected[path])) {
657
+ throw new Error("Polyfilled proxy package does not match its validated plan");
658
+ }
659
+ for (const path of report.applied) {
660
+ if (files[path] !== null && /\.[cm]?js$/.test(path)) {
661
+ (options.execFileSync ?? nodeExecFileSync)(selection.nodePath, ["--check", join(proxyPackageRoot(selection.entryScript), path)], { timeout: 10_000, stdio: "pipe" });
662
+ }
663
+ }
664
+ return selection;
665
+ };
666
+ const staging = await mkdtemp(join(options.packagesDir, `.polyfill-${options.version}-`));
667
+ try {
668
+ await cp(resolve(candidateRoot, "../../.."), staging, {
669
+ recursive: true,
670
+ mode: constants.COPYFILE_FICLONE,
671
+ verbatimSymlinks: true,
672
+ });
673
+ const root = join(staging, "node_modules", "@juspay", "neurolink");
674
+ for (const [path, content] of Object.entries(files)) {
675
+ if (content === null) {
676
+ await rm(join(root, path));
677
+ }
678
+ else {
679
+ writeProxyPolyfilledFile(root, path, content);
680
+ }
681
+ }
682
+ validateCopy(staging);
683
+ assertLocalUnchanged();
684
+ await rename(staging, destination);
685
+ const selection = validateCopy(destination);
686
+ options.onPolyfills?.(report);
687
+ return selection;
688
+ }
689
+ finally {
690
+ await rm(staging, { recursive: true, force: true });
691
+ }
692
+ }
693
+ finally {
694
+ await rm(fresh.container, { recursive: true, force: true });
695
+ }
696
+ }
550
697
  /** Only operator runtime settings survive reinstall, never worker IPC identity. */
551
698
  export function isProxyServiceEnvironmentKey(name) {
552
699
  return ((name.startsWith("OTEL_") ||
@@ -0,0 +1,18 @@
1
+ import type { ProxyPackageBaseline, ProxyPackagePolyfillReport, ProxyPackageSelection } from "../types/index.js";
2
+ /** Locate the package without importing its executable or provider graph. */
3
+ export declare function proxyPackageRoot(entryScript: string): string;
4
+ /** Bounded baseline of shipped proxy code; operator config and dependencies are excluded. */
5
+ export declare function snapshotProxyPackage(selection: ProxyPackageSelection): ProxyPackageBaseline;
6
+ /** Invalid or missing baseline must never be silently replaced with edited files. */
7
+ export declare function readProxyPackageBaseline(selection: ProxyPackageSelection): ProxyPackageBaseline | null;
8
+ export declare function writeProxyPackageBaseline(selection: ProxyPackageSelection, baseline: ProxyPackageBaseline): void;
9
+ /** Operator supplies the pristine base for a legacy local build; this does not activate it. */
10
+ export declare function captureProxyPackageBaseline(base: ProxyPackageSelection, patched: ProxyPackageSelection): string[];
11
+ export declare function changedProxyRuntimeFiles(base: ProxyPackageBaseline, current: ProxyPackageBaseline): string[];
12
+ /** Apply exact local hunks, leaving independent upstream changes intact. */
13
+ export declare function reconcileProxyPackagePolyfills(base: ProxyPackageBaseline, local: ProxyPackageBaseline, candidate: ProxyPackageBaseline): {
14
+ files: Record<string, string | null>;
15
+ report: ProxyPackagePolyfillReport;
16
+ };
17
+ /** Writes are confined to a new staged copy, never the serving package. */
18
+ export declare function writeProxyPolyfilledFile(root: string, path: string, content: string): void;