nanocodex-vite 0.6.1 → 0.6.4
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/chatgpt-egress.mjs +20 -5
- package/oauth-relay.d.mts +1 -1
- package/oauth-relay.mjs +2 -2
- package/package.json +3 -3
- package/plugin.mjs +11 -0
package/chatgpt-egress.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import WebSocket, { WebSocketServer } from "ws";
|
|
|
7
7
|
const CHATGPT_HOST = "chatgpt.com";
|
|
8
8
|
const CHATGPT_PATH_PREFIX = "/backend-api/codex/";
|
|
9
9
|
const RELAY_HTTP_PATHS = new Map([
|
|
10
|
+
["codex-responses", "/backend-api/codex/responses"],
|
|
10
11
|
["codex-web-search", "/backend-api/codex/alpha/search"],
|
|
11
12
|
["codex-image-generation", "/backend-api/codex/images/generations"],
|
|
12
13
|
["codex-image-edit", "/backend-api/codex/images/edits"],
|
|
@@ -84,13 +85,18 @@ export async function startChatGptWorkerEgress(options = {}) {
|
|
|
84
85
|
|
|
85
86
|
async function proxyHttpRequest(request, response, fetchImpl, localPrefix, relayPrefix) {
|
|
86
87
|
const upstreamPath = allowedUpstreamPath(request.url, localPrefix, relayPrefix, false);
|
|
87
|
-
if (!safeLoopbackRequest(request) || upstreamPath === undefined
|
|
88
|
+
if (!safeLoopbackRequest(request) || upstreamPath === undefined
|
|
89
|
+
|| (request.url?.startsWith(`${relayPrefix}/http/codex-responses`)
|
|
90
|
+
&& (request.method !== "POST" || request.url !== `${relayPrefix}/http/codex-responses`))) {
|
|
88
91
|
response.writeHead(404, noStoreHeaders("text/plain; charset=utf-8"));
|
|
89
92
|
response.end("Not found\n");
|
|
90
93
|
return;
|
|
91
94
|
}
|
|
92
95
|
try {
|
|
93
96
|
const method = request.method ?? "GET";
|
|
97
|
+
const controller = new AbortController();
|
|
98
|
+
request.once("aborted", () => controller.abort());
|
|
99
|
+
response.once("close", () => { if (!response.writableFinished) controller.abort(); });
|
|
94
100
|
const upstream = await fetchImpl(`https://${CHATGPT_HOST}${upstreamPath}`, {
|
|
95
101
|
method,
|
|
96
102
|
headers: upstreamHttpHeaders(request),
|
|
@@ -99,17 +105,22 @@ async function proxyHttpRequest(request, response, fetchImpl, localPrefix, relay
|
|
|
99
105
|
: Readable.toWeb(request),
|
|
100
106
|
duplex: "half",
|
|
101
107
|
redirect: "manual",
|
|
108
|
+
signal: controller.signal,
|
|
102
109
|
});
|
|
103
110
|
const headers = new Headers(upstream.headers);
|
|
104
111
|
headers.delete("content-encoding");
|
|
105
112
|
headers.delete("content-length");
|
|
106
113
|
headers.set("cache-control", "no-store");
|
|
107
114
|
response.writeHead(upstream.status, upstream.statusText, Object.fromEntries(headers));
|
|
108
|
-
if (upstream.body) Readable.fromWeb(upstream.body).pipe(response);
|
|
115
|
+
if (upstream.body) Readable.fromWeb(upstream.body).once("error", (error) => response.destroy(error)).pipe(response);
|
|
109
116
|
else response.end();
|
|
110
|
-
} catch {
|
|
111
|
-
if (
|
|
112
|
-
response.
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if (response.destroyed) return;
|
|
119
|
+
if (response.headersSent) response.destroy(error);
|
|
120
|
+
else {
|
|
121
|
+
response.writeHead(502, noStoreHeaders("text/plain; charset=utf-8"));
|
|
122
|
+
response.end("ChatGPT development egress failed\n");
|
|
123
|
+
}
|
|
113
124
|
}
|
|
114
125
|
}
|
|
115
126
|
|
|
@@ -214,6 +225,10 @@ function upstreamHttpHeaders(request) {
|
|
|
214
225
|
"x-oai-attestation",
|
|
215
226
|
"x-openai-fedramp",
|
|
216
227
|
"x-session-id",
|
|
228
|
+
"x-client-request-id",
|
|
229
|
+
"x-codex-turn-state",
|
|
230
|
+
"x-openai-internal-codex-responses-lite",
|
|
231
|
+
"x-responsesapi-include-timing-metrics",
|
|
217
232
|
]) {
|
|
218
233
|
const value = request.headers[name];
|
|
219
234
|
if (typeof value === "string") headers.set(name, value);
|
package/oauth-relay.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type LocalOAuthProvider = "github" | "google" | "gmail" | "gdrive" | "slack" | "x";
|
|
1
|
+
export type LocalOAuthProvider = "github" | "google" | "gmail" | "gdrive" | "slack" | "x" | "spotify" | "soundcloud";
|
|
2
2
|
export type LocalOAuthFlow = "connect" | "managed";
|
|
3
3
|
export type LocalConnectorFlow = LocalOAuthFlow;
|
|
4
4
|
export type LocalConnectorAuthorization = Readonly<{
|
package/oauth-relay.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const PROVIDERS = new Set(["github", "google", "gmail", "gdrive", "slack", "x"]);
|
|
1
|
+
const PROVIDERS = new Set(["github", "google", "gmail", "gdrive", "slack", "x", "spotify", "soundcloud"]);
|
|
2
2
|
const FLOWS = new Set(["connect", "managed"]);
|
|
3
3
|
const BASE64_URL = /^[A-Za-z0-9_-]+$/;
|
|
4
4
|
const INSTANCE_HOST = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.nanocodex\.localhost$/;
|
|
@@ -9,7 +9,7 @@ const MAX_CLOCK_SKEW_SECONDS = 30;
|
|
|
9
9
|
const MAX_INNER_STATE_LENGTH = 512;
|
|
10
10
|
const MAX_ENVELOPE_LENGTH = 2_048;
|
|
11
11
|
const CONNECTION_ID = /^[A-Za-z0-9_-]{43}$/;
|
|
12
|
-
const CONNECTOR_CALLBACK = /^\/v1\/connectors\/(github|google|gmail|gdrive|slack|x)\/callback$/;
|
|
12
|
+
const CONNECTOR_CALLBACK = /^\/v1\/connectors\/(github|google|gmail|gdrive|slack|x|spotify|soundcloud)\/callback$/;
|
|
13
13
|
const MCP_CALLBACK = /^\/v1\/mcp-connections\/([A-Za-z0-9_-]{43})\/callback$/;
|
|
14
14
|
const SAFE_QUERY = ["code", "error", "error_description"];
|
|
15
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nanocodex-vite",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Vite, Cloudflare, WASM, ChatGPT development, and OAuth relay integration for Nanocodex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@cloudflare/vite-plugin": "1.54.2",
|
|
34
34
|
"@types/node": "^22.20.1",
|
|
35
|
-
"nanocodex": "0.6.
|
|
35
|
+
"nanocodex": "0.6.4",
|
|
36
36
|
"typescript": "5.9.3",
|
|
37
37
|
"vite": "8.2.1",
|
|
38
38
|
"wrangler": "4.127.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@cloudflare/vite-plugin": ">=1.54.2",
|
|
42
|
-
"nanocodex": "^0.6.
|
|
42
|
+
"nanocodex": "^0.6.4",
|
|
43
43
|
"vite": ">=6.1.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
package/plugin.mjs
CHANGED
|
@@ -339,6 +339,9 @@ async function localOAuthBindings() {
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
export function oauthBindingsFromEnvironment(environment) {
|
|
342
|
+
const spotifyClientId = firstEnvironmentValue(environment, [
|
|
343
|
+
"NANOCODEX_SPOTIFY_OAUTH_CLIENT_ID", "SPOTIFY_OAUTH_CLIENT_ID", "SPOTIFY_CLIENT_ID",
|
|
344
|
+
]);
|
|
342
345
|
return {
|
|
343
346
|
...oauthCredentialPair(environment, {
|
|
344
347
|
label: "GitHub",
|
|
@@ -361,6 +364,14 @@ export function oauthBindingsFromEnvironment(environment) {
|
|
|
361
364
|
targetId: "SLACK_OAUTH_CLIENT_ID",
|
|
362
365
|
targetSecret: "SLACK_OAUTH_CLIENT_SECRET",
|
|
363
366
|
}),
|
|
367
|
+
...(spotifyClientId ? { SPOTIFY_OAUTH_CLIENT_ID: spotifyClientId } : {}),
|
|
368
|
+
...oauthCredentialPair(environment, {
|
|
369
|
+
label: "SoundCloud",
|
|
370
|
+
ids: ["NANOCODEX_SOUNDCLOUD_OAUTH_CLIENT_ID", "SOUNDCLOUD_OAUTH_CLIENT_ID", "SOUNDCLOUD_CLIENT_ID"],
|
|
371
|
+
secrets: ["NANOCODEX_SOUNDCLOUD_OAUTH_CLIENT_SECRET", "SOUNDCLOUD_OAUTH_CLIENT_SECRET", "SOUNDCLOUD_CLIENT_SECRET"],
|
|
372
|
+
targetId: "SOUNDCLOUD_OAUTH_CLIENT_ID",
|
|
373
|
+
targetSecret: "SOUNDCLOUD_OAUTH_CLIENT_SECRET",
|
|
374
|
+
}),
|
|
364
375
|
...oauthCredentialPair(environment, {
|
|
365
376
|
label: "X",
|
|
366
377
|
ids: ["NANOCODEX_X_OAUTH_CLIENT_ID", "X_OAUTH_CLIENT_ID", "X_CLIENT_ID"],
|