@juspay/neurolink 12.44.5 → 12.44.7

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 = [];
@@ -98,7 +98,9 @@ export async function saveAccountCooldown(accountKey, coolingUntil, reason) {
98
98
  await ensureAccountCooldownsLoaded();
99
99
  // Another worker (a draining one during a rolling restart) may have written
100
100
  // the file since this one loaded it, so the change folds onto the file as
101
- // it is now rather than onto this worker's copy.
101
+ // it is now rather than onto this worker's copy. Best-effort: the mutex is
102
+ // per process, so two workers writing within the same few ms can still
103
+ // lose one update.
102
104
  const onDisk = await readCooldownsFromDisk(memoryCache);
103
105
  memoryCache = onDisk;
104
106
  const current = onDisk[accountKey];
@@ -116,7 +118,8 @@ export async function clearAccountCooldown(accountKey, expectedCoolingUntil) {
116
118
  await mutationMutex.runExclusive(async () => {
117
119
  await ensureAccountCooldownsLoaded();
118
120
  // Compare against the file, not this worker's copy: another worker may
119
- // have extended this cooldown since, and that one must survive.
121
+ // have extended this cooldown since, and that one must survive. Same
122
+ // best-effort limit as saveAccountCooldown: no cross-process lock.
120
123
  const onDisk = await readCooldownsFromDisk(memoryCache);
121
124
  memoryCache = onDisk;
122
125
  const current = onDisk[accountKey];
@@ -387,6 +387,8 @@ async function flushToDisk() {
387
387
  // Another worker (a draining one during a rolling restart) may have
388
388
  // written the file since this one loaded it: fold only this worker's
389
389
  // changes onto the file as it is now, never rewrite it from this copy.
390
+ // Best-effort: the mutexes are per process, so two workers flushing
391
+ // within the same few ms can still lose one update.
390
392
  const onDisk = await readQuotasFromDisk(filePath, fallback);
391
393
  const merged = { ...onDisk };
392
394
  for (const [key, quota] of Object.entries(flushing)) {
@@ -343,10 +343,9 @@ function codexSessionId(body) {
343
343
  return undefined;
344
344
  }
345
345
  const fields = parsed;
346
- const sessionId = fields.session_id ?? fields.parent_session_id;
347
- return typeof sessionId === "string" && sessionId.length > 0
348
- ? sessionId
349
- : undefined;
346
+ // `??` would let an empty or non-string session_id shadow a usable
347
+ // parent_session_id, so each field has to qualify on its own.
348
+ return [fields.session_id, fields.parent_session_id].find((value) => typeof value === "string" && value.length > 0);
350
349
  }
351
350
  /** Convert a Claude Messages request into the ChatGPT Codex Responses shape. */
352
351
  export function convertClaudeRequestToCodex(body, model, reasoningEffort) {
@@ -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;