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.
@@ -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 (!response.headersSent) response.writeHead(502, noStoreHeaders("text/plain; charset=utf-8"));
112
- response.end("ChatGPT development egress failed\n");
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.1",
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.1",
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.1",
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"],