orbit-codex-bridge 0.1.2 → 0.1.6
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 +11 -2
- package/lib/desktop.mjs +55 -8
- package/lib/resume-manager.mjs +177 -0
- package/lib/rpc.mjs +28 -2
- package/package.json +2 -2
- package/public/app.js +304 -28
- package/public/goal.css +7 -0
- package/public/index.html +4 -1
- package/public/style.css +30 -0
- package/relay-agent.mjs +4 -2
- package/relay-server.mjs +15 -4
- package/server.mjs +380 -25
package/relay-agent.mjs
CHANGED
|
@@ -69,7 +69,9 @@ export function createRelayAgent(options = {}) {
|
|
|
69
69
|
requests.delete(request);
|
|
70
70
|
resolve({statusCode:response.statusCode || 502,headers:{
|
|
71
71
|
'content-type':response.headers['content-type'] || 'application/json',
|
|
72
|
-
...(response.headers['set-cookie'] ? {'set-cookie':response.headers['set-cookie']} : {})
|
|
72
|
+
...(response.headers['set-cookie'] ? {'set-cookie':response.headers['set-cookie']} : {}),
|
|
73
|
+
...Object.fromEntries(['content-disposition','content-length','accept-ranges','content-range','etag']
|
|
74
|
+
.filter(name=>typeof response.headers[name]==='string').map(name=>[name,response.headers[name]]))
|
|
73
75
|
},body:Buffer.concat(chunks)});
|
|
74
76
|
});
|
|
75
77
|
});
|
|
@@ -97,7 +99,7 @@ export function createRelayAgent(options = {}) {
|
|
|
97
99
|
const body = Buffer.from(message.body || '', 'base64');
|
|
98
100
|
if (body.length > maxBody) return;
|
|
99
101
|
const headers = {};
|
|
100
|
-
for (const name of ['accept','content-type','cookie','user-agent']) {
|
|
102
|
+
for (const name of ['accept','content-type','cookie','user-agent','range','if-range','if-none-match']) {
|
|
101
103
|
const value = message.headers?.[name];
|
|
102
104
|
if (typeof value === 'string') headers[name] = value;
|
|
103
105
|
}
|
package/relay-server.mjs
CHANGED
|
@@ -71,13 +71,24 @@ function responseHeaders(headers, deviceId, secureCookie) {
|
|
|
71
71
|
const token = paired.split(';')[0].slice('orbit_session='.length);
|
|
72
72
|
safe['Set-Cookie'] = `${deviceCookieName(deviceId)}=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=${token ? 43200 : 0}${secureCookie ? '; Secure' : ''}`;
|
|
73
73
|
}
|
|
74
|
+
const contentType=headers?.['content-type'];
|
|
75
|
+
if(typeof contentType==='string'&&/^(?:application\/(?:json|pdf|zip|octet-stream)|text\/[a-z0-9.+-]+(?:;\s*charset=utf-8)?|image\/(?:png|jpeg|gif|webp|svg\+xml))$/i.test(contentType))safe['Content-Type']=contentType;
|
|
76
|
+
const disposition=headers?.['content-disposition'];
|
|
77
|
+
if(typeof disposition==='string'&&disposition.length<=1000
|
|
78
|
+
&&/^attachment;\s*filename="[^"\r\n]{1,180}";\s*filename\*=UTF-8''[a-zA-Z0-9%._~-]{1,600}$/.test(disposition))safe['Content-Disposition']=disposition;
|
|
79
|
+
const length=headers?.['content-length'];
|
|
80
|
+
if(/^\d{1,8}$/.test(String(length||'')))safe['Content-Length']=length;
|
|
81
|
+
if(/^(?:bytes \d+-\d+\/\d+|bytes \*\/\d+)$/.test(headers?.['content-range']||''))safe['Content-Range']=headers['content-range'];
|
|
82
|
+
if(headers?.['accept-ranges']==='bytes')safe['Accept-Ranges']='bytes';
|
|
83
|
+
if(typeof headers?.etag==='string'&&/^"orbit-\d+-\d+"$/.test(headers.etag))safe.ETag=headers.etag;
|
|
74
84
|
return safe;
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
function isLocalApi(pathname, method) {
|
|
78
88
|
if (method === 'GET') return ['/api/status','/api/threads','/api/models'].includes(pathname)
|
|
79
|
-
|| /^\/api\/threads\/[a-zA-Z0-9_-]{8,120}\/messages$/.test(pathname);
|
|
80
|
-
return method === 'POST' && ['/api/pair','/api/logout','/api/pair/qr'].includes(pathname)
|
|
89
|
+
|| /^\/api\/threads\/[a-zA-Z0-9_-]{8,120}\/(?:messages|files|file)$/.test(pathname);
|
|
90
|
+
return method === 'POST' && (['/api/pair','/api/logout','/api/pair/qr'].includes(pathname)
|
|
91
|
+
|| /^\/api\/threads\/[a-zA-Z0-9_-]{8,120}\/attachments(?:\/remove)?$/.test(pathname));
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
function json(response, status, body, headers = {}) {
|
|
@@ -261,14 +272,14 @@ export function createRelayServer(options = {}) {
|
|
|
261
272
|
const agent=agents.get(device.id);
|
|
262
273
|
if(!agent||agent.socket.readyState!==WebSocket.OPEN)return json(response,503,{error:`电脑“${device.name}”当前不在线。`});
|
|
263
274
|
if(accountConnect&&!agent.accountConnect)return json(response,409,{
|
|
264
|
-
error:'请在电脑上更新 Orbit 连接器到 0.1.
|
|
275
|
+
error:'请在电脑上更新 Orbit 连接器到 0.1.3 或更高版本后重试。',code:'connector_upgrade_required'
|
|
265
276
|
});
|
|
266
277
|
const body=await readBody(request);
|
|
267
278
|
if (!store.hasSession(authenticated.tokenHash,authenticated.user.id)) return json(response,401,{error:'请先登录云端工作台。',code:'cloud_login_required'});
|
|
268
279
|
chooseDevice(request, store.getUser(authenticated.user.id));
|
|
269
280
|
const requestId=crypto.randomUUID();
|
|
270
281
|
const headers={};
|
|
271
|
-
for(const name of ['accept','content-type','host','origin','user-agent'])if(request.headers[name])headers[name]=request.headers[name];
|
|
282
|
+
for(const name of ['accept','content-type','host','origin','user-agent','range','if-range','if-none-match'])if(request.headers[name])headers[name]=request.headers[name];
|
|
272
283
|
headers.cookie = localCookie(request,device.id);
|
|
273
284
|
if(pendingHttp.size>=500)return json(response,429,{error:'请求过多,请稍后重试。'});
|
|
274
285
|
const promise=new Promise((resolve,reject)=>{
|