@proxitor/plugin-api 0.1.0-beta.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/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # @proxitor/plugin-api
2
+
3
+ Published plugin contract for proxitor v1. Plugins transform a `CanonicalRequest`
4
+ (IR) and observe/transform a `CanonicalEvent` stream; they are blind to
5
+ providers, wire formats and transport (spec D9).
6
+
7
+ ## Mutations channels (and only these)
8
+
9
+ 1. The typed IR: `CanonicalRequest` (mutate and return from `onRequest`).
10
+ 2. `req.outboundHeaders` — upstream request headers. Protected (ignored on
11
+ conflict): `authorization`, `x-api-key`, `host`, `content-length`, and all
12
+ `provider.headers`.
13
+ 3. Format-reserved `$proxitor.` keys inside `req.extensions[format]`. Declare
14
+ them in `reservedKeys`; config-time validation matches the provider's
15
+ wireFormat. Reserved keys per format:
16
+
17
+ | format | reserved keys |
18
+ | ------------------- | ------------------------------------------------------------------------------- |
19
+ | `openai-chat` | `$proxitor.provider`, `$proxitor.models`, `$proxitor.route`, `$proxitor.transforms` |
20
+ | `anthropic-messages` | — (none in v1) |
21
+
22
+ ## ShortCircuit
23
+
24
+ `{ shortCircuit: true, status, headers? }` plus **at most one** of `error`
25
+ (CanonicalError, encoded to the client's wire-error format) or `events`
26
+ (CanonicalEvent[], encoded to the client's inbound format — works for both
27
+ streaming and non-streaming clients). Raw-body mocks are not supported.
28
+
29
+ ## definePlugin
30
+
31
+ ```ts
32
+ import { definePlugin } from '@proxitor/plugin-api';
33
+ import { z } from 'zod';
34
+
35
+ export default definePlugin(z.object({ ttl: z.enum(['5m', '1h']) }), {
36
+ name: 'cache-control',
37
+ onRequest(ctx, req) { /* mutate req, return it */ return req; },
38
+ });
39
+ ```
40
+
41
+ zod is a peer dependency (`^4`).
@@ -0,0 +1,277 @@
1
+ import { ZodType } from "zod";
2
+
3
+ //#region src/canonical/request.d.ts
4
+ /** Per-node passthrough for fields the IR does not model (spec §4.1, D17). */
5
+ type NodeExtensions = Record<string, unknown>;
6
+ /** Request-level passthrough bag keyed by source format (spec §4.3). */
7
+ type ExtensionsBag = Record<string, Record<string, unknown>>;
8
+ type CacheControl = {
9
+ type: 'ephemeral';
10
+ ttl?: '5m' | '1h';
11
+ };
12
+ type CanonicalSystemBlock = {
13
+ type: 'text';
14
+ text: string;
15
+ cacheControl?: CacheControl;
16
+ extensions?: NodeExtensions;
17
+ };
18
+ type ImageSource = {
19
+ kind: 'base64';
20
+ mediaType: string;
21
+ data: string;
22
+ } | {
23
+ kind: 'url';
24
+ url: string;
25
+ };
26
+ type ResponseFormat = {
27
+ kind: 'json';
28
+ } | {
29
+ kind: 'json_schema';
30
+ schema: Record<string, unknown>;
31
+ };
32
+ type CanonicalContentBlock = {
33
+ type: 'text';
34
+ text: string;
35
+ cacheControl?: CacheControl;
36
+ extensions?: NodeExtensions;
37
+ } | {
38
+ type: 'image';
39
+ source: ImageSource;
40
+ cacheControl?: CacheControl;
41
+ extensions?: NodeExtensions;
42
+ } | {
43
+ type: 'tool_use';
44
+ id: string;
45
+ name: string;
46
+ input: unknown;
47
+ cacheControl?: CacheControl;
48
+ extensions?: NodeExtensions;
49
+ } | {
50
+ type: 'tool_result';
51
+ toolUseId: string;
52
+ content: CanonicalContentBlock[] | string;
53
+ isError?: boolean;
54
+ cacheControl?: CacheControl;
55
+ extensions?: NodeExtensions;
56
+ } | {
57
+ type: 'thinking';
58
+ thinking: string;
59
+ signature?: string;
60
+ cacheControl?: CacheControl;
61
+ extensions?: NodeExtensions;
62
+ };
63
+ type CanonicalMessage = {
64
+ role: 'user' | 'assistant';
65
+ content: CanonicalContentBlock[];
66
+ extensions?: NodeExtensions;
67
+ };
68
+ type CanonicalTool = {
69
+ name: string;
70
+ description?: string;
71
+ inputSchema: Record<string, unknown>;
72
+ cacheControl?: CacheControl;
73
+ };
74
+ type CanonicalToolChoice = {
75
+ mode: 'auto' | 'any' | 'none';
76
+ } | {
77
+ mode: 'tool';
78
+ name: string;
79
+ };
80
+ /** Provenance-preserving max tokens (r2 P0-1): same-format encode re-emits the source field name. */
81
+ type MaxTokens = {
82
+ value: number;
83
+ source: 'max_tokens' | 'max_completion_tokens' | 'max_output_tokens';
84
+ };
85
+ type CanonicalParams = {
86
+ temperature?: number;
87
+ maxTokens?: MaxTokens;
88
+ topP?: number;
89
+ topK?: number;
90
+ stop?: string[];
91
+ seed?: number;
92
+ n?: number;
93
+ responseFormat?: ResponseFormat;
94
+ presencePenalty?: number;
95
+ frequencyPenalty?: number;
96
+ };
97
+ type CanonicalRequest = {
98
+ model: {
99
+ logical: string;
100
+ physical: string;
101
+ };
102
+ system: CanonicalSystemBlock[];
103
+ messages: CanonicalMessage[];
104
+ tools?: CanonicalTool[];
105
+ toolChoice?: CanonicalToolChoice;
106
+ params: CanonicalParams;
107
+ stream: boolean;
108
+ extensions: ExtensionsBag; /** Plugin → upstream header channel (D18); auth + provider.headers are protected. */
109
+ outboundHeaders?: Record<string, string>; /** Inbound client session hint, stamped by the pipeline from client headers; plugins may honor it instead of deriving their own id. */
110
+ clientSessionId?: string;
111
+ };
112
+ //#endregion
113
+ //#region src/canonical/events.d.ts
114
+ type StopReason = 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use';
115
+ type Usage = {
116
+ inputTokens: number;
117
+ outputTokens: number;
118
+ cacheReadTokens?: number;
119
+ cacheCreateTokens?: number;
120
+ };
121
+ type PartialUsage = Partial<Usage>;
122
+ type TextDelta = {
123
+ type: 'text';
124
+ text: string;
125
+ };
126
+ type InputJsonDelta = {
127
+ type: 'input_json';
128
+ partialJson: string;
129
+ };
130
+ type ThinkingDelta = {
131
+ type: 'thinking';
132
+ thinking: string;
133
+ };
134
+ type CanonicalError = {
135
+ type: string;
136
+ message: string;
137
+ status: number;
138
+ providerError?: unknown;
139
+ };
140
+ type CanonicalEvent = {
141
+ type: 'message_start';
142
+ id: string;
143
+ model: string;
144
+ } | {
145
+ type: 'content_block_start';
146
+ index: number;
147
+ block: {
148
+ type: 'text' | 'tool_use' | 'thinking';
149
+ id?: string;
150
+ name?: string;
151
+ };
152
+ } | {
153
+ type: 'content_block_delta';
154
+ index: number;
155
+ delta: TextDelta | InputJsonDelta | ThinkingDelta;
156
+ } | {
157
+ type: 'signature_delta';
158
+ index: number;
159
+ signature: string;
160
+ } | {
161
+ type: 'content_block_stop';
162
+ index: number;
163
+ } | {
164
+ type: 'message_delta';
165
+ stopReason?: StopReason;
166
+ stopSequence?: string | null;
167
+ usage?: PartialUsage; /** Raw wire provenance the IR cannot express, e.g. openai `finish_reason` (spec §4.2). */
168
+ extensions?: NodeExtensions;
169
+ } | {
170
+ type: 'message_stop';
171
+ } | {
172
+ type: 'ping';
173
+ } | {
174
+ type: 'usage';
175
+ usage: Usage;
176
+ } | {
177
+ type: 'error';
178
+ error: CanonicalError;
179
+ };
180
+ //#endregion
181
+ //#region src/ports.d.ts
182
+ type LoggerPort = {
183
+ info(message: string, context?: Record<string, unknown>): void;
184
+ warn(message: string, context?: Record<string, unknown>): void;
185
+ error(message: string, context?: Record<string, unknown>): void;
186
+ debug(message: string, context?: Record<string, unknown>): void;
187
+ };
188
+ type ClockPort = {
189
+ now(): number;
190
+ };
191
+ type RandomPort = {
192
+ uuid(): string;
193
+ };
194
+ //#endregion
195
+ //#region src/wire-format.d.ts
196
+ declare const WIRE_FORMATS: readonly ["anthropic-messages", "openai-chat"];
197
+ type WireFormat = (typeof WIRE_FORMATS)[number];
198
+ /**
199
+ * Format-reserved extension keys (spec §4.3): the only keys a plugin may write
200
+ * into `ir.extensions[format]`. Public contract — keep in sync with README.
201
+ */
202
+ declare const RESERVED_KEYS: Readonly<Record<WireFormat, readonly string[]>>;
203
+ /**
204
+ * Endpoint path each wire format owns (spec §5.1): the format adapter owns the
205
+ * version path; a provider `baseUrl` is everything before it. Consumed by
206
+ * domain routing for baseUrl validation and upstream URL construction.
207
+ */
208
+ declare const ENDPOINT_PATHS: Readonly<Record<WireFormat, string>>;
209
+ /**
210
+ * Inbound proxy-owned paths (spec §5.2): `/v1/models` is synthesized locally
211
+ * from the routing table; `/v1/responses` (openai-responses format) is
212
+ * deferred — classified to a 501 (§17), never a passthrough.
213
+ */
214
+ declare const MODELS_PATH = "/v1/models";
215
+ declare const DEFERRED_RESPONSES_PATH = "/v1/responses";
216
+ /**
217
+ * Session headers (spec §10a): the pipeline stamps the first present value onto
218
+ * `CanonicalRequest.clientSessionId`; the session-id plugin forwards it upstream.
219
+ */
220
+ declare const CLIENT_SESSION_ID_HEADER = "x-claude-code-session-id";
221
+ declare const SESSION_ID_HEADER = "x-session-id";
222
+ //#endregion
223
+ //#region src/plugin.d.ts
224
+ /**
225
+ * Plugin-initiated response without hitting upstream (spec §7).
226
+ * `error` XOR `events`: error is encoded to the client's wire-error format,
227
+ * events are encoded to the client's inbound format (format-agnostic mock).
228
+ * Raw-body mocks are intentionally NOT supported (D9).
229
+ */
230
+ type ShortCircuit = {
231
+ shortCircuit: true;
232
+ status: number;
233
+ headers?: Record<string, string>;
234
+ error?: CanonicalError;
235
+ events?: CanonicalEvent[];
236
+ } & ({
237
+ error: CanonicalError;
238
+ events?: never;
239
+ } | {
240
+ events?: CanonicalEvent[];
241
+ error?: never;
242
+ });
243
+ type PluginContext<TConfig = unknown> = {
244
+ requestId: string;
245
+ logger: LoggerPort;
246
+ clock: ClockPort;
247
+ random: RandomPort;
248
+ config: TConfig;
249
+ };
250
+ type ProxyPlugin<TConfig = unknown> = {
251
+ /** Unique instance id: dedup across config layers. */name: string;
252
+ validateConfig?(raw: unknown): TConfig;
253
+ /**
254
+ * Declares which format-reserved `$proxitor.` keys this plugin writes (spec §4.3).
255
+ * Config-time validation matches these against the provider's wireFormat.
256
+ */
257
+ reservedKeys?: Partial<Record<WireFormat, readonly string[]>>;
258
+ onRequest?(ctx: PluginContext<TConfig>, req: CanonicalRequest): Promise<CanonicalRequest | ShortCircuit> | CanonicalRequest | ShortCircuit;
259
+ onEvent?(ctx: PluginContext<TConfig>, event: CanonicalEvent): Promise<void> | void;
260
+ transformStream?(ctx: PluginContext<TConfig>, events: AsyncIterable<CanonicalEvent>): AsyncIterable<CanonicalEvent>;
261
+ onError?(ctx: PluginContext<TConfig>, error: CanonicalError): Promise<CanonicalError> | CanonicalError;
262
+ };
263
+ //#endregion
264
+ //#region src/define-plugin.d.ts
265
+ type PluginWithoutValidate<TConfig> = Omit<ProxyPlugin<TConfig>, 'validateConfig'>;
266
+ /**
267
+ * The only runtime helper in the package: attaches a zod-backed validateConfig
268
+ * to a plugin (spec §7). Overload without a schema passes the plugin through.
269
+ */
270
+ declare function definePlugin<TConfig>(plugin: ProxyPlugin<TConfig>): ProxyPlugin<TConfig>;
271
+ declare function definePlugin<TConfig>(schema: ZodType<TConfig>, plugin: PluginWithoutValidate<TConfig>): ProxyPlugin<TConfig>;
272
+ //#endregion
273
+ //#region src/index.d.ts
274
+ declare const PLUGIN_API_VERSION = "0.0.0";
275
+ //#endregion
276
+ export { CLIENT_SESSION_ID_HEADER, CacheControl, CanonicalContentBlock, CanonicalError, CanonicalEvent, CanonicalMessage, CanonicalParams, CanonicalRequest, CanonicalSystemBlock, CanonicalTool, CanonicalToolChoice, ClockPort, DEFERRED_RESPONSES_PATH, ENDPOINT_PATHS, ExtensionsBag, ImageSource, InputJsonDelta, LoggerPort, MODELS_PATH, MaxTokens, NodeExtensions, PLUGIN_API_VERSION, PartialUsage, PluginContext, ProxyPlugin, RESERVED_KEYS, RandomPort, ResponseFormat, SESSION_ID_HEADER, ShortCircuit, StopReason, TextDelta, ThinkingDelta, Usage, WIRE_FORMATS, WireFormat, definePlugin };
277
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/canonical/request.ts","../src/canonical/events.ts","../src/ports.ts","../src/wire-format.ts","../src/plugin.ts","../src/define-plugin.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,54 @@
1
+ //#region src/define-plugin.ts
2
+ function definePlugin(schemaOrPlugin, maybePlugin) {
3
+ if (maybePlugin === void 0) return schemaOrPlugin;
4
+ const schema = schemaOrPlugin;
5
+ return {
6
+ ...maybePlugin,
7
+ validateConfig: (raw) => schema.parse(raw)
8
+ };
9
+ }
10
+ //#endregion
11
+ //#region src/wire-format.ts
12
+ const WIRE_FORMATS = ["anthropic-messages", "openai-chat"];
13
+ /**
14
+ * Format-reserved extension keys (spec §4.3): the only keys a plugin may write
15
+ * into `ir.extensions[format]`. Public contract — keep in sync with README.
16
+ */
17
+ const RESERVED_KEYS = {
18
+ "anthropic-messages": [],
19
+ "openai-chat": [
20
+ "$proxitor.provider",
21
+ "$proxitor.models",
22
+ "$proxitor.route",
23
+ "$proxitor.transforms"
24
+ ]
25
+ };
26
+ /**
27
+ * Endpoint path each wire format owns (spec §5.1): the format adapter owns the
28
+ * version path; a provider `baseUrl` is everything before it. Consumed by
29
+ * domain routing for baseUrl validation and upstream URL construction.
30
+ */
31
+ const ENDPOINT_PATHS = {
32
+ "anthropic-messages": "/v1/messages",
33
+ "openai-chat": "/v1/chat/completions"
34
+ };
35
+ /**
36
+ * Inbound proxy-owned paths (spec §5.2): `/v1/models` is synthesized locally
37
+ * from the routing table; `/v1/responses` (openai-responses format) is
38
+ * deferred — classified to a 501 (§17), never a passthrough.
39
+ */
40
+ const MODELS_PATH = "/v1/models";
41
+ const DEFERRED_RESPONSES_PATH = "/v1/responses";
42
+ /**
43
+ * Session headers (spec §10a): the pipeline stamps the first present value onto
44
+ * `CanonicalRequest.clientSessionId`; the session-id plugin forwards it upstream.
45
+ */
46
+ const CLIENT_SESSION_ID_HEADER = "x-claude-code-session-id";
47
+ const SESSION_ID_HEADER = "x-session-id";
48
+ //#endregion
49
+ //#region src/index.ts
50
+ const PLUGIN_API_VERSION = "0.0.0";
51
+ //#endregion
52
+ export { CLIENT_SESSION_ID_HEADER, DEFERRED_RESPONSES_PATH, ENDPOINT_PATHS, MODELS_PATH, PLUGIN_API_VERSION, RESERVED_KEYS, SESSION_ID_HEADER, WIRE_FORMATS, definePlugin };
53
+
54
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/define-plugin.ts","../src/wire-format.ts","../src/index.ts"],"sourcesContent":["import type { ZodType } from 'zod';\nimport type { ProxyPlugin } from './plugin.js';\n\ntype PluginWithoutValidate<TConfig> = Omit<ProxyPlugin<TConfig>, 'validateConfig'>;\n\n/**\n * The only runtime helper in the package: attaches a zod-backed validateConfig\n * to a plugin (spec §7). Overload without a schema passes the plugin through.\n */\nexport function definePlugin<TConfig>(plugin: ProxyPlugin<TConfig>): ProxyPlugin<TConfig>;\nexport function definePlugin<TConfig>(\n schema: ZodType<TConfig>,\n plugin: PluginWithoutValidate<TConfig>,\n): ProxyPlugin<TConfig>;\nexport function definePlugin<TConfig>(\n schemaOrPlugin: ZodType<TConfig> | ProxyPlugin<TConfig>,\n maybePlugin?: PluginWithoutValidate<TConfig>,\n): ProxyPlugin<TConfig> {\n if (maybePlugin === undefined) {\n return schemaOrPlugin as ProxyPlugin<TConfig>;\n }\n const schema = schemaOrPlugin as ZodType<TConfig>;\n return {\n ...maybePlugin,\n validateConfig: (raw: unknown): TConfig => schema.parse(raw),\n };\n}\n","export const WIRE_FORMATS = ['anthropic-messages', 'openai-chat'] as const;\n\nexport type WireFormat = (typeof WIRE_FORMATS)[number];\n\n/**\n * Format-reserved extension keys (spec §4.3): the only keys a plugin may write\n * into `ir.extensions[format]`. Public contract — keep in sync with README.\n */\nexport const RESERVED_KEYS: Readonly<Record<WireFormat, readonly string[]>> = {\n 'anthropic-messages': [],\n 'openai-chat': [\n '$proxitor.provider',\n '$proxitor.models',\n '$proxitor.route',\n '$proxitor.transforms',\n ],\n};\n\n/**\n * Endpoint path each wire format owns (spec §5.1): the format adapter owns the\n * version path; a provider `baseUrl` is everything before it. Consumed by\n * domain routing for baseUrl validation and upstream URL construction.\n */\nexport const ENDPOINT_PATHS: Readonly<Record<WireFormat, string>> = {\n 'anthropic-messages': '/v1/messages',\n 'openai-chat': '/v1/chat/completions',\n};\n\n/**\n * Inbound proxy-owned paths (spec §5.2): `/v1/models` is synthesized locally\n * from the routing table; `/v1/responses` (openai-responses format) is\n * deferred — classified to a 501 (§17), never a passthrough.\n */\nexport const MODELS_PATH = '/v1/models';\nexport const DEFERRED_RESPONSES_PATH = '/v1/responses';\n\n/**\n * Session headers (spec §10a): the pipeline stamps the first present value onto\n * `CanonicalRequest.clientSessionId`; the session-id plugin forwards it upstream.\n */\nexport const CLIENT_SESSION_ID_HEADER = 'x-claude-code-session-id';\nexport const SESSION_ID_HEADER = 'x-session-id';\n","export const PLUGIN_API_VERSION = '0.0.0';\n\nexport * from './canonical/events.js';\nexport * from './canonical/request.js';\nexport * from './define-plugin.js';\nexport * from './plugin.js';\nexport * from './ports.js';\nexport * from './wire-format.js';\n"],"mappings":";AAcA,SAAgB,aACd,gBACA,aACsB;CACtB,IAAI,gBAAgB,KAAA,GAClB,OAAO;CAET,MAAM,SAAS;CACf,OAAO;EACL,GAAG;EACH,iBAAiB,QAA0B,OAAO,MAAM,GAAG;CAC7D;AACF;;;AC1BA,MAAa,eAAe,CAAC,sBAAsB,aAAa;;;;;AAQhE,MAAa,gBAAiE;CAC5E,sBAAsB,CAAC;CACvB,eAAe;EACb;EACA;EACA;EACA;CACF;AACF;;;;;;AAOA,MAAa,iBAAuD;CAClE,sBAAsB;CACtB,eAAe;AACjB;;;;;;AAOA,MAAa,cAAc;AAC3B,MAAa,0BAA0B;;;;;AAMvC,MAAa,2BAA2B;AACxC,MAAa,oBAAoB;;;ACzCjC,MAAa,qBAAqB"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@proxitor/plugin-api",
3
+ "version": "0.1.0-beta.0",
4
+ "description": "Published proxitor plugin contract: Canonical IR, plugin hooks, ports",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./src/index.ts",
10
+ "import": "./src/index.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsdown",
18
+ "test": "vitest run",
19
+ "test:types": "vitest run --typecheck",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "devDependencies": {
23
+ "tsdown": "^0.22.1",
24
+ "vitest": "^4.1.8",
25
+ "zod": "^4.4.3"
26
+ },
27
+ "peerDependencies": {
28
+ "zod": "^4.0.0"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ }
37
+ }
38
+ }
39
+ }