@skaile/transform-proxy 0.5.0 → 0.5.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 21bab3c: The bin installs its SIGINT, SIGTERM and `--exit-with-stdin` handlers before it prints `listening`. A parent that stopped the proxy right after that line could kill it with the default signal action (exit 143) instead of a clean shutdown (exit 0). `runCli` takes an optional `onStart` callback, called after the proxy listens and before the `listening` line.
8
+
3
9
  ## 0.5.0
4
10
 
5
11
  - Library: the anon trace records what the proxy sends to the provider **after** the pipeline and what the model answers **before** restore, so a reviewer can check that no clear-text personal data reached the provider. `TransformProxyOptions.trace?: TraceSink` (synchronous `record(event: TraceEvent)`) gets one `request` line per proxied request on the wire routes and exactly one `response` or `error` line for it, linked by `requestId`. Without `trace`, nothing is recorded or hashed. A sink that throws is logged (`transform proxy: trace sink failed: <msg>`) and never reaches the client.
package/README.md CHANGED
@@ -214,3 +214,4 @@ Connectors publish facts through `proxy.session(id).publisher(source)`. Facts ar
214
214
  - Fields the walkers do not rewrite (`tools`, metadata, unknown fields) are forwarded as they are. The [leak check](#leak-check) warns when one of them carries a known original; it does not block the request.
215
215
  - Leak warnings carry kind, source and JSON path, never the value. Trace files and any other `TraceSink` get the clear text that leaked: keep them local, never commit them, delete them once reviewed.
216
216
  - Mappings, facts, the signature cache and the trace hashes are kept in memory and are lost on restart.
217
+ - omp writes the request of every HTTP 400 answer to `~/.omp/logs/http-400-requests/<id>.json` (mode `0644`). That copy is what omp sent to the proxy, before anonymization, so it holds the personal data in clear text. It stays on the machine; delete it when anon is in use.
package/dist/cli.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as TransformProxy } from "./server-DdXMr4yF.mjs";
1
+ import { i as TransformProxy } from "./server-gwJGHF82.mjs";
2
2
  /** Environment variable that supplies the client token when `--token` is absent. */
3
3
  export declare const TOKEN_ENV = "SKAILE_TRANSFORM_PROXY_TOKEN";
4
4
  /** Environment variable with the trace directory (relative to cwd); overrides `--trace-dir` and the config's `trace.dir`. */
@@ -9,6 +9,11 @@ export interface CliEnvironment {
9
9
  readonly env: Readonly<Record<string, string | undefined>>;
10
10
  readonly stdout: (line: string) => void;
11
11
  readonly stderr: (line: string) => void;
12
+ /**
13
+ * Called once the proxy listens, before the `listening` line: a parent reacts to that line (with SIGTERM, or by
14
+ * closing stdin), so the caller's shutdown handlers must be in place by then.
15
+ */
16
+ readonly onStart?: (run: Required<CliRun>) => void;
12
17
  }
13
18
  /** `proxy` is set only when the server started; the caller owns its shutdown. */
14
19
  export interface CliRun {
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { d as createTransformProxy, o as resolveProxyConfig, p as createFileTraceSink, x as errorMessage } from "./config-DHxYF3Tv.mjs";
2
+ import { a as createTransformProxy, s as createFileTraceSink, x as errorMessage, y as resolveProxyConfig } from "./server-BR1dDA8S.mjs";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -77,12 +77,14 @@ async function runCli(argv, io) {
77
77
  }) }
78
78
  });
79
79
  if (traceDir !== void 0) io.stderr(format("info", `trace: ${traceDir}`, []));
80
- io.stdout(`listening ${proxy.url}`);
81
- return {
80
+ const run = {
82
81
  code: 0,
83
82
  proxy,
84
83
  exitWithStdin: values["exit-with-stdin"] === true
85
84
  };
85
+ io.onStart?.(run);
86
+ io.stdout(`listening ${proxy.url}`);
87
+ return run;
86
88
  } catch (err) {
87
89
  io.stderr(errorMessage(err));
88
90
  return { code: 1 };
@@ -112,27 +114,26 @@ if (isEntryPoint()) {
112
114
  home: homedir(),
113
115
  env: process.env,
114
116
  stdout: (line) => console.log(line),
115
- stderr: (line) => console.error(line)
117
+ stderr: (line) => console.error(line),
118
+ onStart: ({ proxy, exitWithStdin }) => {
119
+ let stopping = false;
120
+ const stop = () => {
121
+ if (stopping) return;
122
+ stopping = true;
123
+ proxy.close().then(() => process.exit(0), (err) => {
124
+ console.error(errorMessage(err));
125
+ process.exit(1);
126
+ });
127
+ };
128
+ process.once("SIGINT", stop);
129
+ process.once("SIGTERM", stop);
130
+ if (exitWithStdin) {
131
+ process.stdin.once("end", stop);
132
+ process.stdin.once("close", stop);
133
+ process.stdin.resume();
134
+ }
135
+ }
116
136
  });
117
137
  if (run.proxy === void 0) process.exitCode = run.code;
118
- else {
119
- const proxy = run.proxy;
120
- let stopping = false;
121
- const stop = () => {
122
- if (stopping) return;
123
- stopping = true;
124
- proxy.close().then(() => process.exit(0), (err) => {
125
- console.error(errorMessage(err));
126
- process.exit(1);
127
- });
128
- };
129
- process.once("SIGINT", stop);
130
- process.once("SIGTERM", stop);
131
- if (run.exitWithStdin === true) {
132
- process.stdin.once("end", stop);
133
- process.stdin.once("close", stop);
134
- process.stdin.resume();
135
- }
136
- }
137
138
  }
138
139
  export { TOKEN_ENV, TRACE_DIR_ENV, runCli };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as TraceSink, a as TransformProxyOptions, b as TransformModule, c as TransformSpec, d as SessionFactPublisher, f as SessionFacts, g as TraceLeak, h as TraceEvent, i as TransformProxy, l as Logger, m as TextLeafKind, n as SESSION_HEADER, o as UPSTREAM_HEADER, p as TextLeaf, r as TOKEN_HEADER, s as createTransformProxy, t as PIPELINE_HEADER, u as SessionFact, v as Transform, x as TransformSessionContext, y as TransformFactory } from "./server-DdXMr4yF.mjs";
1
+ import { _ as TraceSink, a as TransformProxyOptions, b as TransformModule, c as TransformSpec, d as SessionFactPublisher, f as SessionFacts, g as TraceLeak, h as TraceEvent, i as TransformProxy, l as Logger, m as TextLeafKind, n as SESSION_HEADER, o as UPSTREAM_HEADER, p as TextLeaf, r as TOKEN_HEADER, s as createTransformProxy, t as PIPELINE_HEADER, u as SessionFact, v as Transform, x as TransformSessionContext, y as TransformFactory } from "./server-gwJGHF82.mjs";
2
2
  /** One stage's streamed inbound transformer, as returned by `Transform.inboundStream()`. */
3
3
  interface InboundStream {
4
4
  push(chunk: string): string;
@@ -10,14 +10,6 @@ interface InboundStream {
10
10
  * The empty list is the identity.
11
11
  */
12
12
  export declare function composeTransforms(stages: readonly Transform[], log?: Logger): Transform;
13
- /** Default logger: drops everything. Hosts pass their own `Logger`. */
14
- export declare const silentLogger: Logger;
15
- /** One session's facts: the read side for transforms and the per-source publishers for connectors. */
16
- interface SessionFactStore {
17
- readonly facts: SessionFacts;
18
- publisher(source: string): SessionFactPublisher;
19
- }
20
- export declare function createSessionFacts(): SessionFactStore;
21
13
  export declare const CONFIG_FILE_NAME = "transform-proxy.yaml";
22
14
  /** The YAML-backed subset of the proxy options. `baseDir` is the config file's directory. */
23
15
  interface ProxyConfig {
@@ -55,6 +47,14 @@ export declare function resolveProxyConfig(lookup: ConfigLookup): ResolvedProxyC
55
47
  export declare function loadProxyConfig(path: string): ProxyConfig;
56
48
  /** Validates an already-parsed config object. Exported for hosts that load YAML themselves. */
57
49
  export declare function parseProxyConfig(source: unknown, baseDir: string): ProxyConfig;
50
+ /** One session's facts: the read side for transforms and the per-source publishers for connectors. */
51
+ interface SessionFactStore {
52
+ readonly facts: SessionFacts;
53
+ publisher(source: string): SessionFactPublisher;
54
+ }
55
+ export declare function createSessionFacts(): SessionFactStore;
56
+ /** Default logger: drops everything. Hosts pass their own `Logger`. */
57
+ export declare const silentLogger: Logger;
58
58
  export declare const DEFAULT_TRACE_MAX_CHARS = 262144;
59
59
  /**
60
60
  * One JSON line (no trailing newline). When the JSON of `content` is longer than `maxChars`,
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { t as CONFIG_FILE_NAME, f as DEFAULT_TRACE_MAX_CHARS, s as PIPELINE_HEADER, c as SESSION_HEADER, l as TOKEN_HEADER, u as UPSTREAM_HEADER, v as UnsupportedContentError, _ as anthropicWalker, b as composeTransforms, n as configCandidates, p as createFileTraceSink, y as createSessionFacts, d as createTransformProxy, r as findProxyConfig, i as loadProxyConfig, g as openaiChatWalker, h as openaiResponsesWalker, a as parseProxyConfig, o as resolveProxyConfig, m as serializeTraceEvent, S as silentLogger } from "./config-DHxYF3Tv.mjs";
1
+ export { m as CONFIG_FILE_NAME, o as DEFAULT_TRACE_MAX_CHARS, t as PIPELINE_HEADER, n as SESSION_HEADER, r as TOKEN_HEADER, i as UPSTREAM_HEADER, f as UnsupportedContentError, d as anthropicWalker, b as composeTransforms, h as configCandidates, s as createFileTraceSink, p as createSessionFacts, a as createTransformProxy, g as findProxyConfig, _ as loadProxyConfig, u as openaiChatWalker, l as openaiResponsesWalker, v as parseProxyConfig, y as resolveProxyConfig, c as serializeTraceEvent, S as silentLogger } from "./server-BR1dDA8S.mjs";
@@ -1,7 +1,7 @@
1
- import { c as SESSION_HEADER, i as loadProxyConfig, l as TOKEN_HEADER, n as configCandidates, r as findProxyConfig, u as UPSTREAM_HEADER, x as errorMessage } from "../config-DHxYF3Tv.mjs";
2
- import { randomBytes, randomUUID } from "node:crypto";
1
+ import { _ as loadProxyConfig, g as findProxyConfig, h as configCandidates, i as UPSTREAM_HEADER, n as SESSION_HEADER, r as TOKEN_HEADER, x as errorMessage } from "../server-BR1dDA8S.mjs";
3
2
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
3
  import { dirname, join, resolve } from "node:path";
4
+ import { randomBytes, randomUUID } from "node:crypto";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { homedir } from "node:os";
7
7
  import { spawn } from "node:child_process";
@@ -1,10 +1,10 @@
1
1
  import { createRequire } from "node:module";
2
- import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
3
- import { createServer } from "node:http";
4
2
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
5
3
  import { dirname, isAbsolute, join, resolve } from "node:path";
6
- import { pathToFileURL } from "node:url";
7
4
  import { parse } from "yaml";
5
+ import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
6
+ import { createServer } from "node:http";
7
+ import { pathToFileURL } from "node:url";
8
8
  // src/log.ts
9
9
  /** Default logger: drops everything. Hosts pass their own `Logger`. */
10
10
  const silentLogger = {
@@ -92,6 +92,112 @@ function composeStreams(streams) {
92
92
  }
93
93
  };
94
94
  }
95
+ // src/config.ts
96
+ const CONFIG_FILE_NAME = "transform-proxy.yaml";
97
+ /** The implicit lookup locations, in order: `./.skaile/` then `~/.config/skaile/`. */
98
+ function configCandidates(cwd, home) {
99
+ return [join(cwd, ".skaile", CONFIG_FILE_NAME), join(home, ".config", "skaile", CONFIG_FILE_NAME)];
100
+ }
101
+ /**
102
+ * Finds the config file: the explicit path when given (it must exist), otherwise the first
103
+ * existing implicit candidate. Returns `undefined` when no implicit candidate exists.
104
+ */
105
+ function findProxyConfig(lookup) {
106
+ if (lookup.explicit !== void 0) {
107
+ const path = resolve(lookup.cwd, lookup.explicit);
108
+ if (!existsSync(path)) throw new Error(`transform proxy config not found: ${path}`);
109
+ return path;
110
+ }
111
+ return configCandidates(lookup.cwd, lookup.home).find((candidate) => existsSync(candidate));
112
+ }
113
+ /** Finds and loads the config. Throws, naming the searched paths, when none is found. */
114
+ function resolveProxyConfig(lookup) {
115
+ const path = findProxyConfig(lookup);
116
+ if (path === void 0) {
117
+ const searched = configCandidates(lookup.cwd, lookup.home).join(", ");
118
+ throw new Error(`no transform proxy config found (pass --config, or create one at ${searched})`);
119
+ }
120
+ return {
121
+ path,
122
+ options: loadProxyConfig(path)
123
+ };
124
+ }
125
+ const TOP_LEVEL_KEYS = {
126
+ transforms: true,
127
+ pipelines: true,
128
+ defaultPipeline: true,
129
+ allowUpstreams: true,
130
+ trace: true
131
+ };
132
+ const TRACE_KEYS = {
133
+ dir: true,
134
+ maxChars: true
135
+ };
136
+ /** Reads and validates a YAML config file. Unknown keys are rejected so that typos fail loudly. */
137
+ function loadProxyConfig(path) {
138
+ const source = parse(readFileSync(path, "utf8"));
139
+ try {
140
+ return parseProxyConfig(source ?? {}, dirname(path));
141
+ } catch (err) {
142
+ throw new Error(`invalid transform proxy config ${path}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
143
+ }
144
+ }
145
+ /** Validates an already-parsed config object. Exported for hosts that load YAML themselves. */
146
+ function parseProxyConfig(source, baseDir) {
147
+ if (!isRecord$1(source)) throw new Error("the document must be a mapping");
148
+ for (const key of Object.keys(source)) if (!Object.hasOwn(TOP_LEVEL_KEYS, key)) throw new Error(`unknown key "${key}"`);
149
+ return {
150
+ baseDir,
151
+ transforms: parseTransforms(source.transforms),
152
+ pipelines: parsePipelines(source.pipelines),
153
+ ...source.defaultPipeline === void 0 ? {} : { defaultPipeline: requireString(source.defaultPipeline, "defaultPipeline") },
154
+ ...source.allowUpstreams === void 0 ? {} : { allowUpstreams: requireStringList(source.allowUpstreams, "allowUpstreams") },
155
+ ...source.trace === void 0 ? {} : { trace: parseTrace(source.trace, baseDir) }
156
+ };
157
+ }
158
+ function parseTransforms(value) {
159
+ if (value === void 0) return {};
160
+ if (!isRecord$1(value)) throw new Error("transforms must be a mapping of transform id to { module, config }");
161
+ const out = {};
162
+ for (const [id, spec] of Object.entries(value)) {
163
+ if (!isRecord$1(spec)) throw new Error(`transforms.${id} must be a mapping with a module`);
164
+ const module = requireString(spec.module, `transforms.${id}.module`);
165
+ out[id] = spec.config === void 0 ? { module } : {
166
+ module,
167
+ config: spec.config
168
+ };
169
+ }
170
+ return out;
171
+ }
172
+ function parsePipelines(value) {
173
+ if (value === void 0) return {};
174
+ if (!isRecord$1(value)) throw new Error("pipelines must be a mapping of pipeline id to a list of transform ids");
175
+ const out = {};
176
+ for (const [id, stages] of Object.entries(value)) out[id] = requireStringList(stages, `pipelines.${id}`);
177
+ return out;
178
+ }
179
+ function parseTrace(value, baseDir) {
180
+ if (!isRecord$1(value)) throw new Error("trace must be a mapping with a dir");
181
+ for (const key of Object.keys(value)) if (!Object.hasOwn(TRACE_KEYS, key)) throw new Error(`unknown key "trace.${key}"`);
182
+ const dir = resolve(baseDir, requireString(value.dir, "trace.dir"));
183
+ if (value.maxChars === void 0) return { dir };
184
+ if (typeof value.maxChars !== "number" || !Number.isInteger(value.maxChars) || value.maxChars <= 0) throw new Error("trace.maxChars must be a positive integer");
185
+ return {
186
+ dir,
187
+ maxChars: value.maxChars
188
+ };
189
+ }
190
+ function requireString(value, field) {
191
+ if (typeof value !== "string" || value === "") throw new Error(`${field} must be a non-empty string`);
192
+ return value;
193
+ }
194
+ function requireStringList(value, field) {
195
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item === "")) throw new Error(`${field} must be a list of non-empty strings`);
196
+ return value;
197
+ }
198
+ function isRecord$1(value) {
199
+ return typeof value === "object" && value !== null && !Array.isArray(value);
200
+ }
95
201
  // src/facts.ts
96
202
  function createSessionFacts() {
97
203
  const bySource = /* @__PURE__ */ new Map();
@@ -256,17 +362,17 @@ function resolveImportCondition(specifier, root) {
256
362
  }
257
363
  }
258
364
  function exportTarget(exports, subpath) {
259
- return conditionTarget((isRecord$1(exports) && Object.keys(exports).some((key) => key.startsWith(".")) ? exports : { ".": exports })[subpath]);
365
+ return conditionTarget((isRecord(exports) && Object.keys(exports).some((key) => key.startsWith(".")) ? exports : { ".": exports })[subpath]);
260
366
  }
261
367
  function conditionTarget(entry) {
262
368
  if (typeof entry === "string") return entry;
263
- if (!isRecord$1(entry)) return void 0;
369
+ if (!isRecord(entry)) return void 0;
264
370
  return conditionTarget(entry.import) ?? conditionTarget(entry.default);
265
371
  }
266
372
  function isTransformModule(value) {
267
- return isRecord$1(value) && typeof value.id === "string" && typeof value.open === "function";
373
+ return isRecord(value) && typeof value.id === "string" && typeof value.open === "function";
268
374
  }
269
- function isRecord$1(value) {
375
+ function isRecord(value) {
270
376
  return typeof value === "object" && value !== null && !Array.isArray(value);
271
377
  }
272
378
  // src/wire/json-args.ts
@@ -2160,110 +2266,4 @@ function sendError(res, status, type, message) {
2160
2266
  message
2161
2267
  } }));
2162
2268
  }
2163
- // src/config.ts
2164
- const CONFIG_FILE_NAME = "transform-proxy.yaml";
2165
- /** The implicit lookup locations, in order: `./.skaile/` then `~/.config/skaile/`. */
2166
- function configCandidates(cwd, home) {
2167
- return [join(cwd, ".skaile", CONFIG_FILE_NAME), join(home, ".config", "skaile", CONFIG_FILE_NAME)];
2168
- }
2169
- /**
2170
- * Finds the config file: the explicit path when given (it must exist), otherwise the first
2171
- * existing implicit candidate. Returns `undefined` when no implicit candidate exists.
2172
- */
2173
- function findProxyConfig(lookup) {
2174
- if (lookup.explicit !== void 0) {
2175
- const path = resolve(lookup.cwd, lookup.explicit);
2176
- if (!existsSync(path)) throw new Error(`transform proxy config not found: ${path}`);
2177
- return path;
2178
- }
2179
- return configCandidates(lookup.cwd, lookup.home).find((candidate) => existsSync(candidate));
2180
- }
2181
- /** Finds and loads the config. Throws, naming the searched paths, when none is found. */
2182
- function resolveProxyConfig(lookup) {
2183
- const path = findProxyConfig(lookup);
2184
- if (path === void 0) {
2185
- const searched = configCandidates(lookup.cwd, lookup.home).join(", ");
2186
- throw new Error(`no transform proxy config found (pass --config, or create one at ${searched})`);
2187
- }
2188
- return {
2189
- path,
2190
- options: loadProxyConfig(path)
2191
- };
2192
- }
2193
- const TOP_LEVEL_KEYS = {
2194
- transforms: true,
2195
- pipelines: true,
2196
- defaultPipeline: true,
2197
- allowUpstreams: true,
2198
- trace: true
2199
- };
2200
- const TRACE_KEYS = {
2201
- dir: true,
2202
- maxChars: true
2203
- };
2204
- /** Reads and validates a YAML config file. Unknown keys are rejected so that typos fail loudly. */
2205
- function loadProxyConfig(path) {
2206
- const source = parse(readFileSync(path, "utf8"));
2207
- try {
2208
- return parseProxyConfig(source ?? {}, dirname(path));
2209
- } catch (err) {
2210
- throw new Error(`invalid transform proxy config ${path}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
2211
- }
2212
- }
2213
- /** Validates an already-parsed config object. Exported for hosts that load YAML themselves. */
2214
- function parseProxyConfig(source, baseDir) {
2215
- if (!isRecord(source)) throw new Error("the document must be a mapping");
2216
- for (const key of Object.keys(source)) if (!Object.hasOwn(TOP_LEVEL_KEYS, key)) throw new Error(`unknown key "${key}"`);
2217
- return {
2218
- baseDir,
2219
- transforms: parseTransforms(source.transforms),
2220
- pipelines: parsePipelines(source.pipelines),
2221
- ...source.defaultPipeline === void 0 ? {} : { defaultPipeline: requireString(source.defaultPipeline, "defaultPipeline") },
2222
- ...source.allowUpstreams === void 0 ? {} : { allowUpstreams: requireStringList(source.allowUpstreams, "allowUpstreams") },
2223
- ...source.trace === void 0 ? {} : { trace: parseTrace(source.trace, baseDir) }
2224
- };
2225
- }
2226
- function parseTransforms(value) {
2227
- if (value === void 0) return {};
2228
- if (!isRecord(value)) throw new Error("transforms must be a mapping of transform id to { module, config }");
2229
- const out = {};
2230
- for (const [id, spec] of Object.entries(value)) {
2231
- if (!isRecord(spec)) throw new Error(`transforms.${id} must be a mapping with a module`);
2232
- const module = requireString(spec.module, `transforms.${id}.module`);
2233
- out[id] = spec.config === void 0 ? { module } : {
2234
- module,
2235
- config: spec.config
2236
- };
2237
- }
2238
- return out;
2239
- }
2240
- function parsePipelines(value) {
2241
- if (value === void 0) return {};
2242
- if (!isRecord(value)) throw new Error("pipelines must be a mapping of pipeline id to a list of transform ids");
2243
- const out = {};
2244
- for (const [id, stages] of Object.entries(value)) out[id] = requireStringList(stages, `pipelines.${id}`);
2245
- return out;
2246
- }
2247
- function parseTrace(value, baseDir) {
2248
- if (!isRecord(value)) throw new Error("trace must be a mapping with a dir");
2249
- for (const key of Object.keys(value)) if (!Object.hasOwn(TRACE_KEYS, key)) throw new Error(`unknown key "trace.${key}"`);
2250
- const dir = resolve(baseDir, requireString(value.dir, "trace.dir"));
2251
- if (value.maxChars === void 0) return { dir };
2252
- if (typeof value.maxChars !== "number" || !Number.isInteger(value.maxChars) || value.maxChars <= 0) throw new Error("trace.maxChars must be a positive integer");
2253
- return {
2254
- dir,
2255
- maxChars: value.maxChars
2256
- };
2257
- }
2258
- function requireString(value, field) {
2259
- if (typeof value !== "string" || value === "") throw new Error(`${field} must be a non-empty string`);
2260
- return value;
2261
- }
2262
- function requireStringList(value, field) {
2263
- if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item === "")) throw new Error(`${field} must be a list of non-empty strings`);
2264
- return value;
2265
- }
2266
- function isRecord(value) {
2267
- return typeof value === "object" && value !== null && !Array.isArray(value);
2268
- }
2269
- export { silentLogger as S, anthropicWalker as _, parseProxyConfig as a, composeTransforms as b, SESSION_HEADER as c, createTransformProxy as d, DEFAULT_TRACE_MAX_CHARS as f, openaiChatWalker as g, openaiResponsesWalker as h, loadProxyConfig as i, TOKEN_HEADER as l, serializeTraceEvent as m, configCandidates as n, resolveProxyConfig as o, createFileTraceSink as p, findProxyConfig as r, PIPELINE_HEADER as s, CONFIG_FILE_NAME as t, UPSTREAM_HEADER as u, UnsupportedContentError as v, errorMessage as x, createSessionFacts as y };
2269
+ export { silentLogger as S, loadProxyConfig as _, createTransformProxy as a, composeTransforms as b, serializeTraceEvent as c, anthropicWalker as d, UnsupportedContentError as f, findProxyConfig as g, configCandidates as h, UPSTREAM_HEADER as i, openaiResponsesWalker as l, CONFIG_FILE_NAME as m, SESSION_HEADER as n, DEFAULT_TRACE_MAX_CHARS as o, createSessionFacts as p, TOKEN_HEADER as r, createFileTraceSink as s, PIPELINE_HEADER as t, openaiChatWalker as u, parseProxyConfig as v, errorMessage as x, resolveProxyConfig as y };
@@ -146,7 +146,7 @@ interface TransformProxy {
146
146
  /**
147
147
  * Host-only, in-process: each stage's `inspect()` result of the session's pipeline instance, keyed by transform id.
148
148
  * `{}` when the session or pipeline is unknown, the instance is not built, or its build failed.
149
- * Never builds an instance or creates session state; there is no HTTP route for it.
149
+ * Never builds an instance or creates session state; there is no HTTP route for it. Rejects when a stage's `inspect()` throws.
150
150
  */
151
151
  inspect(sessionId: string, pipelineId?: string): Promise<Record<string, unknown>>;
152
152
  close(): Promise<void>;
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@skaile/transform-proxy",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "description": "Same-protocol passthrough proxy that runs model requests and replies through a chain of text transforms (Anthropic Messages, OpenAI chat, OpenAI responses)",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/skaile-ai/skaile-transform-proxy.git"
9
+ "url": "git+https://github.com/skaile-ai/forge.git",
10
+ "directory": "packages/transform-proxy"
10
11
  },
11
- "homepage": "https://github.com/skaile-ai/skaile-transform-proxy#readme",
12
+ "homepage": "https://github.com/skaile-ai/forge/tree/main/packages/transform-proxy#readme",
12
13
  "bugs": {
13
- "url": "https://github.com/skaile-ai/skaile-transform-proxy/issues"
14
+ "url": "https://github.com/skaile-ai/forge/issues"
14
15
  },
15
16
  "keywords": [
16
17
  "llm",
@@ -54,9 +55,10 @@
54
55
  "scripts": {
55
56
  "prebuild": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
56
57
  "build": "tsdown",
57
- "prepare": "npm run build",
58
- "test": "bun test",
59
- "typecheck": "tsc --noEmit"
58
+ "prepublishOnly": "npm run build",
59
+ "test": "bun --bun vitest run",
60
+ "typecheck": "tsc --noEmit",
61
+ "check": "bun ../../scripts/check-package.ts"
60
62
  },
61
63
  "dependencies": {
62
64
  "yaml": "^2.9.0"
@@ -64,7 +66,6 @@
64
66
  "devDependencies": {
65
67
  "@types/bun": "^1.3.0",
66
68
  "@types/node": "^22.0.0",
67
- "tsdown": "^0.23.1",
68
69
  "typescript": "^5.9.3"
69
70
  }
70
71
  }