@1presence/bridge 0.10.0 → 0.13.0
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/dist/auth.js +11 -52
- package/dist/index.js +15 -2
- package/package.json +2 -1
package/dist/auth.js
CHANGED
|
@@ -4,27 +4,17 @@ exports.AuthCancelledError = void 0;
|
|
|
4
4
|
exports.isTokenValid = isTokenValid;
|
|
5
5
|
exports.ensureFreshToken = ensureFreshToken;
|
|
6
6
|
exports.getValidAuth = getValidAuth;
|
|
7
|
-
exports.refreshAuth = refreshAuth;
|
|
8
|
-
exports.clearAuth = clearAuth;
|
|
9
7
|
const http_1 = require("http");
|
|
10
8
|
const fs_1 = require("fs");
|
|
11
9
|
const os_1 = require("os");
|
|
12
10
|
const path_1 = require("path");
|
|
13
11
|
const child_process_1 = require("child_process");
|
|
14
12
|
const crypto_1 = require("crypto");
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
21
|
-
}
|
|
22
|
-
// writeFileSync's `mode` only applies when the file is newly created. chmodSync
|
|
23
|
-
// covers the overwrite case so a legacy 0644 auth.json gets tightened on next save.
|
|
24
|
-
function writeRestricted(path, data) {
|
|
25
|
-
(0, fs_1.writeFileSync)(path, data, { mode: 0o600 });
|
|
26
|
-
(0, fs_1.chmodSync)(path, 0o600);
|
|
27
|
-
}
|
|
13
|
+
// Auth lives only in process memory. Earlier versions persisted tokens to
|
|
14
|
+
// ~/.1presence/auth.json; remove any leftover file on startup so a stale,
|
|
15
|
+
// permission-bearing token can't survive a bridge restart.
|
|
16
|
+
const LEGACY_AUTH_FILE = (0, path_1.join)((0, os_1.homedir)(), '.1presence', 'auth.json');
|
|
17
|
+
(0, fs_1.rmSync)(LEGACY_AUTH_FILE, { force: true });
|
|
28
18
|
// ─── JWT helpers ──────────────────────────────────────────────────────────────
|
|
29
19
|
function parseJwt(token) {
|
|
30
20
|
try {
|
|
@@ -49,24 +39,6 @@ function uidFromToken(token) {
|
|
|
49
39
|
function emailFromToken(token) {
|
|
50
40
|
return parseJwt(token).email;
|
|
51
41
|
}
|
|
52
|
-
// ─── Cache read/write ─────────────────────────────────────────────────────────
|
|
53
|
-
function loadCachedAuth() {
|
|
54
|
-
try {
|
|
55
|
-
const raw = (0, fs_1.readFileSync)(AUTH_FILE, 'utf-8');
|
|
56
|
-
const data = JSON.parse(raw);
|
|
57
|
-
if (!data.token || !isTokenValid(data.token))
|
|
58
|
-
return null;
|
|
59
|
-
return { token: data.token, uid: data.uid, email: data.email, refreshToken: data.refreshToken };
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function saveCachedAuth(auth) {
|
|
66
|
-
ensureConfigDir();
|
|
67
|
-
const data = { ...auth, savedAt: Date.now() };
|
|
68
|
-
writeRestricted(AUTH_FILE, JSON.stringify(data, null, 2));
|
|
69
|
-
}
|
|
70
42
|
// ─── Browser auth flow ────────────────────────────────────────────────────────
|
|
71
43
|
function openBrowser(url) {
|
|
72
44
|
const platform = process.platform;
|
|
@@ -208,7 +180,7 @@ async function refreshIdToken(refreshToken) {
|
|
|
208
180
|
throw new Error('Token refresh returned no id_token');
|
|
209
181
|
return data.id_token;
|
|
210
182
|
}
|
|
211
|
-
/** Returns auth with a fresh ID token. Refreshes if <10 minutes remain. */
|
|
183
|
+
/** Returns auth with a fresh ID token. Refreshes in-memory if <10 minutes remain. */
|
|
212
184
|
async function ensureFreshToken(auth) {
|
|
213
185
|
const { exp } = parseJwt(auth.token);
|
|
214
186
|
const tenMinutes = 10 * 60;
|
|
@@ -217,26 +189,13 @@ async function ensureFreshToken(auth) {
|
|
|
217
189
|
if (!auth.refreshToken)
|
|
218
190
|
return auth; // no refresh token, use as-is
|
|
219
191
|
const newToken = await refreshIdToken(auth.refreshToken);
|
|
220
|
-
|
|
221
|
-
saveCachedAuth(updated);
|
|
222
|
-
return updated;
|
|
192
|
+
return { ...auth, token: newToken };
|
|
223
193
|
}
|
|
224
194
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
195
|
+
// No cache — every bridge launch goes through the browser flow. This means
|
|
196
|
+
// permission revocations take effect on the next restart, and the PWA's
|
|
197
|
+
// CliAuthPage no-permission screen is what users see if access is denied.
|
|
225
198
|
async function getValidAuth(gatewayUrl, pwaUrl) {
|
|
226
|
-
const cached = loadCachedAuth();
|
|
227
|
-
if (cached)
|
|
228
|
-
return cached;
|
|
229
199
|
console.log('Sign-in required.');
|
|
230
|
-
|
|
231
|
-
saveCachedAuth(auth);
|
|
232
|
-
return auth;
|
|
233
|
-
}
|
|
234
|
-
function refreshAuth(auth) {
|
|
235
|
-
saveCachedAuth(auth);
|
|
236
|
-
}
|
|
237
|
-
function clearAuth() {
|
|
238
|
-
try {
|
|
239
|
-
writeRestricted(AUTH_FILE, '{}');
|
|
240
|
-
}
|
|
241
|
-
catch { /* ignore */ }
|
|
200
|
+
return runBrowserAuthFlow(gatewayUrl, pwaUrl);
|
|
242
201
|
}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,20 @@ const claude_1 = require("./claude");
|
|
|
13
13
|
const config_1 = require("./config");
|
|
14
14
|
const update_1 = require("./update");
|
|
15
15
|
const package_json_1 = require("../package.json");
|
|
16
|
+
// Published tarballs don't ship src/, so this fires only when running the
|
|
17
|
+
// dist build from a live workspace checkout. Catches the trap where editing
|
|
18
|
+
// src/ without re-running tsc leaves you executing stale dist code — banner
|
|
19
|
+
// version matches package.json but behavior doesn't match the source.
|
|
20
|
+
if (__dirname.endsWith('dist')) {
|
|
21
|
+
const srcDir = (0, path_1.join)(__dirname, '..', 'src');
|
|
22
|
+
if ((0, fs_1.existsSync)(srcDir)) {
|
|
23
|
+
const newest = (dir) => Math.max(...(0, fs_1.readdirSync)(dir).map(f => (0, fs_1.statSync)((0, path_1.join)(dir, f)).mtimeMs));
|
|
24
|
+
if (newest(srcDir) > newest(__dirname)) {
|
|
25
|
+
console.error('Bridge dist is stale (src/ has been edited since last build). Run: npm run build');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
16
30
|
// ─── CLI args ─────────────────────────────────────────────────────────────────
|
|
17
31
|
const VERBOSE = process.argv.includes('--verbose') || process.argv.includes('-v');
|
|
18
32
|
// ─── Config ───────────────────────────────────────────────────────────────────
|
|
@@ -252,8 +266,7 @@ function connect(auth, retryDelay = 1000) {
|
|
|
252
266
|
ws.on('close', (code) => {
|
|
253
267
|
stopPing();
|
|
254
268
|
if (code === 4001) {
|
|
255
|
-
console.error('Authentication failed
|
|
256
|
-
(0, auth_1.clearAuth)();
|
|
269
|
+
console.error('Authentication failed. Please restart the bridge to sign in again.');
|
|
257
270
|
process.exit(1);
|
|
258
271
|
}
|
|
259
272
|
if (code === 4003) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1presence/bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
|
|
5
5
|
"bin": {
|
|
6
6
|
"1presence-bridge": "dist/index.js"
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"README.md"
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
|
+
"prepare": "tsc",
|
|
14
15
|
"prepack": "tsc",
|
|
15
16
|
"build": "tsc",
|
|
16
17
|
"dev": "tsx src/index.ts",
|