shadok-ai 0.13.15 → 0.14.1
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/README.md +9 -0
- package/package.json +1 -1
- package/public/index.html +10 -0
- package/public/upload.js +24 -0
package/README.md
CHANGED
|
@@ -345,12 +345,21 @@ location / {
|
|
|
345
345
|
proxy_set_header Upgrade $http_upgrade;
|
|
346
346
|
proxy_set_header Connection "upgrade";
|
|
347
347
|
proxy_set_header Host $host;
|
|
348
|
+
client_max_body_size 50m; # match the server's paste limit
|
|
348
349
|
}
|
|
349
350
|
```
|
|
350
351
|
|
|
351
352
|
The client picks `wss://` on its own when the page is HTTPS, so there is nothing
|
|
352
353
|
to configure on that side.
|
|
353
354
|
|
|
355
|
+
**Upload size.** The server accepts a pasted/dropped file up to 50 MB, but
|
|
356
|
+
nginx's default `client_max_body_size` is **1 MB** — a full-page screenshot
|
|
357
|
+
sails past that, and nginx answers its OWN `413` HTML page **before** the request
|
|
358
|
+
reaches the cockpit. Raise the limit to match (`client_max_body_size 50m;`),
|
|
359
|
+
or a paste larger than 1 MB fails at the proxy. The cockpit now shows a plain
|
|
360
|
+
"too large" instead of a JSON parser error, but the file still won't go through
|
|
361
|
+
until the proxy allows it.
|
|
362
|
+
|
|
354
363
|
**Idle timeout.** A resting agent's `/ws` carries no traffic, and proxies
|
|
355
364
|
idle-close a quiet socket (nginx `proxy_read_timeout`, 60s by default;
|
|
356
365
|
Cloudflare ~100s) — the symptom is a cockpit that keeps flashing
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -2351,6 +2351,8 @@
|
|
|
2351
2351
|
window.bangCommands = bangCommands;
|
|
2352
2352
|
import { claudeUpdateState } from "/update-ready.js?v=__ASSET_V__";
|
|
2353
2353
|
window.claudeUpdateState = claudeUpdateState;
|
|
2354
|
+
import { uploadFailure } from "/upload.js?v=__ASSET_V__";
|
|
2355
|
+
window.uploadFailure = uploadFailure;
|
|
2354
2356
|
window.MODEL_CHOICES = MODEL_CHOICES;
|
|
2355
2357
|
window.composeModel = composeModel;
|
|
2356
2358
|
window.pickChannelSource = pickChannelSource;
|
|
@@ -2446,6 +2448,8 @@
|
|
|
2446
2448
|
// cache. instanceKey is stamped synchronously, so the stub can namespace.
|
|
2447
2449
|
dirKey: (base) => (instanceKey ? base + ":" + instanceKey : base),
|
|
2448
2450
|
serverSwapped: (pageKey, serverKey) => !!pageKey && !!serverKey && pageKey !== serverKey,
|
|
2451
|
+
uploadFailure: (status, contentType) =>
|
|
2452
|
+
/json/i.test(contentType || "") ? null : status === 413 ? "too large (over the server's upload limit)" : `upload failed (HTTP ${status || "?"})`,
|
|
2449
2453
|
};
|
|
2450
2454
|
for (const [name, stub] of Object.entries(BRIDGE_STUBS)) {
|
|
2451
2455
|
if (typeof window[name] !== "function") { stub.__stub = true; window[name] = stub; }
|
|
@@ -6455,6 +6459,12 @@
|
|
|
6455
6459
|
},
|
|
6456
6460
|
body: file,
|
|
6457
6461
|
});
|
|
6462
|
+
// A proxy rejects an oversized body with a 413 text/html page that never
|
|
6463
|
+
// reaches /paste — parsing THAT as JSON is what showed the user
|
|
6464
|
+
// "Unexpected token '<'" instead of "too large". Decide from the status
|
|
6465
|
+
// first; only parse when the response is actually ours (JSON).
|
|
6466
|
+
const fail = window.uploadFailure(r.status, r.headers.get("content-type"));
|
|
6467
|
+
if (fail) throw new Error(fail);
|
|
6458
6468
|
const j = await r.json();
|
|
6459
6469
|
if (!r.ok || !j.line) throw new Error(j.error || `HTTP ${r.status}`);
|
|
6460
6470
|
promptInput.value = promptInput.value.replace(mark, j.line);
|
package/public/upload.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Pure helper for the composer's file upload (paste / drag-and-drop). ESM:
|
|
2
|
+
// loaded by the browser (bridged to window) AND imported by test/upload.test.ts.
|
|
3
|
+
//
|
|
4
|
+
// Why it exists: `attachFile` POSTs to /paste and calls `r.json()`. A reverse
|
|
5
|
+
// proxy (nginx, default `client_max_body_size` 1 MB) rejects an oversized body
|
|
6
|
+
// with its OWN error page — `413 text/html` — which never reaches our JSON
|
|
7
|
+
// route. `r.json()` on that HTML threw `Unexpected token '<', "<html>…"`, and
|
|
8
|
+
// the composer surfaced the raw parser error instead of a plain "too large".
|
|
9
|
+
// The server itself accepts up to PASTE_LIMIT (50 MB), so this is always the
|
|
10
|
+
// proxy, and the fix is to read the STATUS, not the body.
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Should the caller refuse to parse this /paste response, and with what message?
|
|
14
|
+
* Returns null for a JSON response (success OR our `{error}` body — the caller's
|
|
15
|
+
* existing `r.json()` path handles both); otherwise a human string, because a
|
|
16
|
+
* non-JSON response is a proxy/gateway page, never something to `JSON.parse`.
|
|
17
|
+
* @param {number} status - the HTTP status
|
|
18
|
+
* @param {string|null|undefined} contentType - the response Content-Type header
|
|
19
|
+
*/
|
|
20
|
+
export function uploadFailure(status, contentType) {
|
|
21
|
+
if (/json/i.test(contentType || "")) return null; // ours — let the caller read it
|
|
22
|
+
if (status === 413) return "too large (over the server's upload limit)";
|
|
23
|
+
return `upload failed (HTTP ${status || "?"})`;
|
|
24
|
+
}
|