@xopcai/xopc 0.0.272 → 0.0.273
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 +1 -5
- package/README.zh-CN.md +1 -5
- package/dist/browser-ext/dist/assets/{auth-C1QI-uMG.js → auth-DkwOUI6_.js} +101 -53
- package/dist/browser-ext/dist/background.js +1 -22
- package/dist/browser-ext/dist/sidepanel.html +1 -1
- package/dist/browser-ext/dist/sidepanel.js +24 -22
- package/dist/browser-ext/manifest.json +1 -12
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-DffqjeqQ.js → activity-store-cF7IX2RP.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Cwj4HCYY.js → agent-avatar-dicebear-BrgxX8nG.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-6CLfLxVc.js → agent-defaults-settings-panel-DvhuRCLA.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-B6mu64fY.js → agents-C0By2FIo.js} +1 -1
- package/dist/gateway/static/root/assets/{api-CGLdye4i.js → api-CYkdUpkx.js} +1 -1
- package/dist/gateway/static/root/assets/app-link-BiBXVEvp.js +1 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BLujSbaw.js → app-management-settings-panel-DfoNzWIa.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BXMcueb8.js → appearance-settings-czbLdCqj.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BEgy4hY3.js → apps-page-BSJXKWcE.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-D4bUampf.js → archive-plugin-D14P13mX.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CBGNA2Ys.js → attachment-load-Dok_B1Gv.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-dQyolNmy.js → automations-page-DM7ZEewI.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-DxRFrmrV.js → automations-workspace--1TsZf3O.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-bbvp81h2.js → binary-plugins-CxNg6InF.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C8e6Wri4.js → block-editor-D22VcYnC.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automation-inputs-oJWJtQa6.js → browser-automation-inputs-6NWTLEpd.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-CAcJQSjN.js → browser-automations-page-BrqySdbW.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-TLAlqcPo.js → browser-settings-page-DOHgQer_.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-z-K_jrZz.js → capabilities-settings-panel-Bpse_5K-.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-Dzrk33aB.js → channels-settings-yHsY174W.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-CfOPNnVr.js → channels-status-swr-BUZimNmp.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-9ZOl92kh.js → chat-terminal-dock-CZPBNpMI.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-B1dIoRNi.js → connectors-page-B_wLKGnH.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-Dj6FRLF9.js → date-picker-Da_0QyLe.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-D1q89tVc.js → dependency-picker-D_djqzy7.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DfqZBvhp.js → desktop-pet-Celmbw-T.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-HCEh2MOm.js → desktop-pet-settings-CqNNgF45.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-B5_w9qlm.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-C8cAWVoK.js → extension-debug-page-ku3kCjvH.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-5N87Vaym.js → extension-page-C7FpHwL4.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D85SAUFP.js → extension-settings-page-OMj2tU2_.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BjsDnB_n.js → gateway-config-swr-6eb1vKE1.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-Dqx8PmcT.js → gateway-settings-CH-6vkgN.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BIf0eLWX.js → gateway-startup-retry-DUFFCU8H.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BpDWGE1a.js → heartbeat-settings-CSFzOACM.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-DJaqpC8-.js → home-page-BJebAKB-.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-1m8xTVS_.js → image-generation-api-C1cHRBRp.js} +1 -1
- package/dist/gateway/static/root/assets/{index-C6PmD0cK.js → index-C6OWYFtQ.js} +9 -9
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Byy8mCSq.js → keyboard-shortcuts-settings-BuvD3iv8.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-l2AEiG2C.js → local-app-workbench-page-CaC4-THD.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-BPo0wBgM.js → local-apps-page-DdJ8zwBp.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-CRNble2Z.js → locale-store-BBSCIl4I.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-X5FdLlXK.js → logs-page-BaR2he0K.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-DT6NoIjm.js → management-settings-r-iYWZFY.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-c5vtnYe8.js +201 -0
- package/dist/gateway/static/root/assets/{media-plugins-Bzka9qXu.js → media-plugins-D_a6GDY6.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-DH_HCgmw.js → messages-DjuBdDCn.js} +2 -2
- package/dist/gateway/static/root/assets/{note-detail-panel-BUJPoaGZ.js → note-detail-panel-BV6nbgac.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-page-BwFpWRuo.js → notes-page-BmLKoWwi.js} +1 -1
- package/dist/gateway/static/root/assets/{page-tabs-Ys0p65Lt.js → page-tabs-C7Le9bSI.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-iknB5xEp.js → preview-open-alternatives-B2pOxJBK.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-card-BPZDgNNR.js → proactive-card-BlQ1vCtV.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-page-CxdZR-p2.js → proactive-page-CghKTfYa.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-W1o3f-kz.js → product-open-page-DpjiHgwu.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-BU1RKAcy.js → project-detail-page-CV8Lh296.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-z0X0tL8G.js → projects-page-COweOaJP.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-DmYFpjsH.js → registry-api-CyQ4k1Ux.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-NNTut2I8.js → remote-access-hub-ChPPGVU5.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DP1XyYO8.js → runtime-tools-settings-panel-Bl4ArLHf.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BMYKdzsH.js → schema-form-KQFmfWd4.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-B6SsHlz5.js → sessions-page-DgmHibOK.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DV7kMco2.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-2LGjz7bu.js → settings-form-section-Dbnls9ty.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-7DjpC9_C.js → settings-page-CDKirYRG.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Dj9jFWJt.js → setup-status-panel-SQmtWoOs.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BxYdSi8c.js → share-preview-page-DwgLjS1m.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-CMqE0KuK.js → shares-settings-Cs5bUrYw.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DyKrjq7F.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-DNEScMZH.js → skills-page-Bd0_ED_p.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-q88l65YU.js → skills-page.utils-rA-XT-YG.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-8NIssGKj.js → system-settings-panel-CSkMrHLz.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-L6dp9v2y.js → task-detail-page-CEQU-L_G.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-BXZG3S25.js → theme-store-DWpIEWen.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-COJcGnEi.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-BwQuoTQU.js → use-autosave-DkQAIAuB.js} +1 -1
- package/dist/gateway/static/root/assets/{user-model-page-D4BucMrZ.js → user-model-page-BQAU55lf.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-Bd03Ic0s.js → voice-api-key-field-BrqcH0P-.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-gggUp3u9.js → voice-config-api-BJ95Z3pT.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DF8PR_pK.js → work-discovery-overlay-vfTWKm13.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BiAAWlir.js → workflow-run-setup-panel-CHdr_ng9.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DryKUMfA.js → workflows-page-hwRJD7vR.js} +1 -1
- package/dist/gateway/static/root/index.html +10 -9
- package/dist/package.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.d.ts +6 -0
- package/dist/src/browser/providers/browser-ext-install.js +16 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +8 -5
- package/dist/src/cli/commands/gateway/service.js +4 -3
- package/dist/src/cli/commands/gateway/token.js +28 -1
- package/dist/src/gateway/device-routes.js +4 -3
- package/dist/src/gateway/hono/routes/browser.js +26 -0
- package/dist/src/storage/sqlite/device-pairing-approval.js +1 -3
- package/package.json +4 -4
- package/dist/browser-ext/dist/pairing-handoff.js +0 -51
- package/dist/gateway/static/root/assets/device-pairing-wizard-CPth92s6.js +0 -1
- package/dist/gateway/static/root/assets/markdown-view-AglreSOj.js +0 -201
- package/dist/gateway/static/root/assets/settings-advanced-gate-BQu8bAcN.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BXqSJymN.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-CWsRPM84.js +0 -1
package/README.md
CHANGED
|
@@ -28,14 +28,10 @@
|
|
|
28
28
|
|
|
29
29
|
<p align="center">
|
|
30
30
|
<a href="https://xopcai.github.io/xopc/xopc-desktop.mp4">
|
|
31
|
-
<img src="docs/public/xopc-desktop-preview.gif" alt="xopc desktop
|
|
31
|
+
<img src="docs/public/xopc-desktop-preview.gif" alt="xopc desktop app demo" width="960">
|
|
32
32
|
</a>
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
<p align="center">
|
|
36
|
-
<a href="https://xopcai.github.io/xopc/xopc-desktop.mp4"><strong>Watch the full onboarding video (1:02) →</strong></a>
|
|
37
|
-
</p>
|
|
38
|
-
|
|
39
35
|
> After setup, try: **“One thing I want to move forward this week is ____. Help me find the smallest credible next step.”**
|
|
40
36
|
|
|
41
37
|
<details>
|
package/README.zh-CN.md
CHANGED
|
@@ -28,14 +28,10 @@
|
|
|
28
28
|
|
|
29
29
|
<p align="center">
|
|
30
30
|
<a href="https://xopcai.github.io/xopc/xopc-desktop.mp4">
|
|
31
|
-
<img src="docs/public/xopc-desktop-preview.gif" alt="xopc
|
|
31
|
+
<img src="docs/public/xopc-desktop-preview.gif" alt="xopc 桌面应用演示" width="960">
|
|
32
32
|
</a>
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
<p align="center">
|
|
36
|
-
<a href="https://xopcai.github.io/xopc/xopc-desktop.mp4"><strong>观看完整 onboarding 视频(1:02)→</strong></a>
|
|
37
|
-
</p>
|
|
38
|
-
|
|
39
35
|
> 安装后可以直接告诉它:**“这周我最想推进的一件事是 ____。帮我找到最小但可信的下一步。”**
|
|
40
36
|
|
|
41
37
|
<details>
|
|
@@ -5977,12 +5977,12 @@ async function clearBrowserOutboxes() {
|
|
|
5977
5977
|
}
|
|
5978
5978
|
|
|
5979
5979
|
const PROFILE_KEY = "xopc.browser.profile";
|
|
5980
|
-
const PENDING_PAIRING_LINK_KEY = "xopc.browser.pending-pairing-link";
|
|
5981
5980
|
const AUTO_CONNECT_KEY = "xopc.browser.auto-connect";
|
|
5982
5981
|
const KEY_DATABASE = "xopc-browser-identity";
|
|
5983
5982
|
const KEY_STORE = "identity";
|
|
5984
5983
|
const KEY_NAME = "device-key";
|
|
5985
5984
|
const NATIVE_HOST_NAME = "ai.xopc.browser";
|
|
5985
|
+
const GATEWAY_REQUEST_TIMEOUT_MS = 8e3;
|
|
5986
5986
|
let refreshTask;
|
|
5987
5987
|
async function browserPublicKeyThumbprint(jwk) {
|
|
5988
5988
|
const canonical = JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y });
|
|
@@ -6070,13 +6070,6 @@ function parseBrowserPairingLink(value) {
|
|
|
6070
6070
|
}
|
|
6071
6071
|
return payload;
|
|
6072
6072
|
}
|
|
6073
|
-
async function takePendingPairingLink() {
|
|
6074
|
-
const stored = await chrome.storage.session.get(PENDING_PAIRING_LINK_KEY);
|
|
6075
|
-
const link = stored[PENDING_PAIRING_LINK_KEY];
|
|
6076
|
-
if (typeof link !== "string") return void 0;
|
|
6077
|
-
await chrome.storage.session.remove(PENDING_PAIRING_LINK_KEY);
|
|
6078
|
-
return link;
|
|
6079
|
-
}
|
|
6080
6073
|
function openIdentityDatabase() {
|
|
6081
6074
|
return new Promise((resolve, reject) => {
|
|
6082
6075
|
const request = indexedDB.open(KEY_DATABASE, 1);
|
|
@@ -6153,13 +6146,13 @@ async function verifyGateway(publicKey, payload, signature) {
|
|
|
6153
6146
|
return false;
|
|
6154
6147
|
}
|
|
6155
6148
|
}
|
|
6156
|
-
|
|
6157
|
-
const
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
}
|
|
6149
|
+
function requestGatewayOriginPermissions(origins) {
|
|
6150
|
+
const patterns = origins.filter((origin) => {
|
|
6151
|
+
const url = new URL(origin);
|
|
6152
|
+
return !(url.protocol === "http:" && ["127.0.0.1", "localhost"].includes(url.hostname));
|
|
6153
|
+
}).map((origin) => `${new URL(origin).origin}/*`);
|
|
6154
|
+
if (!patterns.length) return Promise.resolve(true);
|
|
6155
|
+
return chrome.permissions.request({ origins: patterns });
|
|
6163
6156
|
}
|
|
6164
6157
|
class GatewayHttpError extends Error {
|
|
6165
6158
|
constructor(message, status) {
|
|
@@ -6170,11 +6163,22 @@ class GatewayHttpError extends Error {
|
|
|
6170
6163
|
status;
|
|
6171
6164
|
}
|
|
6172
6165
|
async function post(origin, path, body) {
|
|
6173
|
-
const
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6166
|
+
const controller = new AbortController();
|
|
6167
|
+
const timeout = setTimeout(() => controller.abort(), GATEWAY_REQUEST_TIMEOUT_MS);
|
|
6168
|
+
let response;
|
|
6169
|
+
try {
|
|
6170
|
+
response = await fetch(`${origin}${path}`, {
|
|
6171
|
+
method: "POST",
|
|
6172
|
+
headers: { "Content-Type": "application/json" },
|
|
6173
|
+
body: JSON.stringify(body),
|
|
6174
|
+
signal: controller.signal
|
|
6175
|
+
});
|
|
6176
|
+
} catch (cause) {
|
|
6177
|
+
if (controller.signal.aborted) throw new Error(`Gateway did not respond within ${GATEWAY_REQUEST_TIMEOUT_MS / 1e3} seconds`);
|
|
6178
|
+
throw cause;
|
|
6179
|
+
} finally {
|
|
6180
|
+
clearTimeout(timeout);
|
|
6181
|
+
}
|
|
6178
6182
|
const json = await response.json().catch(() => ({}));
|
|
6179
6183
|
if (!response.ok) {
|
|
6180
6184
|
throw new GatewayHttpError(
|
|
@@ -6217,7 +6221,22 @@ async function signedPairingRequest(pair, payload, origin, requestId, action, co
|
|
|
6217
6221
|
}
|
|
6218
6222
|
return decoded;
|
|
6219
6223
|
}
|
|
6220
|
-
|
|
6224
|
+
function shouldTryNextRoute(cause) {
|
|
6225
|
+
return !(cause instanceof GatewayHttpError) || cause.status >= 500 || [404, 408, 425, 429].includes(cause.status);
|
|
6226
|
+
}
|
|
6227
|
+
async function signedPairingRequestAcrossRoutes(pair, payload, origins, requestId, action, completion) {
|
|
6228
|
+
let lastRouteError;
|
|
6229
|
+
for (const origin of origins) {
|
|
6230
|
+
try {
|
|
6231
|
+
return { origin, result: await signedPairingRequest(pair, payload, origin, requestId, action, completion) };
|
|
6232
|
+
} catch (cause) {
|
|
6233
|
+
if (!shouldTryNextRoute(cause)) throw cause;
|
|
6234
|
+
lastRouteError = cause;
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
throw lastRouteError instanceof Error ? lastRouteError : new Error("No Gateway route could be reached");
|
|
6238
|
+
}
|
|
6239
|
+
async function refreshAccessToken(gatewayUrls, refreshToken, pair, gateway) {
|
|
6221
6240
|
const nextRefreshToken = createRefreshToken();
|
|
6222
6241
|
const requestId = crypto.randomUUID();
|
|
6223
6242
|
const timestamp = Date.now();
|
|
@@ -6230,14 +6249,30 @@ ${nonce}
|
|
|
6230
6249
|
${requestId}
|
|
6231
6250
|
${nextRefreshToken}`;
|
|
6232
6251
|
const signature = await sign(pair, proof);
|
|
6233
|
-
const
|
|
6252
|
+
const body = {
|
|
6234
6253
|
refreshToken,
|
|
6235
6254
|
nextRefreshToken,
|
|
6236
6255
|
requestId,
|
|
6237
6256
|
timestamp,
|
|
6238
6257
|
nonce,
|
|
6239
6258
|
signature
|
|
6240
|
-
}
|
|
6259
|
+
};
|
|
6260
|
+
let gatewayUrl;
|
|
6261
|
+
let response;
|
|
6262
|
+
let lastRouteError;
|
|
6263
|
+
for (const origin of gatewayUrls) {
|
|
6264
|
+
try {
|
|
6265
|
+
response = await post(origin, "/api/device-auth/refresh", body);
|
|
6266
|
+
gatewayUrl = origin;
|
|
6267
|
+
break;
|
|
6268
|
+
} catch (cause) {
|
|
6269
|
+
if (!shouldTryNextRoute(cause)) throw cause;
|
|
6270
|
+
lastRouteError = cause;
|
|
6271
|
+
}
|
|
6272
|
+
}
|
|
6273
|
+
if (!response || !gatewayUrl) {
|
|
6274
|
+
throw lastRouteError instanceof Error ? lastRouteError : new Error("No Gateway route could be reached");
|
|
6275
|
+
}
|
|
6241
6276
|
if (typeof response.signedPayload !== "string" || typeof response.signature !== "string" || !await verifyGateway(gateway.gatewayPublicKey, response.signedPayload, response.signature)) throw new Error("Gateway identity could not be verified");
|
|
6242
6277
|
const responseProof = decodeJson(response.signedPayload);
|
|
6243
6278
|
if (responseProof.purpose !== "device-refresh-v3" || responseProof.gatewayId !== gateway.gatewayId || responseProof.requestId !== requestId || responseProof.nonce !== nonce || !(responseProof.expiresAt > Date.now()) || responseProof.expiresAt > Date.now() + 6e4) throw new Error("Gateway refresh response does not match this request");
|
|
@@ -6245,55 +6280,63 @@ ${nextRefreshToken}`;
|
|
|
6245
6280
|
if (!payload?.accessToken || !payload.accessTokenExpiresAt || payload.refreshToken !== nextRefreshToken) {
|
|
6246
6281
|
throw new Error("Gateway returned invalid browser credentials");
|
|
6247
6282
|
}
|
|
6248
|
-
return payload;
|
|
6283
|
+
return { ...payload, gatewayUrl };
|
|
6249
6284
|
}
|
|
6250
6285
|
function wait(milliseconds) {
|
|
6251
6286
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
6252
6287
|
}
|
|
6253
6288
|
async function pairGateway(link, onApproval) {
|
|
6254
6289
|
const payload = parseBrowserPairingLink(link);
|
|
6290
|
+
const origins = [...new Set(payload.routes.map((route) => new URL(route.url).origin))];
|
|
6291
|
+
const permissionTask = requestGatewayOriginPermissions(origins);
|
|
6292
|
+
if (!await permissionTask) throw new Error("Gateway site permission was not granted");
|
|
6255
6293
|
const pair = await getOrCreateKeyPair();
|
|
6256
6294
|
const requestId = crypto.randomUUID();
|
|
6257
6295
|
const initialRefreshToken = createRefreshToken();
|
|
6258
|
-
let origin
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
origin = candidate;
|
|
6266
|
-
break;
|
|
6267
|
-
} catch (cause) {
|
|
6268
|
-
if (cause instanceof GatewayHttpError && cause.status < 500 && ![404, 408, 425, 429].includes(cause.status)) {
|
|
6269
|
-
throw cause;
|
|
6270
|
-
}
|
|
6271
|
-
lastRouteError = cause;
|
|
6272
|
-
}
|
|
6273
|
-
}
|
|
6274
|
-
if (!origin || !result) {
|
|
6275
|
-
throw lastRouteError instanceof Error ? lastRouteError : new Error("No Gateway route could be reached");
|
|
6276
|
-
}
|
|
6296
|
+
let { origin, result } = await signedPairingRequestAcrossRoutes(
|
|
6297
|
+
pair,
|
|
6298
|
+
payload,
|
|
6299
|
+
origins,
|
|
6300
|
+
requestId,
|
|
6301
|
+
"request"
|
|
6302
|
+
);
|
|
6277
6303
|
if (result.request.status === "pending") onApproval(result.request.confirmationCode);
|
|
6278
6304
|
while (result.request.status === "pending") {
|
|
6279
6305
|
await wait(1500);
|
|
6280
|
-
|
|
6306
|
+
const response = await signedPairingRequestAcrossRoutes(
|
|
6307
|
+
pair,
|
|
6308
|
+
payload,
|
|
6309
|
+
[origin, ...origins.filter((candidate) => candidate !== origin)],
|
|
6310
|
+
requestId,
|
|
6311
|
+
"status"
|
|
6312
|
+
);
|
|
6313
|
+
({ origin, result } = response);
|
|
6281
6314
|
}
|
|
6282
6315
|
if (result.request.status !== "approved" && result.request.status !== "completed") {
|
|
6283
6316
|
throw new Error(`Pairing ${result.request.status}`);
|
|
6284
6317
|
}
|
|
6285
6318
|
if (result.request.status !== "completed") {
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6319
|
+
const response = await signedPairingRequestAcrossRoutes(
|
|
6320
|
+
pair,
|
|
6321
|
+
payload,
|
|
6322
|
+
[origin, ...origins.filter((candidate) => candidate !== origin)],
|
|
6323
|
+
requestId,
|
|
6324
|
+
"complete",
|
|
6325
|
+
{
|
|
6326
|
+
idempotencyKey: crypto.randomUUID(),
|
|
6327
|
+
initialRefreshToken
|
|
6328
|
+
}
|
|
6329
|
+
);
|
|
6330
|
+
({ origin, result } = response);
|
|
6290
6331
|
}
|
|
6291
6332
|
if (!result.request.deviceId) throw new Error("Gateway did not register the browser");
|
|
6292
|
-
const
|
|
6333
|
+
const orderedOrigins = [origin, ...origins.filter((candidate) => candidate !== origin)];
|
|
6334
|
+
const tokens = await refreshAccessToken(orderedOrigins, initialRefreshToken, pair, payload);
|
|
6293
6335
|
const profile = {
|
|
6294
6336
|
gatewayId: payload.gatewayId,
|
|
6295
6337
|
gatewayName: result.gateway.name,
|
|
6296
|
-
gatewayUrl:
|
|
6338
|
+
gatewayUrl: tokens.gatewayUrl,
|
|
6339
|
+
gatewayUrls: [tokens.gatewayUrl, ...orderedOrigins.filter((candidate) => candidate !== tokens.gatewayUrl)],
|
|
6297
6340
|
gatewayPublicKey: payload.gatewayPublicKey,
|
|
6298
6341
|
deviceId: result.request.deviceId,
|
|
6299
6342
|
refreshToken: tokens.refreshToken,
|
|
@@ -6314,8 +6357,13 @@ async function getAccessProfile() {
|
|
|
6314
6357
|
if (profile.accessTokenExpiresAt > Date.now() + 3e4) return profile;
|
|
6315
6358
|
if (refreshTask) return refreshTask;
|
|
6316
6359
|
refreshTask = (async () => {
|
|
6317
|
-
const
|
|
6318
|
-
const
|
|
6360
|
+
const gatewayUrls = profile.gatewayUrls?.length ? profile.gatewayUrls : [profile.gatewayUrl];
|
|
6361
|
+
const tokens = await refreshAccessToken(gatewayUrls, profile.refreshToken, await getOrCreateKeyPair(), profile);
|
|
6362
|
+
const next = {
|
|
6363
|
+
...profile,
|
|
6364
|
+
...tokens,
|
|
6365
|
+
gatewayUrls: [tokens.gatewayUrl, ...gatewayUrls.filter((candidate) => candidate !== tokens.gatewayUrl)]
|
|
6366
|
+
};
|
|
6319
6367
|
await chrome.storage.local.set({ [PROFILE_KEY]: next });
|
|
6320
6368
|
return next;
|
|
6321
6369
|
})();
|
|
@@ -6403,4 +6451,4 @@ async function revokeAndForgetProfile() {
|
|
|
6403
6451
|
}
|
|
6404
6452
|
}
|
|
6405
6453
|
|
|
6406
|
-
export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T,
|
|
6454
|
+
export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T, activeTabId as a, captureTabWithPermission as b, canonicalJson as c, createBrowserEndpointHello as d, currentTabDescriptor as e, deleteBrowserOutbox as f, discoverLocalGateway as g, endpointToolContentSchema as h, gatewayFetch as i, getAccessProfile as j, readProfile as k, registerBrowserEndpoint as l, revokeAndForgetProfile as m, runWithTabSiteAccess as n, pairGateway as p, readBrowserOutbox as r, setAutoConnectEnabled as s, writeBrowserOutbox as w };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as endpointToolContentSchema, E as ENDPOINT_PROTOCOL_VERSION, c as canonicalJson, T as TAB_BINDING_PREFIX, b as captureTabWithPermission, P as PENDING_CONTEXT_KEY, k as readProfile, l as registerBrowserEndpoint, j as getAccessProfile, R as RealtimeClient, d as createBrowserEndpointHello, i as gatewayFetch } from './assets/auth-DkwOUI6_.js';
|
|
2
2
|
|
|
3
3
|
const BROWSER_EXTENSION_PROTOCOL_VERSION = 4;
|
|
4
4
|
const BROWSER_CONTROL_ENDPOINT_TOOL_NAME = "browser.control";
|
|
@@ -1253,22 +1253,6 @@ function connectWithLogging() {
|
|
|
1253
1253
|
if (generation !== connectionGeneration && !realtime) connectWithLogging();
|
|
1254
1254
|
});
|
|
1255
1255
|
}
|
|
1256
|
-
async function stagePairingInvite(message, sender) {
|
|
1257
|
-
if (typeof message.pairingLink !== "string" || !sender.url || !sender.tab?.id) {
|
|
1258
|
-
throw new Error("Pairing handoff is missing its source tab");
|
|
1259
|
-
}
|
|
1260
|
-
const source = new URL(sender.url);
|
|
1261
|
-
const invitation = new URL(message.pairingLink);
|
|
1262
|
-
if (source.href !== invitation.href || source.protocol !== "https:" || source.hostname !== "link.xopc.ai" || source.pathname !== "/connect") {
|
|
1263
|
-
throw new Error("Pairing handoff source is not trusted");
|
|
1264
|
-
}
|
|
1265
|
-
parseBrowserPairingLink(invitation.href);
|
|
1266
|
-
const tasks = [
|
|
1267
|
-
chrome.storage.session.set({ [PENDING_PAIRING_LINK_KEY]: invitation.href })
|
|
1268
|
-
];
|
|
1269
|
-
if (message.open) tasks.push(chrome.sidePanel.open({ tabId: sender.tab.id }));
|
|
1270
|
-
await Promise.all(tasks);
|
|
1271
|
-
}
|
|
1272
1256
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
1273
1257
|
if (message.type === "browser/get-status") {
|
|
1274
1258
|
sendResponse({ connected: Boolean(endpointClaim), transport: "gateway-realtime", error: lastConnectionError });
|
|
@@ -1278,11 +1262,6 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
1278
1262
|
disconnect();
|
|
1279
1263
|
connectWithLogging();
|
|
1280
1264
|
sendResponse({ ok: true });
|
|
1281
|
-
} else if (message.type === "browser/stage-pairing-invite") {
|
|
1282
|
-
void stagePairingInvite(message, sender).then(() => sendResponse({ ok: true })).catch((cause) => sendResponse({
|
|
1283
|
-
ok: false,
|
|
1284
|
-
error: cause instanceof Error ? cause.message : String(cause)
|
|
1285
|
-
}));
|
|
1286
1265
|
} else {
|
|
1287
1266
|
sendResponse({ ok: false, error: `Unknown message: ${message.type}` });
|
|
1288
1267
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>xopc</title>
|
|
7
7
|
<script type="module" crossorigin src="./sidepanel.js"></script>
|
|
8
|
-
<link rel="modulepreload" crossorigin href="./assets/auth-
|
|
8
|
+
<link rel="modulepreload" crossorigin href="./assets/auth-DkwOUI6_.js">
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/sidepanel-C86O7q5Y.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as RealtimeClient,
|
|
1
|
+
import { R as RealtimeClient, i as gatewayFetch, a as activeTabId, r as readBrowserOutbox, w as writeBrowserOutbox, f as deleteBrowserOutbox, e as currentTabDescriptor, T as TAB_BINDING_PREFIX, j as getAccessProfile, n as runWithTabSiteAccess, P as PENDING_CONTEXT_KEY, b as captureTabWithPermission, p as pairGateway, s as setAutoConnectEnabled, k as readProfile, g as discoverLocalGateway, m as revokeAndForgetProfile } from './assets/auth-DkwOUI6_.js';
|
|
2
2
|
|
|
3
3
|
true &&(function polyfill() {
|
|
4
4
|
const relList = document.createElement("link").relList;
|
|
@@ -27544,6 +27544,22 @@ function watchSidePanelTheme(gatewayUrl) {
|
|
|
27544
27544
|
async function reconnectBrowserBridge() {
|
|
27545
27545
|
await chrome.runtime.sendMessage({ type: "browser/reconnect" }).catch(() => void 0);
|
|
27546
27546
|
}
|
|
27547
|
+
function pairingErrorMessage(cause) {
|
|
27548
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
27549
|
+
if (message === "Gateway site permission was not granted") {
|
|
27550
|
+
return "Chrome needs access to the Gateway address. Select Connect again and allow the site permission.";
|
|
27551
|
+
}
|
|
27552
|
+
if (message === "PAIRING_EXPIRED" || message === "Pairing expired" || message === "Pairing link has expired") {
|
|
27553
|
+
return "This invitation expired. Create and copy a new invitation from Device access.";
|
|
27554
|
+
}
|
|
27555
|
+
if (message === "PAIRING_DEVICE_MISMATCH") {
|
|
27556
|
+
return "This invitation was created for a phone. Create a browser invitation instead.";
|
|
27557
|
+
}
|
|
27558
|
+
if (message === "No Gateway route could be reached") {
|
|
27559
|
+
return "None of the Gateway addresses responded. Check that the Gateway is online and its secure connection is active.";
|
|
27560
|
+
}
|
|
27561
|
+
return message;
|
|
27562
|
+
}
|
|
27547
27563
|
function SidePanelApp() {
|
|
27548
27564
|
const [profile, setProfile] = reactExports.useState();
|
|
27549
27565
|
const [pairingLink, setPairingLink] = reactExports.useState("");
|
|
@@ -27558,6 +27574,7 @@ function SidePanelApp() {
|
|
|
27558
27574
|
pairingStarted.current = true;
|
|
27559
27575
|
setState("pairing");
|
|
27560
27576
|
setError("");
|
|
27577
|
+
setConfirmationCode("");
|
|
27561
27578
|
setPairingLink(link);
|
|
27562
27579
|
try {
|
|
27563
27580
|
const paired = await pairGateway(link, setConfirmationCode);
|
|
@@ -27566,7 +27583,7 @@ function SidePanelApp() {
|
|
|
27566
27583
|
setProfile(paired);
|
|
27567
27584
|
setState("online");
|
|
27568
27585
|
} catch (cause) {
|
|
27569
|
-
setError(
|
|
27586
|
+
setError(pairingErrorMessage(cause));
|
|
27570
27587
|
setState("unpaired");
|
|
27571
27588
|
} finally {
|
|
27572
27589
|
pairingStarted.current = false;
|
|
@@ -27576,11 +27593,6 @@ function SidePanelApp() {
|
|
|
27576
27593
|
if (initializationStarted.current) return;
|
|
27577
27594
|
initializationStarted.current = true;
|
|
27578
27595
|
void (async () => {
|
|
27579
|
-
const handedOff = await takePendingPairingLink();
|
|
27580
|
-
if (handedOff) {
|
|
27581
|
-
await connect(handedOff);
|
|
27582
|
-
return;
|
|
27583
|
-
}
|
|
27584
27596
|
const stored = await readProfile();
|
|
27585
27597
|
if (stored) {
|
|
27586
27598
|
await reconnectBrowserBridge();
|
|
@@ -27597,16 +27609,6 @@ function SidePanelApp() {
|
|
|
27597
27609
|
await connect(local.pairingLink);
|
|
27598
27610
|
})();
|
|
27599
27611
|
}, [connect]);
|
|
27600
|
-
reactExports.useEffect(() => {
|
|
27601
|
-
const handleStorageChange = (changes, area) => {
|
|
27602
|
-
if (area !== "session" || !changes[PENDING_PAIRING_LINK_KEY]?.newValue) return;
|
|
27603
|
-
void takePendingPairingLink().then((link) => {
|
|
27604
|
-
if (link) void connect(link);
|
|
27605
|
-
});
|
|
27606
|
-
};
|
|
27607
|
-
chrome.storage.onChanged.addListener(handleStorageChange);
|
|
27608
|
-
return () => chrome.storage.onChanged.removeListener(handleStorageChange);
|
|
27609
|
-
}, [connect]);
|
|
27610
27612
|
reactExports.useEffect(() => watchSidePanelTheme(profile?.gatewayUrl), [profile?.gatewayUrl]);
|
|
27611
27613
|
async function disconnect() {
|
|
27612
27614
|
await revokeAndForgetProfile();
|
|
@@ -27641,18 +27643,18 @@ function SidePanelApp() {
|
|
|
27641
27643
|
state !== "online" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "center", children: [
|
|
27642
27644
|
state === "loading" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "muted", children: "Loading…" }) : null,
|
|
27643
27645
|
state === "unpaired" || state === "pairing" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "card", children: [
|
|
27644
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: "Connect
|
|
27646
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: "Connect a Gateway" }),
|
|
27645
27647
|
localPairingLink ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
27646
27648
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "muted", children: "A local xopc Gateway was found. xopc connects automatically on this computer." }),
|
|
27647
27649
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "primary local-connect", onClick: () => void connect(localPairingLink), disabled: state === "pairing", children: state === "pairing" ? "Connecting…" : "Retry local connection" }),
|
|
27648
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pairing-divider", children: "or
|
|
27650
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pairing-divider", children: "or paste an invitation" })
|
|
27649
27651
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
27650
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "muted", children: "Connect
|
|
27652
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "muted", children: "Connect locally, or paste the one-time invitation copied from Device access." }),
|
|
27651
27653
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "primary local-connect", onClick: () => void connectLocalGateway(), disabled: state === "pairing", children: state === "pairing" ? "Connecting…" : "Connect local Gateway" }),
|
|
27652
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pairing-divider", children: "or
|
|
27654
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pairing-divider", children: "or paste an invitation" })
|
|
27653
27655
|
] }),
|
|
27654
27656
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "field", children: [
|
|
27655
|
-
"
|
|
27657
|
+
"One-time invitation",
|
|
27656
27658
|
/* @__PURE__ */ jsxRuntimeExports.jsx("textarea", { rows: 4, value: pairingLink, onChange: (event) => setPairingLink(event.target.value), disabled: state === "pairing" })
|
|
27657
27659
|
] }),
|
|
27658
27660
|
confirmationCode ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"minimum_chrome_version": "120",
|
|
4
4
|
"name": "xopc",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.273",
|
|
6
6
|
"description": "Chat with xopc and explicitly share or control the current page.",
|
|
7
7
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqnpr4vpLC/nmvy+wiOWk3SWlp2nEZkFijfk8ivGw7StNZgCK90nOMvwhdEtlkk3GOWDvdVnq8HxCsM3UNQ8FnGUyerpH1FJXqXuradxeHf8ZxFjiQU/mIWfnKbUuONWQORon3/pigyoXoK/VUXgg0Wbm/rbVwsS0bv+25R6m+mZgBspOLeKuoH7ivhL+48WV6POtMBsFPZweY26477EM7ukh+56Ff5ENevB8ymxBBn7qK5ZoeZd2a23U8ioX5TsHfe6fnrjitPWjIxD8G0NoKQxcaa/Mo+xs+T6UiLKxP0wjz5bm7jB5H+CXtkRJqzBWUB0h+RSLJckzZfA8BAJrRwIDAQAB",
|
|
8
8
|
"permissions": [
|
|
@@ -28,17 +28,6 @@
|
|
|
28
28
|
"service_worker": "dist/background.js",
|
|
29
29
|
"type": "module"
|
|
30
30
|
},
|
|
31
|
-
"content_scripts": [
|
|
32
|
-
{
|
|
33
|
-
"matches": [
|
|
34
|
-
"https://link.xopc.ai/connect*"
|
|
35
|
-
],
|
|
36
|
-
"js": [
|
|
37
|
-
"dist/pairing-handoff.js"
|
|
38
|
-
],
|
|
39
|
-
"run_at": "document_idle"
|
|
40
|
-
}
|
|
41
|
-
],
|
|
42
31
|
"side_panel": {
|
|
43
32
|
"default_path": "dist/sidepanel.html"
|
|
44
33
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "telegram",
|
|
3
3
|
"name": "Telegram Channel",
|
|
4
4
|
"description": "Bundled Telegram Bot channel (private workspace sources; ships inside @xopcai/xopc dist/)",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.273",
|
|
6
6
|
"kind": "channel",
|
|
7
7
|
"main": "src/index.js",
|
|
8
8
|
"channels": [
|
package/dist/gateway/static/root/assets/{activity-store-DffqjeqQ.js → activity-store-cF7IX2RP.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{p as e}from"./locale-store-
|
|
1
|
+
import{p as e}from"./locale-store-BBSCIl4I.js";var t=`xopc.activity-center.v1`,n=80,r=720*60*60*1e3;function i(e){return e===`error`?`failed`:e===`warning`?`attention`:`done`}function a(){if(!(typeof window>`u`))return window.location.hash.replace(/^#/,``)||`${window.location.pathname}${window.location.search}`||void 0}function o(){try{let e=globalThis.localStorage?.getItem(t);if(!e)return[];let i=JSON.parse(e);if(!Array.isArray(i.items))return[];let a=Date.now()-r,o=i.items.filter(e=>e&&typeof e.id==`string`&&typeof e.title==`string`).filter(e=>Number.isFinite(e.updatedAt)&&e.updatedAt>=a).slice(0,n);return o.length!==i.items.length&&s(o),o}catch{return[]}}function s(e){try{globalThis.localStorage?.setItem(t,JSON.stringify({items:e}))}catch{}}function c(e){return`${e.toString(36)}-${Math.random().toString(36).slice(2,8)}`}var l=e(e=>({items:o(),add:t=>e(e=>{let r=t.title.trim();if(!r)return e;let o=Date.now(),l=t.tone??`info`,u=t.dedupeKey?e.items.findIndex(e=>e.dedupeKey===t.dedupeKey):-1,d=[{id:u>=0?e.items[u].id:c(o),tone:l,status:t.status??i(l),title:r,message:t.message?.trim()||void 0,source:t.source?.trim()||void 0,href:t.href??a(),dedupeKey:t.dedupeKey,createdAt:u>=0?e.items[u].createdAt:o,updatedAt:o,read:t.read??!1,occurrences:u>=0?e.items[u].occurrences+1:1},...u>=0?e.items.filter((e,t)=>t!==u):e.items].slice(0,n);return s(d),{items:d}}),markAllRead:()=>e(e=>{let t=e.items.map(e=>({...e,read:!0}));return s(t),{items:t}}),remove:t=>e(e=>{let n=e.items.filter(e=>e.id!==t);return s(n),{items:n}}),clearFinished:()=>e(e=>{let t=e.items.filter(e=>e.status!==`done`);return s(t),{items:t}}),clear:()=>{s([]),e({items:[]})}}));function u(e){l.getState().add(e)}export{u as t};
|