offrouter-core 0.2.1 → 0.3.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/dist/audit.d.ts +137 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +320 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth/credential-chain.d.ts +84 -0
- package/dist/auth/credential-chain.d.ts.map +1 -0
- package/dist/auth/credential-chain.js +150 -0
- package/dist/auth/credential-chain.js.map +1 -0
- package/dist/auth/index.d.ts +10 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +7 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/keychain.d.ts +60 -0
- package/dist/auth/keychain.d.ts.map +1 -0
- package/dist/auth/keychain.js +104 -0
- package/dist/auth/keychain.js.map +1 -0
- package/dist/auth/oauth-pkce.d.ts +185 -0
- package/dist/auth/oauth-pkce.d.ts.map +1 -0
- package/dist/auth/oauth-pkce.js +558 -0
- package/dist/auth/oauth-pkce.js.map +1 -0
- package/dist/auth/oauth-server.d.ts +38 -0
- package/dist/auth/oauth-server.d.ts.map +1 -0
- package/dist/auth/oauth-server.js +295 -0
- package/dist/auth/oauth-server.js.map +1 -0
- package/dist/config.d.ts +76 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +355 -0
- package/dist/config.js.map +1 -0
- package/dist/delegation.d.ts +123 -0
- package/dist/delegation.d.ts.map +1 -0
- package/dist/delegation.js +455 -0
- package/dist/delegation.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/policy.d.ts +45 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +318 -0
- package/dist/policy.js.map +1 -0
- package/{src/protocol.ts → dist/protocol.d.ts} +2 -2
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +6 -0
- package/dist/protocol.js.map +1 -0
- package/dist/providers/adapter.d.ts +137 -0
- package/dist/providers/adapter.d.ts.map +1 -0
- package/dist/providers/adapter.js +163 -0
- package/dist/providers/adapter.js.map +1 -0
- package/dist/providers/catalog-data.d.ts +128 -0
- package/dist/providers/catalog-data.d.ts.map +1 -0
- package/dist/providers/catalog-data.js +397 -0
- package/dist/providers/catalog-data.js.map +1 -0
- package/dist/providers/catalog.d.ts +63 -0
- package/dist/providers/catalog.d.ts.map +1 -0
- package/dist/providers/catalog.js +394 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/fake.d.ts +46 -0
- package/dist/providers/fake.d.ts.map +1 -0
- package/dist/providers/fake.js +234 -0
- package/dist/providers/fake.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +65 -0
- package/dist/providers/openai-compatible.d.ts.map +1 -0
- package/dist/providers/openai-compatible.js +434 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/proxy/responses-mapper.d.ts +366 -0
- package/dist/proxy/responses-mapper.d.ts.map +1 -0
- package/dist/proxy/responses-mapper.js +517 -0
- package/dist/proxy/responses-mapper.js.map +1 -0
- package/dist/proxy/responses-server.d.ts +29 -0
- package/dist/proxy/responses-server.d.ts.map +1 -0
- package/dist/proxy/responses-server.js +360 -0
- package/dist/proxy/responses-server.js.map +1 -0
- package/dist/router.d.ts +18 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +296 -0
- package/dist/router.js.map +1 -0
- package/dist/schemas.d.ts +560 -0
- package/dist/schemas.d.ts.map +1 -0
- package/{src/schemas.ts → dist/schemas.js} +83 -103
- package/dist/schemas.js.map +1 -0
- package/dist/secrets.d.ts +112 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +326 -0
- package/dist/secrets.js.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/usage-file.d.ts +59 -0
- package/dist/usage-file.d.ts.map +1 -0
- package/dist/usage-file.js +316 -0
- package/dist/usage-file.js.map +1 -0
- package/dist/usage.d.ts +235 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +517 -0
- package/dist/usage.js.map +1 -0
- package/package.json +7 -2
- package/src/audit.test.ts +0 -302
- package/src/audit.ts +0 -553
- package/src/auth/credential-chain.test.ts +0 -326
- package/src/auth/credential-chain.ts +0 -235
- package/src/auth/index.ts +0 -45
- package/src/auth/keychain.test.ts +0 -265
- package/src/auth/keychain.ts +0 -168
- package/src/auth/oauth-pkce.test.ts +0 -329
- package/src/auth/oauth-pkce.ts +0 -571
- package/src/auth/oauth-server.test.ts +0 -83
- package/src/auth/oauth-server.ts +0 -296
- package/src/config.test.ts +0 -479
- package/src/config.ts +0 -505
- package/src/delegation.test.ts +0 -368
- package/src/delegation.ts +0 -605
- package/src/index.ts +0 -280
- package/src/policy.test.ts +0 -634
- package/src/policy.ts +0 -420
- package/src/providers/adapter.test.ts +0 -293
- package/src/providers/adapter.ts +0 -328
- package/src/providers/catalog-data.test.ts +0 -258
- package/src/providers/catalog-data.ts +0 -498
- package/src/providers/catalog.test.ts +0 -84
- package/src/providers/catalog.ts +0 -483
- package/src/providers/fake.ts +0 -312
- package/src/providers/openai-compatible.test.ts +0 -366
- package/src/providers/openai-compatible.ts +0 -554
- package/src/proxy/responses-mapper.test.ts +0 -290
- package/src/proxy/responses-mapper.ts +0 -736
- package/src/proxy/responses-server.test.ts +0 -322
- package/src/proxy/responses-server.ts +0 -469
- package/src/router.test.ts +0 -699
- package/src/router.ts +0 -352
- package/src/schemas.test.ts +0 -291
- package/src/secrets.test.ts +0 -271
- package/src/secrets.ts +0 -461
- package/src/types.ts +0 -173
- package/src/usage-file.test.ts +0 -243
- package/src/usage-file.ts +0 -435
- package/src/usage.test.ts +0 -335
- package/src/usage.ts +0 -859
- package/tsconfig.json +0 -9
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local OAuth callback server for OffRouter's live PKCE login flow.
|
|
3
|
+
*
|
|
4
|
+
* Binds to 127.0.0.1 ONLY (never 0.0.0.0) so the provider can redirect back
|
|
5
|
+
* to this machine without exposing the callback to the network. The server
|
|
6
|
+
* captures the authorization `code` + `state` from the redirect and hands them
|
|
7
|
+
* to the caller; it never touches tokens, secrets, or the network beyond the
|
|
8
|
+
* single loopback HTTP socket.
|
|
9
|
+
*/
|
|
10
|
+
import { createServer } from "node:http";
|
|
11
|
+
import { URL } from "node:url";
|
|
12
|
+
/** Loopback-only hostname. Hardcoded to prevent accidental 0.0.0.0 binds. */
|
|
13
|
+
const LOOPBACK_HOST = "127.0.0.1";
|
|
14
|
+
/** Path the provider redirects to (http://localhost:PORT/callback). */
|
|
15
|
+
const CALLBACK_PATH = "/callback";
|
|
16
|
+
/**
|
|
17
|
+
* Start a loopback HTTP server that captures an OAuth authorization code.
|
|
18
|
+
* Pass port 0 to let the OS choose a free port (read handle.port afterwards).
|
|
19
|
+
*/
|
|
20
|
+
export function startCallbackServer(port, options = {}) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const serverLevelState = options.expectedState;
|
|
23
|
+
const effectiveCallbackPath = options.callbackPath ?? CALLBACK_PATH;
|
|
24
|
+
// Deferred for the first valid callback (has a `code` param).
|
|
25
|
+
let captured = null;
|
|
26
|
+
const waiters = [];
|
|
27
|
+
const httpServer = createServer((req, res) => {
|
|
28
|
+
handleCallback(req, res);
|
|
29
|
+
});
|
|
30
|
+
function handleCallback(req, res) {
|
|
31
|
+
// Only respond to GET on the callback path; everything else 404s.
|
|
32
|
+
if (req.method !== "GET") {
|
|
33
|
+
res.writeHead(405, { "content-type": "text/plain; charset=utf-8" });
|
|
34
|
+
res.end("Method Not Allowed");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let parsedUrl;
|
|
38
|
+
try {
|
|
39
|
+
parsedUrl = new URL(req.url ?? "/", `http://${LOOPBACK_HOST}`);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
|
|
43
|
+
res.end("Bad Request");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const pathname = parsedUrl.pathname;
|
|
47
|
+
const code = parsedUrl.searchParams.get("code");
|
|
48
|
+
const state = parsedUrl.searchParams.get("state");
|
|
49
|
+
const error = parsedUrl.searchParams.get("error");
|
|
50
|
+
// OAuth error from the provider (e.g. user denied consent).
|
|
51
|
+
if (error) {
|
|
52
|
+
res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
53
|
+
res.end(authorizationDeniedPage(error));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (pathname !== effectiveCallbackPath) {
|
|
57
|
+
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
58
|
+
res.end("Not Found");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Missing code -> provider returned nothing usable.
|
|
62
|
+
if (!code) {
|
|
63
|
+
res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
64
|
+
res.end(missingCodePage());
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Capture the first valid callback exactly once.
|
|
68
|
+
const callback = { code, state: state ?? "" };
|
|
69
|
+
if (!captured) {
|
|
70
|
+
captured = callback;
|
|
71
|
+
// Resolve any pending waiters that accept this callback.
|
|
72
|
+
const pending = waiters.splice(0, waiters.length);
|
|
73
|
+
for (const w of pending) {
|
|
74
|
+
w.resolve(callback);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Always show the user a friendly page; security validation happens in
|
|
78
|
+
// waitForCode (state may not be known at request time).
|
|
79
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
80
|
+
res.end(successPage());
|
|
81
|
+
}
|
|
82
|
+
httpServer.on("error", (err) => {
|
|
83
|
+
reject(new Error(`Failed to start OAuth callback server on 127.0.0.1:${port}: ${err.message}`, { cause: err }));
|
|
84
|
+
});
|
|
85
|
+
httpServer.listen(port, LOOPBACK_HOST, () => {
|
|
86
|
+
const address = httpServer.address();
|
|
87
|
+
const boundPort = address && typeof address === "object" ? address.port : port;
|
|
88
|
+
const redirectUrl = `http://localhost:${boundPort}${effectiveCallbackPath}`;
|
|
89
|
+
const handle = {
|
|
90
|
+
url: redirectUrl,
|
|
91
|
+
port: boundPort,
|
|
92
|
+
waitForCode(waitOpts = {}) {
|
|
93
|
+
const expected = waitOpts.expectedState !== undefined
|
|
94
|
+
? waitOpts.expectedState
|
|
95
|
+
: serverLevelState;
|
|
96
|
+
const timeoutMs = waitOpts.timeoutMs ?? 5 * 60 * 1000;
|
|
97
|
+
return new Promise((resolveWait, rejectWait) => {
|
|
98
|
+
let settled = false;
|
|
99
|
+
const settle = (outcome, isReject) => {
|
|
100
|
+
if (settled)
|
|
101
|
+
return;
|
|
102
|
+
settled = true;
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
waitOpts.signal?.removeEventListener("abort", onAbort);
|
|
105
|
+
if (isReject) {
|
|
106
|
+
rejectWait(outcome);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
resolveWait(outcome);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const onAbort = () => {
|
|
113
|
+
settle(new Error("OAuth callback wait was aborted."), true);
|
|
114
|
+
};
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
settle(new Error("OAuth login timed out waiting for callback."), true);
|
|
117
|
+
}, timeoutMs);
|
|
118
|
+
if (waitOpts.signal?.aborted) {
|
|
119
|
+
settle(new Error("OAuth callback wait was aborted."), true);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
waitOpts.signal?.addEventListener("abort", onAbort);
|
|
123
|
+
const resolveWith = (callback) => {
|
|
124
|
+
if (expected !== undefined && callback.state !== expected) {
|
|
125
|
+
settle(new Error(`OAuth state mismatch: expected "${redactState(expected)}" ` +
|
|
126
|
+
`but received "${redactState(callback.state)}". ` +
|
|
127
|
+
`This may indicate a CSRF attempt or a stale login tab.`), true);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
settle(callback, false);
|
|
131
|
+
};
|
|
132
|
+
if (captured) {
|
|
133
|
+
resolveWith(captured);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
waiters.push({ resolve: resolveWith, reject: rejectWait });
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
close() {
|
|
140
|
+
return new Promise((resolveClose) => {
|
|
141
|
+
httpServer.close(() => resolveClose());
|
|
142
|
+
// close() waits for in-flight connections; closeAllConnections is
|
|
143
|
+
// available on Node 18+ and speeds shutdown without dropping the
|
|
144
|
+
// response the user's browser is mid-receiving.
|
|
145
|
+
// (Not called here to keep the success page delivery intact.)
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
resolve(handle);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// Static HTML pages (ASCII-only, no secret material)
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Styled HTML pages (dark theme, OffRouter branding)
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
const STYLED_HTML_TEMPLATE = `
|
|
160
|
+
<!doctype html>
|
|
161
|
+
<html lang="en">
|
|
162
|
+
<head>
|
|
163
|
+
<meta charset="utf-8">
|
|
164
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
165
|
+
<title>OffRouter — $$TITLE</title>
|
|
166
|
+
<style>
|
|
167
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
168
|
+
body {
|
|
169
|
+
background: #09090b;
|
|
170
|
+
color: #fafafa;
|
|
171
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
172
|
+
display: flex;
|
|
173
|
+
justify-content: center;
|
|
174
|
+
align-items: center;
|
|
175
|
+
min-height: 100vh;
|
|
176
|
+
padding: 1rem;
|
|
177
|
+
}
|
|
178
|
+
.card {
|
|
179
|
+
background: #18181b;
|
|
180
|
+
border: 1px solid #27272a;
|
|
181
|
+
border-radius: 12px;
|
|
182
|
+
padding: 2.5rem;
|
|
183
|
+
max-width: 560px;
|
|
184
|
+
width: 100%;
|
|
185
|
+
text-align: center;
|
|
186
|
+
}
|
|
187
|
+
.logo {
|
|
188
|
+
margin-bottom: 1.5rem;
|
|
189
|
+
}
|
|
190
|
+
.logo svg {
|
|
191
|
+
width: 48px;
|
|
192
|
+
height: 48px;
|
|
193
|
+
}
|
|
194
|
+
.icon {
|
|
195
|
+
margin-bottom: 1rem;
|
|
196
|
+
}
|
|
197
|
+
.icon-success {
|
|
198
|
+
color: #22c55e;
|
|
199
|
+
}
|
|
200
|
+
.icon-error {
|
|
201
|
+
color: #ef4444;
|
|
202
|
+
}
|
|
203
|
+
h1 {
|
|
204
|
+
font-size: 1.5rem;
|
|
205
|
+
font-weight: 600;
|
|
206
|
+
margin-bottom: 0.75rem;
|
|
207
|
+
}
|
|
208
|
+
p {
|
|
209
|
+
color: #a1a1aa;
|
|
210
|
+
line-height: 1.6;
|
|
211
|
+
margin-bottom: 1.5rem;
|
|
212
|
+
}
|
|
213
|
+
.details {
|
|
214
|
+
background: #27272a;
|
|
215
|
+
border-radius: 8px;
|
|
216
|
+
padding: 1rem;
|
|
217
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
218
|
+
font-size: 0.875rem;
|
|
219
|
+
color: #fafafa;
|
|
220
|
+
word-break: break-word;
|
|
221
|
+
text-align: left;
|
|
222
|
+
margin-bottom: 1.5rem;
|
|
223
|
+
}
|
|
224
|
+
.link {
|
|
225
|
+
color: #a1a1aa;
|
|
226
|
+
font-size: 0.875rem;
|
|
227
|
+
}
|
|
228
|
+
.link a {
|
|
229
|
+
color: #fafafa;
|
|
230
|
+
text-decoration: underline;
|
|
231
|
+
}
|
|
232
|
+
.link a:hover {
|
|
233
|
+
color: #ffffff;
|
|
234
|
+
}
|
|
235
|
+
</style>
|
|
236
|
+
</head>
|
|
237
|
+
<body>
|
|
238
|
+
<div class="card">
|
|
239
|
+
<div class="logo">
|
|
240
|
+
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
241
|
+
<circle cx="24" cy="24" r="20" stroke="#fafafa" stroke-width="2"/>
|
|
242
|
+
<circle cx="24" cy="24" r="9" stroke="#fafafa" stroke-width="2"/>
|
|
243
|
+
<circle cx="24" cy="24" r="3" fill="#fafafa"/>
|
|
244
|
+
<line x1="24" y1="4" x2="24" y2="14" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
245
|
+
<line x1="24" y1="34" x2="24" y2="44" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
246
|
+
<line x1="4" y1="24" x2="14" y2="24" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
247
|
+
<line x1="34" y1="24" x2="44" y2="24" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
248
|
+
<line x1="8.2" y1="8.2" x2="15.5" y2="15.5" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
249
|
+
<line x1="32.5" y1="32.5" x2="39.8" y2="39.8" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
250
|
+
<line x1="39.8" y1="8.2" x2="32.5" y2="15.5" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
251
|
+
<line x1="15.5" y1="32.5" x2="8.2" y2="39.8" stroke="#fafafa" stroke-width="2" stroke-linecap="round"/>
|
|
252
|
+
</svg>
|
|
253
|
+
</div>
|
|
254
|
+
$$CONTENT
|
|
255
|
+
<div class="link">
|
|
256
|
+
<a href="https://offrouter.com" target="_blank" rel="noopener noreferrer">Visit offrouter.com</a>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
</body>
|
|
260
|
+
</html>`;
|
|
261
|
+
function styledPage(title, icon, heading, details) {
|
|
262
|
+
const content = [
|
|
263
|
+
`<div class="icon ${icon === "✓" ? "icon-success" : "icon-error"}" style="font-size: 2.5rem;">${icon}</div>`,
|
|
264
|
+
`<h1>${heading}</h1>`,
|
|
265
|
+
details ? `<p>${details}</p>` : "",
|
|
266
|
+
].join("\n");
|
|
267
|
+
return STYLED_HTML_TEMPLATE
|
|
268
|
+
.replace("$$TITLE", title)
|
|
269
|
+
.replace("$$CONTENT", content);
|
|
270
|
+
}
|
|
271
|
+
function successPage() {
|
|
272
|
+
return styledPage("Authentication successful", "✓", "Authentication successful", "You can close this tab and return to your terminal.");
|
|
273
|
+
}
|
|
274
|
+
function authorizationDeniedPage(error) {
|
|
275
|
+
const safe = escapeHtml(error);
|
|
276
|
+
return styledPage("Authentication failed", "✗", "Authentication failed", `The provider reported: <strong>${safe}</strong>. You can close this tab and try again from your terminal.`);
|
|
277
|
+
}
|
|
278
|
+
function missingCodePage() {
|
|
279
|
+
return styledPage("Authentication incomplete", "✗", "Authentication incomplete", "The callback did not include an authorization code. Please try again from your terminal.");
|
|
280
|
+
}
|
|
281
|
+
function escapeHtml(value) {
|
|
282
|
+
return value
|
|
283
|
+
.replace(/&/g, "&")
|
|
284
|
+
.replace(/</g, "<")
|
|
285
|
+
.replace(/>/g, ">")
|
|
286
|
+
.replace(/"/g, """)
|
|
287
|
+
.replace(/'/g, "'");
|
|
288
|
+
}
|
|
289
|
+
/** Truncate a state token for error messages so it is never echoed in full. */
|
|
290
|
+
function redactState(state) {
|
|
291
|
+
if (state.length <= 8)
|
|
292
|
+
return "***";
|
|
293
|
+
return `${state.slice(0, 4)}...${state.slice(-4)}`;
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=oauth-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-server.js","sourceRoot":"","sources":["../../src/auth/oauth-server.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { PolicyConfig } from "./policy.js";
|
|
2
|
+
/** Defaults applied when user config omits policy knobs. */
|
|
3
|
+
export interface PolicyDefaults {
|
|
4
|
+
subscriptionFirst: boolean;
|
|
5
|
+
allowApiKeyFallback: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Declared provider entry from config (no secrets here). */
|
|
8
|
+
export interface ConfiguredProvider {
|
|
9
|
+
id: string;
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
accounts: ConfiguredAccount[];
|
|
12
|
+
}
|
|
13
|
+
/** Named profile overlay loaded from profiles/*.toml. */
|
|
14
|
+
export interface ConfiguredProfile {
|
|
15
|
+
id: string;
|
|
16
|
+
deniedProviders?: string[];
|
|
17
|
+
allowApiKeyFallback?: boolean;
|
|
18
|
+
subscriptionFirst?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Single configured account within a provider. */
|
|
21
|
+
export interface ConfiguredAccount {
|
|
22
|
+
id: string;
|
|
23
|
+
label?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ConfigWarning {
|
|
26
|
+
filePath: string;
|
|
27
|
+
path: string;
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
export interface OffRouterConfig {
|
|
31
|
+
homeDir: string;
|
|
32
|
+
sources: string[];
|
|
33
|
+
policy: PolicyConfig;
|
|
34
|
+
policyDefaults: PolicyDefaults;
|
|
35
|
+
providers: Record<string, ConfiguredProvider>;
|
|
36
|
+
profiles: Record<string, ConfiguredProfile>;
|
|
37
|
+
warnings: ConfigWarning[];
|
|
38
|
+
}
|
|
39
|
+
export interface LoadConfigOptions {
|
|
40
|
+
/** Override process.env (for tests). */
|
|
41
|
+
env?: NodeJS.ProcessEnv;
|
|
42
|
+
/** Override os.homedir (for tests). */
|
|
43
|
+
homedir?: () => string;
|
|
44
|
+
/** Workspace directory that may contain .offrouter/config.toml. */
|
|
45
|
+
workspaceDir?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the workspace is trusted. Project config is ignored when false
|
|
48
|
+
* or when workspaceDir is unset.
|
|
49
|
+
*/
|
|
50
|
+
workspaceTrusted?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface ResolveHomeOptions {
|
|
53
|
+
env?: NodeJS.ProcessEnv;
|
|
54
|
+
homedir?: () => string;
|
|
55
|
+
}
|
|
56
|
+
export declare class ConfigError extends Error {
|
|
57
|
+
readonly filePath: string;
|
|
58
|
+
readonly issues: string[];
|
|
59
|
+
constructor(filePath: string, issues: string[], cause?: unknown);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Safe default config: work profiles denied, nothing allowlisted, no providers.
|
|
63
|
+
*/
|
|
64
|
+
export declare function defaultConfig(homeDir?: string): OffRouterConfig;
|
|
65
|
+
export declare function resolveOffRouterHome(options?: ResolveHomeOptions): string;
|
|
66
|
+
/**
|
|
67
|
+
* Load OffRouter configuration.
|
|
68
|
+
*
|
|
69
|
+
* Resolution order:
|
|
70
|
+
* 1. defaults (deny *-work, empty allowlist, no providers)
|
|
71
|
+
* 2. `$OFFROUTER_HOME/config.toml` or `~/.offrouter/config.toml`
|
|
72
|
+
* 3. `$OFFROUTER_HOME/profiles/*.toml`
|
|
73
|
+
* 4. `<workspace>/.offrouter/config.toml` only when workspaceTrusted
|
|
74
|
+
*/
|
|
75
|
+
export declare function loadConfig(options?: LoadConfigOptions): Promise<OffRouterConfig>;
|
|
76
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,4DAA4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC5C,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IACvB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBAEd,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,OAAO;CAUhE;AA+DD;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAK,GAAG,eAAe,CAkB3D;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAQR;AAsSD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAe1B"}
|