@juspay/neurolink 12.14.4 → 12.14.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.
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import type { CommandModule } from "yargs";
13
13
  import type { Hono } from "hono";
14
- import type { AccountAllowlist, LoadedProxyConfig, ModelRouterInterface, ProxyGuardArgs, ProxyHealthProbe, ProxyNeurolinkRuntime, ProxyStartArgs, ProxyStartStrategy, ProxySupervisorState, ProxyStatusArgs, ProxyTelemetryArgs, ProxyReadinessState } from "../../types/index.js";
14
+ import type { AccountAllowlist, LoadedProxyConfig, ModelRouterInterface, ProxyGuardArgs, ProxyHealthProbe, ProxyNeurolinkRuntime, ProxyStartArgs, ProxyStartStrategy, ProxyRestartSupervisorState as ProxySupervisorState, ProxyStatusArgs, ProxyTelemetryArgs, ProxyReadinessState } from "../../types/index.js";
15
15
  import { ProxyRuntimeConfigStore } from "../../proxy/runtimeConfig.js";
16
16
  /**
17
17
  * Drop a supervisor `version` that is not a string.
@@ -24,6 +24,7 @@ import { describeInstallFailure, getGlobalInstallArgs, isTransientInstallFailure
24
24
  import { startUpdaterWorkerSupervisor } from "../../proxy/updaterSupervisor.js";
25
25
  import { openProxyWorkerLog } from "../../proxy/workerLog.js";
26
26
  import { startRollingProxyServer } from "../../proxy/rollingProxyServer.js";
27
+ import { startProxyRestartControl } from "../../proxy/restartControl.js";
27
28
  import { isProxyAuxiliaryRequest } from "../../proxy/proxyRequestKind.js";
28
29
  import { spawnProxySocketWorker } from "../../proxy/rollingWorkerProcess.js";
29
30
  import { PROXY_ROLLING_SUPERVISOR_ENV, PROXY_SOCKET_WORKER_ENV, } from "../../proxy/rollingWorkerProtocol.js";
@@ -1079,6 +1080,8 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
1079
1080
  requestMetadata.set(c.req.raw, metadata);
1080
1081
  const stopObservingFinalLog = observeProxyFinalLog(metadata.requestId, (entry) => {
1081
1082
  metadata.terminalResult = entry;
1083
+ }, (entry) => {
1084
+ metadata.lastUpstreamAttempt = { ...entry };
1082
1085
  });
1083
1086
  const finishActivity = metadata.rejectForUpdate
1084
1087
  ? () => undefined
@@ -1306,7 +1309,8 @@ export async function createProxyStartApp(params) {
1306
1309
  const recordRuntimeError = async (metadata, status, errorType, errorMessage, options) => {
1307
1310
  const clientMessage = options?.clientMessage ?? errorMessage;
1308
1311
  const clientErrorType = options?.clientErrorType ?? errorType;
1309
- recordFinalError(status, PROXY_INTERNAL_ACCOUNT_LABEL, PROXY_INTERNAL_ACCOUNT_TYPE, {
1312
+ const attempt = metadata.lastUpstreamAttempt;
1313
+ recordFinalError(status, attempt?.account ?? PROXY_INTERNAL_ACCOUNT_LABEL, attempt?.accountType ?? PROXY_INTERNAL_ACCOUNT_TYPE, {
1310
1314
  requestId: metadata.requestId,
1311
1315
  errorType,
1312
1316
  errorCode: options?.errorCode,
@@ -1322,8 +1326,13 @@ export async function createProxyStartApp(params) {
1322
1326
  model: metadata.model,
1323
1327
  stream: metadata.stream,
1324
1328
  toolCount: metadata.toolCount,
1325
- account: "",
1326
- accountType: "proxy-runtime",
1329
+ account: attempt?.account ?? "",
1330
+ accountType: attempt?.accountType ?? "proxy-runtime",
1331
+ accountKey: attempt?.accountKey,
1332
+ provider: attempt?.provider,
1333
+ transportScope: attempt?.transportScope,
1334
+ traceId: attempt?.traceId,
1335
+ spanId: attempt?.spanId,
1327
1336
  responseStatus: status,
1328
1337
  responseTimeMs: Date.now() - metadata.startedAt,
1329
1338
  errorType,
@@ -1392,6 +1401,15 @@ export async function createProxyStartApp(params) {
1392
1401
  .json()
1393
1402
  .catch(() => ({ action: undefined }));
1394
1403
  if (payload.action === "drain") {
1404
+ // A rolling worker must keep admitting until the supervisor has a ready
1405
+ // replacement. The legacy global drain can otherwise strand the listener
1406
+ // behind maintenance responses when its caller stalls or disappears.
1407
+ if (isProxySocketWorkerProcess()) {
1408
+ return c.json({
1409
+ error: "rolling_restart_required",
1410
+ message: "Use neurolink proxy restart; global update drain is disabled for rolling workers.",
1411
+ }, 409);
1412
+ }
1395
1413
  if (!markProxyDrainingForUpdate(readiness)) {
1396
1414
  return c.json({ error: "proxy_not_ready" }, 409);
1397
1415
  }
@@ -2769,6 +2787,7 @@ async function runLaunchdProxySupervisor(argv, spinner) {
2769
2787
  filePrefix: "proxy-supervisor",
2770
2788
  });
2771
2789
  let currentUpdaterPid;
2790
+ let restartControl;
2772
2791
  const rollingServer = await startRollingProxyServer({
2773
2792
  onEvent: (event) => logProxyLifecycleEvent({
2774
2793
  event: "supervisor_event",
@@ -2799,6 +2818,7 @@ async function runLaunchdProxySupervisor(argv, spinner) {
2799
2818
  version: PROXY_VERSION,
2800
2819
  updaterPid: currentUpdaterPid,
2801
2820
  rolling: snapshot,
2821
+ restartControl: restartControl?.identity,
2802
2822
  });
2803
2823
  },
2804
2824
  log: (message) => logger.always(message),
@@ -2835,13 +2855,46 @@ async function runLaunchdProxySupervisor(argv, spinner) {
2835
2855
  };
2836
2856
  process.on("SIGUSR2", activatePendingUpdate);
2837
2857
  const readinessHost = host === "0.0.0.0" ? "127.0.0.1" : host;
2858
+ try {
2859
+ restartControl = await startProxyRestartControl({
2860
+ stateDir: join(homedir(), ".neurolink"),
2861
+ server: rollingServer,
2862
+ log: (message) => logger.warn(message),
2863
+ isUpdatePending: () => !!rollingReplacement || !!loadUpdateState()?.pendingRestartVersion,
2864
+ getInstalledVersion: async () => {
2865
+ const { execFile } = await import("node:child_process");
2866
+ const { promisify } = await import("node:util");
2867
+ const { stdout } = await promisify(execFile)(TRAMPOLINE_PATH, ["--version"], { timeout: 5_000, maxBuffer: 65_536 });
2868
+ return stdout.trim();
2869
+ },
2870
+ getStatus: async () => {
2871
+ const probeHost = readinessHost === "::" ? "::1" : readinessHost;
2872
+ const response = await fetch(`http://${probeHost.includes(":") ? `[${probeHost}]` : probeHost}:${rollingServer.address.port}/status`, {
2873
+ headers: { connection: "close" },
2874
+ signal: AbortSignal.timeout(3_000),
2875
+ });
2876
+ if (!response.ok) {
2877
+ throw new Error("Serving status is unavailable.");
2878
+ }
2879
+ return response.json();
2880
+ },
2881
+ });
2882
+ }
2883
+ catch (error) {
2884
+ // A control-plane setup failure must not stop an otherwise serving proxy.
2885
+ logger.warn(`[proxy-supervisor] safe restart control unavailable: ${error instanceof Error ? error.message : String(error)}`);
2886
+ }
2838
2887
  const updatePersistedUpdaterPid = (updaterPid) => {
2839
2888
  currentUpdaterPid = updaterPid;
2840
2889
  const state = loadProxySupervisorState();
2841
2890
  if (!state || state.pid !== process.pid) {
2842
2891
  return;
2843
2892
  }
2844
- saveProxySupervisorState({ ...state, updaterPid });
2893
+ saveProxySupervisorState({
2894
+ ...state,
2895
+ updaterPid,
2896
+ restartControl: restartControl?.identity,
2897
+ });
2845
2898
  };
2846
2899
  const updaterSupervisor = startUpdaterWorkerSupervisor({
2847
2900
  spawnWorker: () => spawnProxyUpdater(readinessHost, rollingServer.address.port, process.pid, true),
@@ -2864,6 +2917,7 @@ async function runLaunchdProxySupervisor(argv, spinner) {
2864
2917
  stopping = true;
2865
2918
  logger.always(`[proxy-supervisor] shutting down (${signal})`);
2866
2919
  process.off("SIGUSR2", activatePendingUpdate);
2920
+ await restartControl?.close();
2867
2921
  updaterSupervisor.stop();
2868
2922
  await rollingServer.close();
2869
2923
  await flushProxyLifecycleEvents().catch((error) => logger.warn(String(error)));
@@ -0,0 +1,3 @@
1
+ import type { CommandModule } from "yargs";
2
+ import type { ProxyRestartArgs } from "../../types/index.js";
3
+ export declare const proxyRestartCommand: CommandModule<object, ProxyRestartArgs>;
@@ -0,0 +1,88 @@
1
+ import { readFile, lstat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { z } from "zod";
4
+ import { resolveProxyPaths } from "../../proxy/proxyPaths.js";
5
+ import { requestProxyRestart } from "../../proxy/restartControl.js";
6
+ const supervisorSchema = z.object({
7
+ pid: z.number().int().positive(),
8
+ restartControl: z.object({
9
+ protocol: z.literal(1),
10
+ socketPath: z.string(),
11
+ instanceId: z.string().uuid(),
12
+ }),
13
+ });
14
+ export const proxyRestartCommand = {
15
+ command: "restart",
16
+ describe: "Replace the serving worker without stopping the proxy listener",
17
+ builder: (yargs) => yargs
18
+ .option("check", {
19
+ type: "boolean",
20
+ default: false,
21
+ description: "Check restart readiness without changing the running proxy",
22
+ })
23
+ .option("dev", {
24
+ type: "boolean",
25
+ default: false,
26
+ description: "Use the isolated proxy state in .neurolink-dev/",
27
+ })
28
+ .option("format", {
29
+ type: "string",
30
+ choices: ["text", "json"],
31
+ default: "text",
32
+ })
33
+ .example("neurolink proxy restart --check", "Verify the running supervisor supports safe worker replacement")
34
+ .example("neurolink proxy restart", "Start a replacement, verify it, then let existing streams finish"),
35
+ handler: async (argv) => {
36
+ try {
37
+ const { stateDir } = resolveProxyPaths(argv.dev);
38
+ const saved = supervisorSchema.safeParse(JSON.parse(await readFile(join(stateDir, "proxy-supervisor-state.json"), "utf8")));
39
+ if (!saved.success) {
40
+ throw new Error("This running supervisor does not advertise safe restart support. It must first be upgraded through a separately planned service activation.");
41
+ }
42
+ const { pid, restartControl } = saved.data;
43
+ if (restartControl.socketPath !==
44
+ join(stateDir, `restart-${pid}-${restartControl.instanceId}.sock`)) {
45
+ throw new Error("Restart control path does not match the recorded supervisor.");
46
+ }
47
+ const socket = await lstat(restartControl.socketPath);
48
+ if (!socket.isSocket() ||
49
+ (socket.mode & 0o077) !== 0 ||
50
+ (process.getuid && socket.uid !== process.getuid())) {
51
+ throw new Error("Restart control socket ownership or permissions are invalid.");
52
+ }
53
+ const result = await requestProxyRestart(restartControl, argv.check);
54
+ if (result.supervisorPid !== pid) {
55
+ throw new Error("Restart control identity changed; outcome is unverified.");
56
+ }
57
+ if (argv.format === "json") {
58
+ console.info(JSON.stringify(result, null, 2));
59
+ }
60
+ else {
61
+ console.info(result.message);
62
+ console.info(`Supervisor ${result.supervisorPid}; worker ${result.workerPid ?? "unknown"}; version ${result.version ?? "unknown"}; previous workers finishing requests: ${result.drainingWorkers}.`);
63
+ console.info("This operation preserves the supervisor and launchd settings. It does not reinstall the service.");
64
+ }
65
+ if (!result.ok) {
66
+ process.exitCode = 1;
67
+ }
68
+ }
69
+ catch (error) {
70
+ const message = error instanceof Error
71
+ ? error.message
72
+ : "Restart control is unavailable.";
73
+ if (argv.format === "json") {
74
+ const result = {
75
+ ok: false,
76
+ phase: "unverified",
77
+ message,
78
+ };
79
+ console.info(JSON.stringify(result));
80
+ }
81
+ else {
82
+ console.error(message);
83
+ }
84
+ process.exitCode = 1;
85
+ }
86
+ },
87
+ };
88
+ //# sourceMappingURL=proxyRestart.js.map
@@ -23,6 +23,7 @@ import { ObservabilityCommandFactory } from "./commands/observability.js";
23
23
  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
+ import { proxyRestartCommand } from "./commands/proxyRestart.js";
26
27
  import { proxyShareCommand } from "./commands/proxyShare.js";
27
28
  import { proxyPeerCommand } from "./commands/proxyPeer.js";
28
29
  import { proxyExposeCommand } from "./commands/proxyExpose.js";
@@ -218,6 +219,7 @@ export function initializeCliParser() {
218
219
  builder: (yargs) => yargs
219
220
  .command(proxyStartCommand)
220
221
  .command(proxyStatusCommand)
222
+ .command(proxyRestartCommand)
221
223
  .command(proxyShareCommand)
222
224
  .command(proxyPeerCommand)
223
225
  .command(proxyExposeCommand)
@@ -228,7 +230,7 @@ export function initializeCliParser() {
228
230
  .command(proxyGuardCommand)
229
231
  .command(proxyInstallCommand)
230
232
  .command(proxyUninstallCommand)
231
- .demandCommand(1, "Please specify a proxy subcommand: start, status, 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"),
233
+ .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"),
232
234
  handler: () => { },
233
235
  })
234
236
  // Evaluate Command Group - Using EvaluateCommandFactory
@@ -9,6 +9,7 @@ export declare function prepareProxyBodyForLogging(body: unknown): {
9
9
  value?: string;
10
10
  bytes?: number;
11
11
  truncated: boolean;
12
+ originalBytes?: number;
12
13
  };
13
14
  /**
14
15
  * Expose the same header-redaction policy to replay and metadata
@@ -6,6 +6,7 @@ import { gzip as gzipCallback } from "node:zlib";
6
6
  const REQUEST_LOG_IO_TIMEOUT_MS = 5_000;
7
7
  /** Maximum redacted body bytes persisted per capture entry. */
8
8
  const MAX_CAPTURED_BODY_BYTES = 1024 * 1024;
9
+ const MAX_OTEL_CAPTURED_BODY_BYTES = 8 * 1024 * 1024;
9
10
  const BODY_TRUNCATION_MARKER = "\n...[TRUNCATED]";
10
11
  const gzip = promisify(gzipCallback);
11
12
  /** Headers whose values must always be redacted. */
@@ -130,12 +131,15 @@ export function splitUtf8StringByBytes(input, maxBytes) {
130
131
  * Apply structural redaction before enforcing the per-artifact byte
131
132
  * ceiling.
132
133
  */
133
- function prepareRedactedBody(body) {
134
+ function prepareRedactedBody(body, maxBytes = MAX_CAPTURED_BODY_BYTES) {
134
135
  const redacted = redactBody(body);
135
136
  if (redacted === undefined) {
136
137
  return { truncated: false };
137
138
  }
138
- return truncateUtf8String(redacted, MAX_CAPTURED_BODY_BYTES);
139
+ return {
140
+ ...truncateUtf8String(redacted, maxBytes),
141
+ originalBytes: utf8ByteLength(redacted),
142
+ };
139
143
  }
140
144
  /**
141
145
  * Write a private gzip artifact with a unique name and return its
@@ -202,7 +206,8 @@ export function redactProxyHeadersForLogging(headers) {
202
206
  */
203
207
  export async function processProxyBodyCapture(entry, logDir) {
204
208
  const headers = redactHeaders(entry.headers);
205
- const prepared = prepareRedactedBody(entry.body);
209
+ const limit = logDir === null ? MAX_OTEL_CAPTURED_BODY_BYTES : MAX_CAPTURED_BODY_BYTES;
210
+ const prepared = prepareRedactedBody(entry.body, limit);
206
211
  if (logDir === null) {
207
212
  return {
208
213
  headers,
@@ -210,6 +215,9 @@ export async function processProxyBodyCapture(entry, logDir) {
210
215
  redactedBody: prepared.value,
211
216
  redactedBodyBytes: prepared.bytes,
212
217
  bodyTruncated: prepared.truncated,
218
+ bodyCaptureLimitBytes: limit,
219
+ originalRedactedBodyBytes: prepared.originalBytes,
220
+ bodySha256: prepared.value === undefined ? undefined : sha256(prepared.value),
213
221
  },
214
222
  };
215
223
  }
@@ -225,5 +233,12 @@ export async function processProxyBodyCapture(entry, logDir) {
225
233
  bodyWriteFailed: true,
226
234
  };
227
235
  }
228
- return { headers, stored };
236
+ return {
237
+ headers,
238
+ stored: {
239
+ ...stored,
240
+ bodyCaptureLimitBytes: limit,
241
+ originalRedactedBodyBytes: prepared.originalBytes,
242
+ },
243
+ };
229
244
  }
@@ -1,7 +1,9 @@
1
1
  import { Worker } from "node:worker_threads";
2
2
  const MAX_PENDING = 16;
3
3
  const MAX_PENDING_BYTES = 32 * 1024 * 1024;
4
- const MAX_ENTRY_BYTES = 8 * 1024 * 1024;
4
+ // Bound retained UTF-16 strings rather than a 3x UTF-8 guess. This accommodates
5
+ // the observed 7.3 MB JSON requests while retaining a 32 MiB aggregate pool.
6
+ const MAX_ENTRY_BYTES = 16 * 1024 * 1024;
5
7
  export const PROXY_BODY_CAPTURE_DEADLINE_MS = 20_000;
6
8
  let worker;
7
9
  let workerUrl;
@@ -16,6 +18,7 @@ const snapshot = {
16
18
  pendingBytes: 0,
17
19
  maxPending: MAX_PENDING,
18
20
  maxPendingBytes: MAX_PENDING_BYTES,
21
+ rejectionReasons: {},
19
22
  };
20
23
  const pending = new Map();
21
24
  // Bound traversal as well as the structured clone sent to the worker. Never
@@ -29,12 +32,15 @@ function estimateCloneBytes(value) {
29
32
  const seen = new Set();
30
33
  let bytes = 0, nodes = 0;
31
34
  while (stack.length) {
32
- if (++nodes > 100_000 || bytes > MAX_ENTRY_BYTES) {
33
- return Infinity;
35
+ if (++nodes > 100_000) {
36
+ throw new Error("body_capture_traversal_limit");
37
+ }
38
+ if (bytes > MAX_ENTRY_BYTES) {
39
+ throw new Error("body_capture_entry_too_large");
34
40
  }
35
41
  const item = stack.pop();
36
42
  if (typeof item === "string") {
37
- bytes += item.length * 3;
43
+ bytes += 16 + item.length * 2;
38
44
  continue;
39
45
  }
40
46
  bytes += 16;
@@ -42,23 +48,26 @@ function estimateCloneBytes(value) {
42
48
  continue;
43
49
  }
44
50
  if (seen.has(item)) {
45
- return Infinity;
51
+ throw new Error("body_capture_unsupported_value");
46
52
  }
47
53
  seen.add(item);
48
54
  if (!Array.isArray(item) &&
49
55
  Object.getPrototypeOf(item) !== Object.prototype &&
50
56
  Object.getPrototypeOf(item) !== null) {
51
- return Infinity;
57
+ throw new Error("body_capture_unsupported_value");
52
58
  }
53
59
  for (const key of Object.keys(item)) {
54
- bytes += key.length * 3;
60
+ bytes += 16 + key.length * 2;
55
61
  const descriptor = Object.getOwnPropertyDescriptor(item, key);
56
62
  if (!descriptor || descriptor.get || descriptor.set) {
57
- return Infinity;
63
+ throw new Error("body_capture_unsupported_value");
58
64
  }
59
65
  stack.push(descriptor.value);
60
- if (stack.length > 100_000 || bytes > MAX_ENTRY_BYTES) {
61
- return Infinity;
66
+ if (stack.length > 100_000) {
67
+ throw new Error("body_capture_traversal_limit");
68
+ }
69
+ if (bytes > MAX_ENTRY_BYTES) {
70
+ throw new Error("body_capture_entry_too_large");
62
71
  }
63
72
  }
64
73
  }
@@ -125,11 +134,21 @@ function getWorker() {
125
134
  export async function captureProxyBody(entry, logDir, consume) {
126
135
  snapshot.attempted += 1;
127
136
  let bytes;
137
+ let admissionError;
128
138
  try {
129
139
  bytes = estimateCloneBytes(entry);
130
140
  }
131
- catch {
141
+ catch (error) {
132
142
  bytes = Infinity;
143
+ admissionError =
144
+ error instanceof Error &&
145
+ [
146
+ "body_capture_entry_too_large",
147
+ "body_capture_traversal_limit",
148
+ "body_capture_unsupported_value",
149
+ ].includes(error.message)
150
+ ? error.message
151
+ : "body_capture_unsupported_value";
133
152
  }
134
153
  if (bytes > MAX_ENTRY_BYTES ||
135
154
  snapshot.pending >= MAX_PENDING ||
@@ -137,11 +156,13 @@ export async function captureProxyBody(entry, logDir, consume) {
137
156
  Date.now() < retryAfter) {
138
157
  snapshot.rejected += 1;
139
158
  const error = bytes > MAX_ENTRY_BYTES
140
- ? "body_capture_too_large_or_non_json"
159
+ ? (admissionError ?? "body_capture_entry_too_large")
141
160
  : Date.now() < retryAfter
142
161
  ? "body_worker_backoff"
143
162
  : "body_capture_queue_full";
144
163
  snapshot.lastError = error;
164
+ snapshot.rejectionReasons[error] =
165
+ (snapshot.rejectionReasons[error] ?? 0) + 1;
145
166
  return consume({ error, stored: { bodyWriteFailed: true } });
146
167
  }
147
168
  let current;
@@ -204,7 +225,7 @@ export async function captureProxyBody(entry, logDir, consume) {
204
225
  * retained publication work.
205
226
  */
206
227
  export function getBodyCaptureWorkerSnapshot() {
207
- return { ...snapshot };
228
+ return { ...snapshot, rejectionReasons: { ...snapshot.rejectionReasons } };
208
229
  }
209
230
  /** Isolated tests point at a separately executed built worker. */
210
231
  export const __bodyCaptureWorkerTestHooks = {
@@ -227,6 +248,7 @@ export const __bodyCaptureWorkerTestHooks = {
227
248
  pending: 0,
228
249
  pendingBytes: 0,
229
250
  lastError: undefined,
251
+ rejectionReasons: {},
230
252
  });
231
253
  },
232
254
  };
@@ -1,6 +1,13 @@
1
1
  import { LoggerProvider } from "@opentelemetry/sdk-logs";
2
+ import type { ProxyBodyChunkEmitter, ProxyBodyDeliveryResult } from "../types/index.js";
2
3
  /** Explicit opt-in; configuration never silently falls back to file logging. */
3
4
  export declare function isProxyOtelOnly(): boolean;
5
+ /**
6
+ * Own a whole capture within byte/count bounds, then pace its chunks by actual
7
+ * export callbacks. SDK forceFlush alone does not await an automatic export
8
+ * already in flight. Serial publication prevents bursts from dropping tails.
9
+ */
10
+ export declare function publishProxyOtelBody(captureId: string, body: string, emit: ProxyBodyChunkEmitter): Promise<ProxyBodyDeliveryResult>;
4
11
  /** Initialize a log-only provider in every proxy process, including the supervisor. */
5
12
  export declare function initializeProxyOtelLogs(role?: string): LoggerProvider | undefined;
6
13
  /** Structured evidence without final-request dashboard fields on auxiliary events. */
@@ -13,6 +20,19 @@ export declare function getProxyOtelLogSnapshot(): {
13
20
  initialized: boolean;
14
21
  deliveryGuarantee: string;
15
22
  invalidRecords: number;
23
+ bodyDelivery: {
24
+ attempted: number;
25
+ transportAcknowledged: number;
26
+ exportUnconfirmed: number;
27
+ rejected: number;
28
+ partial: number;
29
+ pending: number;
30
+ pendingBytes: number;
31
+ highWaterPending: number;
32
+ highWaterBytes: number;
33
+ maxPending: number;
34
+ maxPendingBytes: number;
35
+ };
16
36
  queues: {
17
37
  attempted: number;
18
38
  submitted: number;
@@ -22,7 +42,8 @@ export declare function getProxyOtelLogSnapshot(): {
22
42
  outstanding: number;
23
43
  lastAcknowledgedAt: string | undefined;
24
44
  lastFailureAt: string | undefined;
25
- kind: string;
45
+ highWaterOutstanding: number;
46
+ kind: "metadata" | "bodies";
26
47
  capacity: number;
27
48
  }[];
28
49
  };