sovergate 0.1.0-alpha.1 → 0.1.0-alpha.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Roberto Postolovski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,14 +1,33 @@
1
- # sovergate — TypeScript SDK
1
+ # sovergate
2
2
 
3
- EU AI Act Article 12 compliance — automatic, non-invasive audit logging for LLM calls.
3
+ TypeScript / JavaScript SDK for [Sovergate](https://sovergate.com): EU AI Act
4
+ Article 12 audit logging for LLM calls, with PII scrubbed inside your own
5
+ infrastructure.
6
+
7
+ > **Early access.** The SDK is published as an alpha and the hosted ingest
8
+ > service is not generally available yet. APIs may change before 1.0.
9
+
10
+ ## How it works
11
+
12
+ Your app keeps calling OpenAI or Anthropic directly. Sovergate does not proxy
13
+ or intercept the request. After a call completes, the SDK takes a copy,
14
+ scrubs personal data **locally**, and sends the scrubbed copy to Sovergate in
15
+ the background.
16
+
17
+ ```
18
+ Your app ─────────────────────────────► OpenAI / Anthropic
19
+ │
20
+ └──► scrub PII locally ──► Sovergate (async, fire and forget)
21
+ ```
4
22
 
5
23
  ## Install
6
24
 
7
25
  ```bash
8
- npm install sovergate
26
+ npm install sovergate@alpha
9
27
  ```
10
28
 
11
- Requires Node.js 18+.
29
+ Requires Node.js 18+. Ships ESM and CommonJS builds with TypeScript types.
30
+ No runtime dependencies.
12
31
 
13
32
  ## Quick start
14
33
 
@@ -21,12 +40,12 @@ const openai = new OpenAI()
21
40
  init({ apiKey: 'sov_prod_xxxx' })
22
41
  instrument(openai)
23
42
 
24
- // Your existing code is completely unchanged
43
+ // Your existing code is unchanged
25
44
  const response = await openai.chat.completions.create({
26
45
  model: 'gpt-4o',
27
46
  messages: [{ role: 'user', content: 'Hello' }],
28
47
  })
29
- // Response returned immediately — logging fires in background
48
+ // The response is returned immediately; logging happens in the background
30
49
  ```
31
50
 
32
51
  Anthropic works the same way:
@@ -40,26 +59,109 @@ init({ apiKey: 'sov_prod_xxxx' })
40
59
  instrument(client)
41
60
  ```
42
61
 
62
+ ### Streaming
63
+
64
+ Streamed calls are logged too: `create({ stream: true })` on both providers, plus
65
+ the `chat.completions.stream()` and `messages.stream()` helpers. Your app gets
66
+ the same stream object and every chunk unchanged as soon as it arrives; the SDK
67
+ keeps a copy of the text and logs it once the stream ends. If your app stops
68
+ reading part-way, what it had received up to that point is logged.
69
+
70
+ OpenAI only reports token counts for a stream when you ask for them:
71
+
72
+ ```ts
73
+ client.chat.completions.create({ ..., stream: true, stream_options: { include_usage: true } })
74
+ ```
75
+
76
+ Without that option the record is still logged, with 0 tokens. The SDK never
77
+ adds the option itself, because it changes the chunks your app receives.
78
+
79
+ ## Stable PII tokens (recommended)
80
+
81
+ By default, detected PII is replaced with positional placeholders
82
+ (`[EMAIL_REDACTED_1]`), which are not correlatable between logs. Pass a
83
+ `piiKey` to replace values with deterministic, irreversible HMAC-SHA256 tokens
84
+ instead. The same value always maps to the same token, so Sovergate can count
85
+ unique people, IBANs and so on without ever receiving the raw values.
86
+
87
+ ```typescript
88
+ init({ apiKey: 'sov_prod_xxxx', piiKey: process.env.SOVERGATE_PII_KEY })
89
+ ```
90
+
91
+ The `piiKey` is your secret. Keep it stable, and never send it to us: it stays
92
+ on your infrastructure, and without it the tokens cannot be reversed. The Python
93
+ SDK produces the same tokens for the same key, so services in both languages
94
+ count a person once.
95
+
43
96
  ## Options
44
97
 
45
98
  ```typescript
46
99
  init({
47
100
  apiKey: 'sov_prod_xxxx', // required
48
- baseUrl: 'https://...', // default: https://api.sovergate.com
49
- debug: true, // print SDK internals to console.debug
101
+ baseUrl: 'https://...', // default: https://api.sovergate.com
102
+ piiKey: '<your-secret>', // stable PII tokens (see above)
103
+ debug: true, // print SDK internals to console.debug
50
104
  })
51
105
  ```
52
106
 
107
+ ## What is sent to Sovergate
108
+
109
+ For each completed call, one JSON record:
110
+
111
+ | Field | Content |
112
+ |---|---|
113
+ | `model` | Model name returned by the provider |
114
+ | `messages` | Your prompt messages, **after** PII scrubbing |
115
+ | `response` | The model's text output, **after** PII scrubbing |
116
+ | `prompt_tokens`, `completion_tokens` | Token counts from the provider |
117
+ | `latency_ms`, `timestamp` | Call duration and start time |
118
+ | `finish_reason` | Why the model stopped |
119
+ | `pii_detections` | Category and placeholder of each scrubbed item, never the original value |
120
+
121
+ Never sent: the raw prompt or response, your LLM provider API key, or request
122
+ headers.
123
+
124
+ ### What the scrubber detects
125
+
126
+ Regex-based, applied to every text part of the prompt and response: email
127
+ addresses, IP addresses, IBANs, phone numbers, dates of birth, ID numbers, and
128
+ names that follow a title (Mr, Mrs, Ms, Dr, Prof). Other personal data, such
129
+ as names without a title, is **not** detected yet, so keep data minimisation in
130
+ mind when you build prompts. The code is in [`src/scrubber.ts`](src/scrubber.ts).
131
+
53
132
  ## Guarantees
54
133
 
55
- - Never blocks the event loop — logging runs via `setImmediate`
56
- - Never throws — if setup fails, the SDK logs a `console.warn` and stays out of the way
57
- - Leaves your client unchanged — `create()` still returns the SDK's own object, so `.withResponse()` and `.asResponse()` keep working
58
- - 2 second timeout on every HTTP call to our servers
59
- - Queues locally and retries with exponential backoff if our servers are down
60
- - PII is scrubbed **before** any data leaves your infrastructure
134
+ - Never blocks the event loop: logging runs via `setImmediate`
135
+ - Never keeps your process alive: a script or job exits normally even while
136
+ records are waiting to be retried
137
+ - Never throws: if setup fails, the SDK logs a `console.warn` and stays out of the way
138
+ - Leaves your client unchanged: `create()` still returns the provider SDK's own
139
+ object, so `.withResponse()` and `.asResponse()` keep working, and streams keep
140
+ their `.controller`, `.tee()` and `.toReadableStream()`
141
+ - 2 second timeout on every HTTP call to Sovergate
142
+ - If Sovergate is unreachable, records are queued in memory (up to 10,000) and
143
+ retried with exponential backoff
144
+ - A record Sovergate permanently rejects (for example after a key is revoked) is
145
+ dropped with a `console.warn`, so it never blocks the records behind it
61
146
 
62
147
  ## Current limitations
63
148
 
64
- - Streaming calls (`stream: true`) are passed through untouched but not logged yet.
65
- - PII placeholders are positional (`[EMAIL_REDACTED_1]`) and not correlatable across logs.
149
+ - Only the text of a response is logged, streamed or not; tool calls are not.
150
+ - The retry queue is in memory, so queued records are lost if the process exits.
151
+
152
+ ## Development
153
+
154
+ ```bash
155
+ npm ci
156
+ npm run typecheck
157
+ npm test
158
+ npm run build
159
+ ```
160
+
161
+ ## Security
162
+
163
+ Please report vulnerabilities privately. See [SECURITY.md](SECURITY.md).
164
+
165
+ ## License
166
+
167
+ [MIT](LICENSE)
package/dist/index.d.mts CHANGED
@@ -1,9 +1,16 @@
1
1
  interface InitOptions {
2
2
  apiKey: string;
3
3
  baseUrl?: string;
4
+ /**
5
+ * Secret used to turn detected personal data into stable, irreversible tokens.
6
+ * The same value always maps to the same token, so Sovergate can count unique
7
+ * people without holding the data. Keep it secret and stable: it never leaves
8
+ * your infrastructure. Without it, placeholders are numbered per record.
9
+ */
10
+ piiKey?: string;
4
11
  debug?: boolean;
5
12
  }
6
- declare function init({ apiKey, baseUrl, debug }: InitOptions): void;
13
+ declare function init({ apiKey, baseUrl, piiKey, debug }: InitOptions): void;
7
14
  declare function instrument(client: any): void;
8
15
  declare function shutdown(): void;
9
16
 
package/dist/index.d.ts CHANGED
@@ -1,9 +1,16 @@
1
1
  interface InitOptions {
2
2
  apiKey: string;
3
3
  baseUrl?: string;
4
+ /**
5
+ * Secret used to turn detected personal data into stable, irreversible tokens.
6
+ * The same value always maps to the same token, so Sovergate can count unique
7
+ * people without holding the data. Keep it secret and stable: it never leaves
8
+ * your infrastructure. Without it, placeholders are numbered per record.
9
+ */
10
+ piiKey?: string;
4
11
  debug?: boolean;
5
12
  }
6
- declare function init({ apiKey, baseUrl, debug }: InitOptions): void;
13
+ declare function init({ apiKey, baseUrl, piiKey, debug }: InitOptions): void;
7
14
  declare function instrument(client: any): void;
8
15
  declare function shutdown(): void;
9
16