@skaile/transform-proxy 0.0.0-stage → 0.1.0
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 +5 -0
- package/LICENSE +21 -0
- package/README.md +100 -2
- package/dist/cli.d.mts +17 -0
- package/dist/cli.mjs +116 -0
- package/dist/config-BKD-ILIz.mjs +1060 -0
- package/dist/index.d.mts +86 -0
- package/dist/index.mjs +1 -0
- package/dist/server-D5nBnO7T.d.mts +96 -0
- package/package.json +47 -4
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { _ as TransformModule, a as TransformProxyOptions, c as TransformSpec, d as SessionFactPublisher, f as SessionFacts, g as TransformFactory, h as Transform, 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 TransformSessionContext } from "./server-D5nBnO7T.mjs";
|
|
2
|
+
/** One stage's streamed inbound transformer, as returned by `Transform.inboundStream()`. */
|
|
3
|
+
interface InboundStream {
|
|
4
|
+
push(chunk: string): string;
|
|
5
|
+
flush(): string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Composes the stages of one pipeline into a single transform.
|
|
9
|
+
* Outbound runs stage 1 to n, inbound and streamed inbound run stage n to 1.
|
|
10
|
+
* The empty list is the identity.
|
|
11
|
+
*/
|
|
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
|
+
export declare const CONFIG_FILE_NAME = "transform-proxy.yaml";
|
|
22
|
+
/** The YAML-backed subset of the proxy options. `baseDir` is the config file's directory. */
|
|
23
|
+
interface ProxyConfig {
|
|
24
|
+
readonly baseDir: string;
|
|
25
|
+
readonly transforms: Record<string, TransformSpec>;
|
|
26
|
+
readonly pipelines: Record<string, readonly string[]>;
|
|
27
|
+
readonly defaultPipeline?: string;
|
|
28
|
+
readonly allowUpstreams?: readonly string[];
|
|
29
|
+
}
|
|
30
|
+
interface ResolvedProxyConfig {
|
|
31
|
+
readonly path: string;
|
|
32
|
+
readonly options: ProxyConfig;
|
|
33
|
+
}
|
|
34
|
+
interface ConfigLookup {
|
|
35
|
+
/** The `--config` value, relative to `cwd`. When set, it is the only candidate. */
|
|
36
|
+
readonly explicit?: string;
|
|
37
|
+
readonly cwd: string;
|
|
38
|
+
readonly home: string;
|
|
39
|
+
}
|
|
40
|
+
/** The implicit lookup locations, in order: `./.skaile/` then `~/.config/skaile/`. */
|
|
41
|
+
export declare function configCandidates(cwd: string, home: string): readonly string[];
|
|
42
|
+
/**
|
|
43
|
+
* Finds the config file: the explicit path when given (it must exist), otherwise the first
|
|
44
|
+
* existing implicit candidate. Returns `undefined` when no implicit candidate exists.
|
|
45
|
+
*/
|
|
46
|
+
export declare function findProxyConfig(lookup: ConfigLookup): string | undefined;
|
|
47
|
+
/** Finds and loads the config. Throws, naming the searched paths, when none is found. */
|
|
48
|
+
export declare function resolveProxyConfig(lookup: ConfigLookup): ResolvedProxyConfig;
|
|
49
|
+
/** Reads and validates a YAML config file. Unknown keys are rejected so that typos fail loudly. */
|
|
50
|
+
export declare function loadProxyConfig(path: string): ProxyConfig;
|
|
51
|
+
/** Validates an already-parsed config object. Exported for hosts that load YAML themselves. */
|
|
52
|
+
export declare function parseProxyConfig(source: unknown, baseDir: string): ProxyConfig;
|
|
53
|
+
interface WireContext {
|
|
54
|
+
/** The session's composed pipeline. */
|
|
55
|
+
readonly transform: Transform;
|
|
56
|
+
/**
|
|
57
|
+
* Session-scoped cache of signed reasoning: key -> text exactly as the model produced it.
|
|
58
|
+
* Walkers namespace their keys (`anthropic:<signature>`, `responses:<itemId>`).
|
|
59
|
+
*/
|
|
60
|
+
readonly signatures: Map<string, string>;
|
|
61
|
+
}
|
|
62
|
+
/** Thrown by `request` for attachments (image, document, file parts); the server answers 400 `unsupported_content`. */
|
|
63
|
+
export declare class UnsupportedContentError extends Error {
|
|
64
|
+
readonly code = "unsupported_content";
|
|
65
|
+
constructor(message: string);
|
|
66
|
+
}
|
|
67
|
+
/** A text transformer over raw SSE text; safe at any chunk boundary. */
|
|
68
|
+
interface SseTransformer {
|
|
69
|
+
push(chunk: string): string;
|
|
70
|
+
flush(): string;
|
|
71
|
+
}
|
|
72
|
+
/** Pure functions over one wire protocol's parsed JSON. */
|
|
73
|
+
interface WireWalker {
|
|
74
|
+
/**
|
|
75
|
+
* Returns the request body with every text leaf passed through `outbound` and the
|
|
76
|
+
* pipeline `instruction` added to the system prompt. Throws `UnsupportedContentError`
|
|
77
|
+
* for attachments; `outbound` errors propagate unchanged.
|
|
78
|
+
*/
|
|
79
|
+
request(body: unknown, ctx: WireContext): Promise<unknown>;
|
|
80
|
+
/** Restores a non-streamed JSON response. */
|
|
81
|
+
response(body: unknown, ctx: WireContext): unknown;
|
|
82
|
+
/** SSE event transformer for a streamed response. */
|
|
83
|
+
stream(ctx: WireContext): SseTransformer;
|
|
84
|
+
}
|
|
85
|
+
export declare const anthropicWalker: WireWalker;
|
|
86
|
+
export { type ConfigLookup, type InboundStream, type Logger, PIPELINE_HEADER, type ProxyConfig, type ResolvedProxyConfig, SESSION_HEADER, type SessionFact, type SessionFactPublisher, type SessionFactStore, type SessionFacts, type SseTransformer, TOKEN_HEADER, type TextLeaf, type TextLeafKind, type Transform, type TransformFactory, type TransformModule, type TransformProxy, type TransformProxyOptions, type TransformSessionContext, type TransformSpec, UPSTREAM_HEADER, type WireContext, type WireWalker, createTransformProxy };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as CONFIG_FILE_NAME, s as PIPELINE_HEADER, c as SESSION_HEADER, l as TOKEN_HEADER, u as UPSTREAM_HEADER, p as UnsupportedContentError, f as anthropicWalker, h as composeTransforms, n as configCandidates, m as createSessionFacts, d as createTransformProxy, r as findProxyConfig, i as loadProxyConfig, a as parseProxyConfig, o as resolveProxyConfig, _ as silentLogger } from "./config-BKD-ILIz.mjs";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** Minimal logger; structurally compatible with the workspaces `Logger`. */
|
|
2
|
+
interface Logger {
|
|
3
|
+
debug(msg: string, ...args: unknown[]): void;
|
|
4
|
+
info(msg: string, ...args: unknown[]): void;
|
|
5
|
+
warn(msg: string, ...args: unknown[]): void;
|
|
6
|
+
error(msg: string, ...args: unknown[]): void;
|
|
7
|
+
}
|
|
8
|
+
type TextLeafKind = 'system' | 'user' | 'assistant' | 'thinking' | 'toolCall' | 'toolResult';
|
|
9
|
+
interface TextLeaf {
|
|
10
|
+
readonly kind: TextLeafKind;
|
|
11
|
+
readonly toolName?: string;
|
|
12
|
+
}
|
|
13
|
+
/** One session's instance of one pipeline stage. */
|
|
14
|
+
interface Transform {
|
|
15
|
+
/** Prepended to the system prompt; omit when the model needs no instruction. */
|
|
16
|
+
readonly instruction?: string;
|
|
17
|
+
/** Host -> model, one text leaf. A throw refuses the request (502 `transform_failed`); nothing is sent. */
|
|
18
|
+
outbound(text: string, leaf: TextLeaf): Promise<string>;
|
|
19
|
+
/** Model -> host, one complete text. */
|
|
20
|
+
inbound(text: string): string;
|
|
21
|
+
/** Model -> host, one streamed text block. Invariant: push(c1)+...+push(cn)+flush() === inbound(c1+...+cn). */
|
|
22
|
+
inboundStream(): {
|
|
23
|
+
push(chunk: string): string;
|
|
24
|
+
flush(): string;
|
|
25
|
+
};
|
|
26
|
+
/** Called once when the proxy drops the session. */
|
|
27
|
+
dispose?(): void | Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
interface SessionFact {
|
|
30
|
+
readonly kind: string;
|
|
31
|
+
readonly value: string;
|
|
32
|
+
readonly source: string;
|
|
33
|
+
}
|
|
34
|
+
interface SessionFacts {
|
|
35
|
+
/** Bumped on every publish/clear; readers re-read `list()` only when it changed. */
|
|
36
|
+
readonly version: number;
|
|
37
|
+
list(kind?: string): readonly SessionFact[];
|
|
38
|
+
}
|
|
39
|
+
interface SessionFactPublisher {
|
|
40
|
+
/** Replaces this publisher's facts (source = publisher id). */
|
|
41
|
+
publish(facts: readonly Omit<SessionFact, 'source'>[]): void;
|
|
42
|
+
clear(): void;
|
|
43
|
+
}
|
|
44
|
+
interface TransformSessionContext {
|
|
45
|
+
readonly sessionId: string;
|
|
46
|
+
readonly facts: SessionFacts;
|
|
47
|
+
readonly log: Logger;
|
|
48
|
+
}
|
|
49
|
+
type TransformFactory = (ctx: TransformSessionContext) => Promise<Transform>;
|
|
50
|
+
/** Default export of a transform module, e.g. `@skaile/forge-anon/proxy`. */
|
|
51
|
+
interface TransformModule {
|
|
52
|
+
readonly id: string;
|
|
53
|
+
/** Once per proxy and config: validate config, build shared heavy state (detectors). Throws on a bad config. */
|
|
54
|
+
open(config: unknown, ctx: {
|
|
55
|
+
readonly baseDir: string;
|
|
56
|
+
readonly log: Logger;
|
|
57
|
+
}): Promise<TransformFactory>;
|
|
58
|
+
}
|
|
59
|
+
/** A configured transform: a module (object, npm specifier or relative path) and its config. */
|
|
60
|
+
interface TransformSpec {
|
|
61
|
+
readonly module: string | TransformModule;
|
|
62
|
+
readonly config?: unknown;
|
|
63
|
+
}
|
|
64
|
+
interface TransformProxyOptions {
|
|
65
|
+
/** Default 127.0.0.1. A non-loopback host requires `token`. */
|
|
66
|
+
host?: string;
|
|
67
|
+
/** Default 0 (ephemeral). */
|
|
68
|
+
port?: number;
|
|
69
|
+
/** Required `x-skaile-transform-token` when set. */
|
|
70
|
+
token?: string;
|
|
71
|
+
/** Where transform module specifiers and configs resolve. */
|
|
72
|
+
baseDir: string;
|
|
73
|
+
transforms: Readonly<Record<string, TransformSpec>>;
|
|
74
|
+
pipelines: Readonly<Record<string, readonly string[]>>;
|
|
75
|
+
/** Used when the request names no pipeline. Absent = such requests are refused. */
|
|
76
|
+
defaultPipeline?: string;
|
|
77
|
+
/** Origins. Absent = any https origin plus loopback http. */
|
|
78
|
+
allowUpstreams?: readonly string[];
|
|
79
|
+
log?: Logger;
|
|
80
|
+
}
|
|
81
|
+
interface TransformProxy {
|
|
82
|
+
readonly url: string;
|
|
83
|
+
session(id: string): {
|
|
84
|
+
readonly facts: SessionFacts;
|
|
85
|
+
publisher(source: string): SessionFactPublisher;
|
|
86
|
+
};
|
|
87
|
+
/** Disposes the session's transform instances and forgets its facts and caches. */
|
|
88
|
+
dropSession(id: string): Promise<void>;
|
|
89
|
+
close(): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
declare const UPSTREAM_HEADER = "x-skaile-transform-upstream";
|
|
92
|
+
declare const SESSION_HEADER = "x-skaile-transform-session";
|
|
93
|
+
declare const PIPELINE_HEADER = "x-skaile-transform-pipeline";
|
|
94
|
+
declare const TOKEN_HEADER = "x-skaile-transform-token";
|
|
95
|
+
declare function createTransformProxy(options: TransformProxyOptions): Promise<TransformProxy>;
|
|
96
|
+
export { TransformModule as _, TransformProxyOptions as a, TransformSpec as c, SessionFactPublisher as d, SessionFacts as f, TransformFactory as g, Transform as h, TransformProxy as i, Logger as l, TextLeafKind as m, SESSION_HEADER as n, UPSTREAM_HEADER as o, TextLeaf as p, TOKEN_HEADER as r, createTransformProxy as s, PIPELINE_HEADER as t, SessionFact as u, TransformSessionContext as v };
|
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skaile/transform-proxy",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
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
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/skaile-ai/skaile-transform-proxy.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/skaile-ai/skaile-transform-proxy#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/skaile-ai/skaile-transform-proxy/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["llm", "proxy", "anthropic", "openai", "anonymization", "transform"],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.mts",
|
|
22
|
+
"import": "./dist/index.mjs"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"skaile-transform-proxy": "dist/cli.mjs"
|
|
28
|
+
},
|
|
29
|
+
"files": ["dist", "README.md", "CHANGELOG.md", "LICENSE"],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"prebuild": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
35
|
+
"build": "tsdown",
|
|
36
|
+
"prepare": "npm run build",
|
|
37
|
+
"test": "bun test",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"yaml": "^2.9.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/bun": "^1.3.0",
|
|
45
|
+
"@types/node": "^22.0.0",
|
|
46
|
+
"tsdown": "^0.23.1",
|
|
47
|
+
"typescript": "^5.9.3"
|
|
48
|
+
}
|
|
49
|
+
}
|