@lanonasis/oauth-client 1.0.1 → 1.0.2

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/index.cjs CHANGED
@@ -378,7 +378,11 @@ var TokenStorage = class {
378
378
  }
379
379
  }
380
380
  async store(tokens) {
381
- const tokenString = JSON.stringify(tokens);
381
+ const tokensWithTimestamp = {
382
+ ...tokens,
383
+ issued_at: Date.now()
384
+ };
385
+ const tokenString = JSON.stringify(tokensWithTimestamp);
382
386
  if (this.isNode()) {
383
387
  if (this.keytar) {
384
388
  await this.keytar.setPassword("lanonasis-mcp", "tokens", tokenString);
@@ -386,7 +390,7 @@ var TokenStorage = class {
386
390
  await this.storeToFile(tokenString);
387
391
  }
388
392
  } else if (this.isElectron()) {
389
- await window.electronAPI.secureStore.set(this.storageKey, tokens);
393
+ await window.electronAPI.secureStore.set(this.storageKey, tokensWithTimestamp);
390
394
  } else if (this.isMobile()) {
391
395
  await window.SecureStorage.set(this.storageKey, tokenString);
392
396
  } else {
@@ -437,15 +441,14 @@ var TokenStorage = class {
437
441
  }
438
442
  isTokenExpired(tokens) {
439
443
  if (!tokens.expires_in) return false;
440
- const storedAt = this.getStoredAt(tokens);
441
- if (!storedAt) return true;
442
- const expiresAt = storedAt + tokens.expires_in * 1e3;
444
+ if (!tokens.issued_at) {
445
+ console.warn("Token missing issued_at timestamp, treating as expired");
446
+ return true;
447
+ }
448
+ const expiresAt = tokens.issued_at + tokens.expires_in * 1e3;
443
449
  const now = Date.now();
444
450
  return expiresAt - now < 3e5;
445
451
  }
446
- getStoredAt(tokens) {
447
- return Date.now() - 36e5;
448
- }
449
452
  async storeToFile(tokenString) {
450
453
  if (!this.isNode()) return;
451
454
  const fs = require("fs").promises;
@@ -1118,6 +1121,29 @@ var MCPClient = class {
1118
1121
  await this.tokenStorage.store(tokens);
1119
1122
  return tokens;
1120
1123
  }
1124
+ async ensureAccessToken() {
1125
+ if (this.accessToken) return;
1126
+ const tokens = await this.tokenStorage.retrieve();
1127
+ if (!tokens) {
1128
+ throw new Error("Not authenticated");
1129
+ }
1130
+ if (this.tokenStorage.isTokenExpired(tokens)) {
1131
+ if (tokens.refresh_token) {
1132
+ try {
1133
+ const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
1134
+ await this.tokenStorage.store(newTokens);
1135
+ this.accessToken = newTokens.access_token;
1136
+ return;
1137
+ } catch (error) {
1138
+ console.error("Token refresh failed:", error);
1139
+ throw new Error("Token expired and refresh failed");
1140
+ }
1141
+ } else {
1142
+ throw new Error("Token expired and no refresh token available");
1143
+ }
1144
+ }
1145
+ this.accessToken = tokens.access_token;
1146
+ }
1121
1147
  scheduleTokenRefresh(tokens) {
1122
1148
  if (this.refreshTimer) {
1123
1149
  clearTimeout(this.refreshTimer);
@@ -1225,6 +1251,7 @@ var MCPClient = class {
1225
1251
  await this.establishConnection();
1226
1252
  }
1227
1253
  async request(method, params) {
1254
+ await this.ensureAccessToken();
1228
1255
  if (!this.accessToken) {
1229
1256
  throw new Error("Not authenticated");
1230
1257
  }
package/dist/index.d.cts CHANGED
@@ -1,9 +1,10 @@
1
1
  interface TokenResponse {
2
2
  access_token: string;
3
- token_type: string;
4
- expires_in: number;
5
3
  refresh_token?: string;
6
- scope: string;
4
+ expires_in: number;
5
+ token_type: string;
6
+ scope?: string;
7
+ issued_at?: number;
7
8
  }
8
9
  interface DeviceCodeResponse {
9
10
  device_code: string;
@@ -77,8 +78,9 @@ declare class TokenStorage {
77
78
  store(tokens: TokenResponse): Promise<void>;
78
79
  retrieve(): Promise<TokenResponse | null>;
79
80
  clear(): Promise<void>;
80
- isTokenExpired(tokens: TokenResponse): boolean;
81
- private getStoredAt;
81
+ isTokenExpired(tokens: TokenResponse & {
82
+ issued_at?: number;
83
+ }): boolean;
82
84
  private storeToFile;
83
85
  private retrieveFromFile;
84
86
  private deleteFile;
@@ -182,6 +184,7 @@ declare class MCPClient {
182
184
  constructor(config?: MCPClientConfig);
183
185
  connect(): Promise<void>;
184
186
  private authenticate;
187
+ private ensureAccessToken;
185
188
  private scheduleTokenRefresh;
186
189
  private establishConnection;
187
190
  private connectWebSocket;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  interface TokenResponse {
2
2
  access_token: string;
3
- token_type: string;
4
- expires_in: number;
5
3
  refresh_token?: string;
6
- scope: string;
4
+ expires_in: number;
5
+ token_type: string;
6
+ scope?: string;
7
+ issued_at?: number;
7
8
  }
8
9
  interface DeviceCodeResponse {
9
10
  device_code: string;
@@ -77,8 +78,9 @@ declare class TokenStorage {
77
78
  store(tokens: TokenResponse): Promise<void>;
78
79
  retrieve(): Promise<TokenResponse | null>;
79
80
  clear(): Promise<void>;
80
- isTokenExpired(tokens: TokenResponse): boolean;
81
- private getStoredAt;
81
+ isTokenExpired(tokens: TokenResponse & {
82
+ issued_at?: number;
83
+ }): boolean;
82
84
  private storeToFile;
83
85
  private retrieveFromFile;
84
86
  private deleteFile;
@@ -182,6 +184,7 @@ declare class MCPClient {
182
184
  constructor(config?: MCPClientConfig);
183
185
  connect(): Promise<void>;
184
186
  private authenticate;
187
+ private ensureAccessToken;
185
188
  private scheduleTokenRefresh;
186
189
  private establishConnection;
187
190
  private connectWebSocket;
package/dist/index.js CHANGED
@@ -344,7 +344,11 @@ var TokenStorage = class {
344
344
  }
345
345
  }
346
346
  async store(tokens) {
347
- const tokenString = JSON.stringify(tokens);
347
+ const tokensWithTimestamp = {
348
+ ...tokens,
349
+ issued_at: Date.now()
350
+ };
351
+ const tokenString = JSON.stringify(tokensWithTimestamp);
348
352
  if (this.isNode()) {
349
353
  if (this.keytar) {
350
354
  await this.keytar.setPassword("lanonasis-mcp", "tokens", tokenString);
@@ -352,7 +356,7 @@ var TokenStorage = class {
352
356
  await this.storeToFile(tokenString);
353
357
  }
354
358
  } else if (this.isElectron()) {
355
- await window.electronAPI.secureStore.set(this.storageKey, tokens);
359
+ await window.electronAPI.secureStore.set(this.storageKey, tokensWithTimestamp);
356
360
  } else if (this.isMobile()) {
357
361
  await window.SecureStorage.set(this.storageKey, tokenString);
358
362
  } else {
@@ -403,15 +407,14 @@ var TokenStorage = class {
403
407
  }
404
408
  isTokenExpired(tokens) {
405
409
  if (!tokens.expires_in) return false;
406
- const storedAt = this.getStoredAt(tokens);
407
- if (!storedAt) return true;
408
- const expiresAt = storedAt + tokens.expires_in * 1e3;
410
+ if (!tokens.issued_at) {
411
+ console.warn("Token missing issued_at timestamp, treating as expired");
412
+ return true;
413
+ }
414
+ const expiresAt = tokens.issued_at + tokens.expires_in * 1e3;
409
415
  const now = Date.now();
410
416
  return expiresAt - now < 3e5;
411
417
  }
412
- getStoredAt(tokens) {
413
- return Date.now() - 36e5;
414
- }
415
418
  async storeToFile(tokenString) {
416
419
  if (!this.isNode()) return;
417
420
  const fs = __require("fs").promises;
@@ -1084,6 +1087,29 @@ var MCPClient = class {
1084
1087
  await this.tokenStorage.store(tokens);
1085
1088
  return tokens;
1086
1089
  }
1090
+ async ensureAccessToken() {
1091
+ if (this.accessToken) return;
1092
+ const tokens = await this.tokenStorage.retrieve();
1093
+ if (!tokens) {
1094
+ throw new Error("Not authenticated");
1095
+ }
1096
+ if (this.tokenStorage.isTokenExpired(tokens)) {
1097
+ if (tokens.refresh_token) {
1098
+ try {
1099
+ const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
1100
+ await this.tokenStorage.store(newTokens);
1101
+ this.accessToken = newTokens.access_token;
1102
+ return;
1103
+ } catch (error) {
1104
+ console.error("Token refresh failed:", error);
1105
+ throw new Error("Token expired and refresh failed");
1106
+ }
1107
+ } else {
1108
+ throw new Error("Token expired and no refresh token available");
1109
+ }
1110
+ }
1111
+ this.accessToken = tokens.access_token;
1112
+ }
1087
1113
  scheduleTokenRefresh(tokens) {
1088
1114
  if (this.refreshTimer) {
1089
1115
  clearTimeout(this.refreshTimer);
@@ -1191,6 +1217,7 @@ var MCPClient = class {
1191
1217
  await this.establishConnection();
1192
1218
  }
1193
1219
  async request(method, params) {
1220
+ await this.ensureAccessToken();
1194
1221
  if (!this.accessToken) {
1195
1222
  throw new Error("Not authenticated");
1196
1223
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lanonasis/oauth-client",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "OAuth client for Lan Onasis MCP integration",
6
6
  "license": "MIT",
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "https://github.com/lanonasis/v-secure.git",
18
+ "url": "git+https://github.com/lanonasis/v-secure.git",
19
19
  "directory": "oauth-client"
20
20
  },
21
21
  "bugs": {
@@ -62,7 +62,6 @@
62
62
  "@supabase/supabase-js": "^2.0.0"
63
63
  },
64
64
  "publishConfig": {
65
- "access": "public",
66
- "registry": "https://registry.npmjs.org/"
65
+ "access": "public"
67
66
  }
68
67
  }