@vacbo/opencode-anthropic-fix 0.1.6 → 0.1.8

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.
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vacbo/opencode-anthropic-fix",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "main": "dist/opencode-anthropic-auth-plugin.js",
5
5
  "bin": {
6
6
  "opencode-anthropic-auth": "dist/opencode-anthropic-auth-cli.mjs",
@@ -16,6 +16,14 @@
16
16
  "access": "public",
17
17
  "registry": "https://registry.npmjs.org/"
18
18
  },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/Vacbo/opencode-anthropic-fix"
22
+ },
23
+ "homepage": "https://github.com/Vacbo/opencode-anthropic-fix#readme",
24
+ "bugs": {
25
+ "url": "https://github.com/Vacbo/opencode-anthropic-fix/issues"
26
+ },
19
27
  "scripts": {
20
28
  "build": "bun scripts/build.ts",
21
29
  "prepublishOnly": "npm run build && npm test",
@@ -1,291 +0,0 @@
1
- // src/bun-proxy.ts
2
- import { resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- // src/parent-pid-watcher.ts
6
- var DEFAULT_POLL_INTERVAL_MS = 5e3;
7
- function assertValidParentPid(parentPid) {
8
- if (!Number.isInteger(parentPid) || parentPid <= 0) {
9
- throw new Error("Parent PID must be a positive integer.");
10
- }
11
- }
12
- function assertValidPollInterval(pollIntervalMs) {
13
- if (!Number.isFinite(pollIntervalMs) || pollIntervalMs <= 0) {
14
- throw new Error("Poll interval must be a positive number.");
15
- }
16
- }
17
- function isParentAlive(parentPid) {
18
- try {
19
- process.kill(parentPid, 0);
20
- return true;
21
- } catch (error) {
22
- const code = error.code;
23
- if (code === "ESRCH") {
24
- return false;
25
- }
26
- if (code === "EPERM") {
27
- return true;
28
- }
29
- return true;
30
- }
31
- }
32
- var ParentPidWatcher = class {
33
- parentPid;
34
- pollIntervalMs;
35
- onParentGone;
36
- interval = null;
37
- shouldMonitorPpidDrift = false;
38
- constructor(options) {
39
- this.parentPid = options.parentPid;
40
- this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
41
- this.onParentGone = options.onParentGone;
42
- }
43
- start() {
44
- if (this.interval) {
45
- return;
46
- }
47
- assertValidParentPid(this.parentPid);
48
- assertValidPollInterval(this.pollIntervalMs);
49
- this.shouldMonitorPpidDrift = process.ppid === this.parentPid;
50
- this.interval = setInterval(() => {
51
- if (this.shouldMonitorPpidDrift && process.ppid !== this.parentPid) {
52
- this.handleParentGone();
53
- return;
54
- }
55
- if (!isParentAlive(this.parentPid)) {
56
- this.handleParentGone();
57
- }
58
- }, this.pollIntervalMs);
59
- }
60
- stop() {
61
- if (!this.interval) {
62
- return;
63
- }
64
- clearInterval(this.interval);
65
- this.interval = null;
66
- this.shouldMonitorPpidDrift = false;
67
- }
68
- handleParentGone() {
69
- this.stop();
70
- this.onParentGone();
71
- }
72
- };
73
-
74
- // src/bun-proxy.ts
75
- var DEFAULT_ALLOWED_HOSTS = ["api.anthropic.com", "platform.claude.com"];
76
- var DEFAULT_REQUEST_TIMEOUT_MS = 6e5;
77
- var DEFAULT_PARENT_EXIT_CODE = 1;
78
- var DEFAULT_PARENT_POLL_INTERVAL_MS = 5e3;
79
- var HEALTH_PATH = "/__health";
80
- var DEBUG_ENABLED = process.env.OPENCODE_ANTHROPIC_DEBUG === "1";
81
- function isMainModule(argv = process.argv) {
82
- return Boolean(argv[1]) && resolve(argv[1]) === fileURLToPath(import.meta.url);
83
- }
84
- function parseInteger(value) {
85
- const parsed = Number.parseInt(value ?? "", 10);
86
- return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
87
- }
88
- function parseParentPid(argv) {
89
- const inlineValue = argv.map((argument) => argument.match(/^--parent-pid=(\d+)$/)?.[1] ?? null).find((value) => value !== null);
90
- if (inlineValue) {
91
- return parseInteger(inlineValue);
92
- }
93
- const flagIndex = argv.indexOf("--parent-pid");
94
- return flagIndex >= 0 ? parseInteger(argv[flagIndex + 1]) : null;
95
- }
96
- function createNoopWatcher() {
97
- return {
98
- start() {
99
- },
100
- stop() {
101
- }
102
- };
103
- }
104
- function createDefaultParentWatcherFactory() {
105
- return ({ parentPid, onParentExit, pollIntervalMs, exitCode }) => new ParentPidWatcher({
106
- parentPid,
107
- pollIntervalMs,
108
- onParentGone: () => {
109
- onParentExit(exitCode);
110
- }
111
- });
112
- }
113
- function sanitizeForwardHeaders(source) {
114
- const headers = new Headers(source);
115
- ["x-proxy-url", "host", "connection", "content-length"].forEach((headerName) => {
116
- headers.delete(headerName);
117
- });
118
- return headers;
119
- }
120
- function copyResponseHeaders(source) {
121
- const headers = new Headers(source);
122
- ["transfer-encoding", "content-encoding"].forEach((headerName) => {
123
- headers.delete(headerName);
124
- });
125
- return headers;
126
- }
127
- function resolveTargetUrl(req, allowedHosts) {
128
- const targetUrl = req.headers.get("x-proxy-url");
129
- if (!targetUrl) {
130
- return new Response("Missing x-proxy-url", { status: 400 });
131
- }
132
- try {
133
- const parsedUrl = new URL(targetUrl);
134
- if (allowedHosts.size > 0 && !allowedHosts.has(parsedUrl.hostname)) {
135
- return new Response(`Host not allowed: ${parsedUrl.hostname}`, { status: 403 });
136
- }
137
- return parsedUrl;
138
- } catch {
139
- return new Response("Invalid x-proxy-url", { status: 400 });
140
- }
141
- }
142
- function createAbortContext(requestTimeoutMs) {
143
- const timeoutController = new AbortController();
144
- const timer = setTimeout(() => {
145
- timeoutController.abort(new DOMException("Upstream request timed out", "TimeoutError"));
146
- }, requestTimeoutMs);
147
- timer.unref?.();
148
- return {
149
- timeoutSignal: timeoutController.signal,
150
- cancelTimeout() {
151
- clearTimeout(timer);
152
- }
153
- };
154
- }
155
- function isAbortError(error) {
156
- return error instanceof DOMException ? error.name === "AbortError" || error.name === "TimeoutError" : error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
157
- }
158
- function isTimeoutAbort(signal) {
159
- const reason = signal.reason;
160
- return reason instanceof DOMException ? reason.name === "TimeoutError" : reason instanceof Error && reason.name === "TimeoutError";
161
- }
162
- function createAbortResponse(req, timeoutSignal) {
163
- return req.signal.aborted ? new Response("Client disconnected", { status: 499 }) : isTimeoutAbort(timeoutSignal) ? new Response("Upstream request timed out", { status: 504 }) : new Response("Upstream request aborted", { status: 499 });
164
- }
165
- async function createUpstreamInit(req, signal) {
166
- const method = req.method || "GET";
167
- const hasBody = method !== "GET" && method !== "HEAD";
168
- const bodyText = hasBody ? await req.text() : "";
169
- return {
170
- method,
171
- headers: sanitizeForwardHeaders(req.headers),
172
- signal,
173
- ...hasBody && bodyText.length > 0 ? { body: bodyText } : {}
174
- };
175
- }
176
- function logRequest(targetUrl, req) {
177
- if (!DEBUG_ENABLED) {
178
- return;
179
- }
180
- const logHeaders = Object.fromEntries(
181
- [...sanitizeForwardHeaders(req.headers).entries()].map(([key, value]) => [
182
- key,
183
- key === "authorization" ? "Bearer ***" : value
184
- ])
185
- );
186
- console.error("\n[bun-proxy] === FORWARDED REQUEST ===");
187
- console.error(`[bun-proxy] ${req.method} ${targetUrl.toString()}`);
188
- console.error(`[bun-proxy] Headers: ${JSON.stringify(logHeaders, null, 2)}`);
189
- console.error("[bun-proxy] =========================\n");
190
- }
191
- function createProxyRequestHandler(options) {
192
- const allowedHosts = new Set(options.allowHosts ?? DEFAULT_ALLOWED_HOSTS);
193
- const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
194
- return async function handleProxyRequest(req) {
195
- if (new URL(req.url).pathname === HEALTH_PATH) {
196
- return new Response("ok");
197
- }
198
- const targetUrl = resolveTargetUrl(req, allowedHosts);
199
- if (targetUrl instanceof Response) {
200
- return targetUrl;
201
- }
202
- const abortContext = createAbortContext(requestTimeoutMs);
203
- const upstreamSignal = AbortSignal.any([req.signal, abortContext.timeoutSignal]);
204
- const upstreamInit = await createUpstreamInit(req, upstreamSignal);
205
- logRequest(targetUrl, req);
206
- try {
207
- const upstreamResponse = await options.fetchImpl(targetUrl.toString(), upstreamInit);
208
- return new Response(upstreamResponse.body, {
209
- status: upstreamResponse.status,
210
- statusText: upstreamResponse.statusText,
211
- headers: copyResponseHeaders(upstreamResponse.headers)
212
- });
213
- } catch (error) {
214
- if (upstreamSignal.aborted && isAbortError(error)) {
215
- return createAbortResponse(req, abortContext.timeoutSignal);
216
- }
217
- const message = error instanceof Error ? error.message : String(error);
218
- return new Response(message, { status: 502 });
219
- } finally {
220
- abortContext.cancelTimeout();
221
- }
222
- };
223
- }
224
- function createProxyProcessRuntime(options = {}) {
225
- const argv = options.argv ?? process.argv;
226
- const parentPid = parseParentPid(argv);
227
- if (!parentPid) {
228
- return createNoopWatcher();
229
- }
230
- const exit = options.exit ?? process.exit;
231
- const parentWatcherFactory = options.parentWatcherFactory ?? createDefaultParentWatcherFactory();
232
- return parentWatcherFactory({
233
- parentPid,
234
- pollIntervalMs: DEFAULT_PARENT_POLL_INTERVAL_MS,
235
- exitCode: DEFAULT_PARENT_EXIT_CODE,
236
- onParentExit: (exitCode) => {
237
- exit(exitCode ?? DEFAULT_PARENT_EXIT_CODE);
238
- }
239
- });
240
- }
241
- function assertBunRuntime() {
242
- if (typeof Bun === "undefined") {
243
- throw new Error("bun-proxy.ts must be executed with Bun.");
244
- }
245
- return Bun;
246
- }
247
- async function runProxyProcess() {
248
- const bun = assertBunRuntime();
249
- const watcher = createProxyProcessRuntime();
250
- const server = bun.serve({
251
- port: 0,
252
- fetch: createProxyRequestHandler({
253
- fetchImpl: fetch,
254
- allowHosts: DEFAULT_ALLOWED_HOSTS,
255
- requestTimeoutMs: DEFAULT_REQUEST_TIMEOUT_MS
256
- })
257
- });
258
- const lifecycle = {
259
- closed: false
260
- };
261
- const shutdown = (exitCode = 0) => {
262
- if (lifecycle.closed) {
263
- return;
264
- }
265
- lifecycle.closed = true;
266
- watcher.stop();
267
- server.stop(true);
268
- process.exit(exitCode);
269
- };
270
- process.on("SIGTERM", () => {
271
- shutdown(0);
272
- });
273
- process.on("SIGINT", () => {
274
- shutdown(0);
275
- });
276
- watcher.start();
277
- process.stdout.write(`BUN_PROXY_PORT=${server.port}
278
- `);
279
- }
280
- if (isMainModule()) {
281
- void runProxyProcess().catch((error) => {
282
- const message = error instanceof Error ? error.stack ?? error.message : String(error);
283
- process.stderr.write(`${message}
284
- `);
285
- process.exit(1);
286
- });
287
- }
288
- export {
289
- createProxyProcessRuntime,
290
- createProxyRequestHandler
291
- };