@xamukavila/pxpipe 0.8.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +312 -0
  3. package/bin/cli.js +7 -0
  4. package/dist/core/applicability.d.ts +31 -0
  5. package/dist/core/applicability.js +96 -0
  6. package/dist/core/atlas-gray.d.ts +26 -0
  7. package/dist/core/atlas-gray.js +64 -0
  8. package/dist/core/atlas.d.ts +34 -0
  9. package/dist/core/atlas.js +71 -0
  10. package/dist/core/baseline.d.ts +80 -0
  11. package/dist/core/baseline.js +101 -0
  12. package/dist/core/caveman.d.ts +38 -0
  13. package/dist/core/caveman.js +183 -0
  14. package/dist/core/export.d.ts +128 -0
  15. package/dist/core/export.js +390 -0
  16. package/dist/core/factsheet.d.ts +78 -0
  17. package/dist/core/factsheet.js +216 -0
  18. package/dist/core/gpt-model-profiles.d.ts +60 -0
  19. package/dist/core/gpt-model-profiles.js +161 -0
  20. package/dist/core/history.d.ts +141 -0
  21. package/dist/core/history.js +553 -0
  22. package/dist/core/index.d.ts +8 -0
  23. package/dist/core/index.js +8 -0
  24. package/dist/core/library.d.ts +74 -0
  25. package/dist/core/library.js +133 -0
  26. package/dist/core/measurement.d.ts +22 -0
  27. package/dist/core/measurement.js +213 -0
  28. package/dist/core/openai-history.d.ts +124 -0
  29. package/dist/core/openai-history.js +494 -0
  30. package/dist/core/openai-savings.d.ts +44 -0
  31. package/dist/core/openai-savings.js +75 -0
  32. package/dist/core/openai.d.ts +24 -0
  33. package/dist/core/openai.js +839 -0
  34. package/dist/core/png.d.ts +11 -0
  35. package/dist/core/png.js +132 -0
  36. package/dist/core/proxy.d.ts +81 -0
  37. package/dist/core/proxy.js +730 -0
  38. package/dist/core/render.d.ts +188 -0
  39. package/dist/core/render.js +785 -0
  40. package/dist/core/schema-strip.d.ts +29 -0
  41. package/dist/core/schema-strip.js +160 -0
  42. package/dist/core/tracker.d.ts +154 -0
  43. package/dist/core/tracker.js +216 -0
  44. package/dist/core/transform.d.ts +362 -0
  45. package/dist/core/transform.js +1828 -0
  46. package/dist/core/types.d.ts +77 -0
  47. package/dist/core/types.js +8 -0
  48. package/dist/dashboard/fragments.d.ts +36 -0
  49. package/dist/dashboard/fragments.js +938 -0
  50. package/dist/dashboard/types.d.ts +154 -0
  51. package/dist/dashboard/types.js +3 -0
  52. package/dist/dashboard/vendor.d.ts +3 -0
  53. package/dist/dashboard/vendor.js +6 -0
  54. package/dist/dashboard.d.ts +245 -0
  55. package/dist/dashboard.js +1140 -0
  56. package/dist/export-collect.d.ts +36 -0
  57. package/dist/export-collect.js +59 -0
  58. package/dist/node.d.ts +9 -0
  59. package/dist/node.js +9038 -0
  60. package/dist/sessions.d.ts +172 -0
  61. package/dist/sessions.js +510 -0
  62. package/dist/stats.d.ts +74 -0
  63. package/dist/stats.js +248 -0
  64. package/dist/worker.d.ts +53 -0
  65. package/dist/worker.js +102 -0
  66. package/package.json +96 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Minimal PNG encoder (grayscale + RGB, 8-bit, filter=None, single IDAT).
3
+ * Pure Uint8Array — uses CompressionStream (Node 18+, Workers, browsers); no Buffer/node:zlib.
4
+ */
5
+ /** Encode a single-channel (grayscale) buffer as PNG bytes. pixels is row-major, length = width × height. */
6
+ export declare function encodeGrayPng(pixels: Uint8Array, width: number, height: number): Promise<Uint8Array>;
7
+ /** Encode an RGB (3 bytes/pixel, R,G,B) buffer as PNG bytes (colorType 2 = truecolor). length = width × height × 3. */
8
+ export declare function encodeRgbPng(pixels: Uint8Array, width: number, height: number): Promise<Uint8Array>;
9
+ /** Base64-encode bytes. Chunks to avoid call-stack blow-up from String.fromCharCode(...bigArray). */
10
+ export declare function bytesToBase64(bytes: Uint8Array): string;
11
+ //# sourceMappingURL=png.d.ts.map
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Minimal PNG encoder (grayscale + RGB, 8-bit, filter=None, single IDAT).
3
+ * Pure Uint8Array — uses CompressionStream (Node 18+, Workers, browsers); no Buffer/node:zlib.
4
+ */
5
+ // ---- CRC32 ---------------------------------------------------------------
6
+ const CRC_TABLE = (() => {
7
+ const t = new Uint32Array(256);
8
+ for (let n = 0; n < 256; n++) {
9
+ let c = n;
10
+ for (let k = 0; k < 8; k++)
11
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
12
+ t[n] = c >>> 0;
13
+ }
14
+ return t;
15
+ })();
16
+ function crc32(bytes) {
17
+ let c = 0xffffffff;
18
+ for (let i = 0; i < bytes.length; i++)
19
+ c = CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8);
20
+ return (c ^ 0xffffffff) >>> 0;
21
+ }
22
+ // ---- Helpers -------------------------------------------------------------
23
+ function concat(parts) {
24
+ let total = 0;
25
+ for (const p of parts)
26
+ total += p.length;
27
+ const out = new Uint8Array(total);
28
+ let off = 0;
29
+ for (const p of parts) {
30
+ out.set(p, off);
31
+ off += p.length;
32
+ }
33
+ return out;
34
+ }
35
+ function u32be(n) {
36
+ const b = new Uint8Array(4);
37
+ new DataView(b.buffer).setUint32(0, n >>> 0, false);
38
+ return b;
39
+ }
40
+ const TYPE_BYTES = (s) => {
41
+ const b = new Uint8Array(s.length);
42
+ for (let i = 0; i < s.length; i++)
43
+ b[i] = s.charCodeAt(i);
44
+ return b;
45
+ };
46
+ function chunk(type, data) {
47
+ const typeB = TYPE_BYTES(type);
48
+ const crcSrc = concat([typeB, data]);
49
+ return concat([u32be(data.length), typeB, data, u32be(crc32(crcSrc))]);
50
+ }
51
+ // ---- Deflate via Web Streams ---------------------------------------------
52
+ async function deflateZlib(input) {
53
+ // 'deflate' = RFC 1950 zlib-wrapped — what PNG IDAT needs. 'deflate-raw' (RFC 1951) would be wrong.
54
+ const cs = new CompressionStream('deflate');
55
+ const writer = cs.writable.getWriter();
56
+ // TS 5.7 narrows Uint8Array<ArrayBufferLike> away from BufferSource; safe since we never use SharedArrayBuffer.
57
+ void writer.write(input);
58
+ void writer.close();
59
+ const reader = cs.readable.getReader();
60
+ const chunks = [];
61
+ while (true) {
62
+ const { value, done } = await reader.read();
63
+ if (done)
64
+ break;
65
+ if (value)
66
+ chunks.push(value);
67
+ }
68
+ return concat(chunks);
69
+ }
70
+ // ---- Encode --------------------------------------------------------------
71
+ const PNG_SIGNATURE = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
72
+ /** Encode a single-channel (grayscale) buffer as PNG bytes. pixels is row-major, length = width × height. */
73
+ export async function encodeGrayPng(pixels, width, height) {
74
+ if (pixels.length !== width * height) {
75
+ throw new Error(`encodeGrayPng: pixels.length=${pixels.length} != ${width}×${height}=${width * height}`);
76
+ }
77
+ // IHDR: width(4) height(4) bitDepth=8 colorType=0(gray) compress=0 filter=0 interlace=0
78
+ const ihdr = new Uint8Array(13);
79
+ ihdr.set(u32be(width), 0);
80
+ ihdr.set(u32be(height), 4);
81
+ ihdr[8] = 8;
82
+ ihdr[9] = 0; // colorType 0 = grayscale; bytes 10-12 already zero
83
+ // Prepend per-scanline filter byte (0 = None).
84
+ const stride = width + 1;
85
+ const raw = new Uint8Array(stride * height);
86
+ for (let y = 0; y < height; y++) {
87
+ raw[y * stride] = 0; // filter: None
88
+ raw.set(pixels.subarray(y * width, (y + 1) * width), y * stride + 1);
89
+ }
90
+ const compressed = await deflateZlib(raw);
91
+ return concat([
92
+ PNG_SIGNATURE,
93
+ chunk('IHDR', ihdr),
94
+ chunk('IDAT', compressed),
95
+ chunk('IEND', new Uint8Array(0)),
96
+ ]);
97
+ }
98
+ /** Encode an RGB (3 bytes/pixel, R,G,B) buffer as PNG bytes (colorType 2 = truecolor). length = width × height × 3. */
99
+ export async function encodeRgbPng(pixels, width, height) {
100
+ if (pixels.length !== width * height * 3) {
101
+ throw new Error(`encodeRgbPng: pixels.length=${pixels.length} != ${width}×${height}×3=${width * height * 3}`);
102
+ }
103
+ const ihdr = new Uint8Array(13);
104
+ ihdr.set(u32be(width), 0);
105
+ ihdr.set(u32be(height), 4);
106
+ ihdr[8] = 8; // bit depth per channel
107
+ ihdr[9] = 2; // colorType 2 = truecolor RGB; bytes 10-12 already zero
108
+ // Prepend per-scanline filter byte (0 = None).
109
+ const stride = width * 3 + 1;
110
+ const raw = new Uint8Array(stride * height);
111
+ for (let y = 0; y < height; y++) {
112
+ raw[y * stride] = 0; // filter: None
113
+ raw.set(pixels.subarray(y * width * 3, (y + 1) * width * 3), y * stride + 1);
114
+ }
115
+ const compressed = await deflateZlib(raw);
116
+ return concat([
117
+ PNG_SIGNATURE,
118
+ chunk('IHDR', ihdr),
119
+ chunk('IDAT', compressed),
120
+ chunk('IEND', new Uint8Array(0)),
121
+ ]);
122
+ }
123
+ /** Base64-encode bytes. Chunks to avoid call-stack blow-up from String.fromCharCode(...bigArray). */
124
+ export function bytesToBase64(bytes) {
125
+ let binary = '';
126
+ const CHUNK = 0x8000;
127
+ for (let i = 0; i < bytes.length; i += CHUNK) {
128
+ binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
129
+ }
130
+ return btoa(binary);
131
+ }
132
+ //# sourceMappingURL=png.js.map
@@ -0,0 +1,81 @@
1
+ /**
2
+ * pxpipe proxy as a single Web-standard fetch handler.
3
+ * Adapted by src/node.ts and src/worker.ts; uses only Request/Response/URL/fetch.
4
+ */
5
+ import { type TransformOptions, type TransformInfo } from './transform.js';
6
+ import type { Usage } from './types.js';
7
+ export interface ProxyConfig {
8
+ /** 'cloudflare-ai-gateway': routes both families through gatewayBaseUrl;
9
+ * OpenAI paths drop the `/v1` prefix to match gateway shape. */
10
+ provider?: 'cloudflare-ai-gateway';
11
+ /** Gateway base URL (account/gateway-scoped). Required when provider is set. */
12
+ gatewayBaseUrl?: string;
13
+ /** Extra headers injected on every upstream request (e.g. gateway auth). */
14
+ gatewayHeaders?: Record<string, string>;
15
+ /** Anthropic API base, no trailing slash. Defaults to api.anthropic.com. */
16
+ upstream?: string;
17
+ /** Override or supply an API key. If unset, we forward whatever the client sent. */
18
+ apiKey?: string;
19
+ /** OpenAI API base for GPT chat completions, no trailing slash. */
20
+ openAIUpstream?: string;
21
+ /** Override or supply an OpenAI API key. If unset, we forward Authorization. */
22
+ openAIApiKey?: string;
23
+ /** Pass a function to inject dynamic values per-request (e.g. live charsPerToken);
24
+ * static object for Workers/tests. */
25
+ transform?: TransformOptions | (() => TransformOptions);
26
+ /** Called after every request — useful for logging / metrics in the host. */
27
+ onRequest?: (event: ProxyEvent) => void | Promise<void>;
28
+ }
29
+ export interface ProxyEvent {
30
+ method: string;
31
+ path: string;
32
+ /** Top-level request model when present. Used for telemetry/dashboard labels only. */
33
+ model?: string;
34
+ status: number;
35
+ /** Wall-clock ms from request start to event fire (≈ end of upstream body). */
36
+ durationMs: number;
37
+ /** Wall-clock ms from request start to upstream response headers. */
38
+ firstByteMs?: number;
39
+ info?: TransformInfo;
40
+ /** Usage block from Anthropic's response — input/output/cache tokens. */
41
+ usage?: Usage;
42
+ /** Model stop reason from the response ("end_turn", "tool_use", "max_tokens",
43
+ * "refusal", …). "refusal" = safety classifier fired on the transformed request —
44
+ * scorers must fail cost comparisons on refusal rows (refusals emit almost no
45
+ * output and would otherwise look "cheaper"). OpenAI finish_reason ("stop",
46
+ * "length", "content_filter", …) is normalized into the same field. */
47
+ stopReason?: string;
48
+ error?: string;
49
+ /** First ~2 KiB of the upstream 4xx body (not captured on 2xx or 5xx). */
50
+ errorBody?: string;
51
+ /** sha256[0..8] of the transformed outgoing body — set on every /v1/messages POST for correlation. */
52
+ reqBodySha8?: string;
53
+ /** Gzipped transformed body, populated only on 4xx. Node may write to sidecar (see reqBodySamplePath). */
54
+ reqBodyGz?: Uint8Array;
55
+ /** Set by the Node host instead of reqBodyGz when the body was written to a sidecar file. */
56
+ reqBodySamplePath?: string;
57
+ /** Ground-truth char counts from the response stream, independent of usage.output_tokens.
58
+ * Absent when the body couldn't be scanned (5xx, unknown content-type). See OutputMeasurement. */
59
+ measurement?: OutputMeasurement;
60
+ }
61
+ /**
62
+ * Ground-truth char counts from the response stream, independent of usage.output_tokens.
63
+ * redactedBlockCount blocks are opaque server bytes — no char count available for those.
64
+ */
65
+ export interface OutputMeasurement {
66
+ textChars: number;
67
+ thinkingChars: number;
68
+ toolUseChars: number;
69
+ redactedBlockCount: number;
70
+ }
71
+ /** Resolve upstream URLs from config. Pure — unit-testable. */
72
+ export declare function resolveUpstreams(config: ProxyConfig): {
73
+ anthropic: string;
74
+ openai: string;
75
+ stripOpenAIV1: boolean;
76
+ };
77
+ /** Parse PXPIPE_GATEWAY_HEADERS — JSON object or `k=v;k2=v2`. */
78
+ export declare function parseGatewayHeaders(spec: string | undefined): Record<string, string>;
79
+ /** Build the proxy fetch handler. */
80
+ export declare function createProxy(config?: ProxyConfig): (req: Request) => Promise<Response>;
81
+ //# sourceMappingURL=proxy.d.ts.map