mindcache 3.4.4 → 3.5.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/dist/index.d.mts CHANGED
@@ -1,8 +1,138 @@
1
- import { e as MindCacheOptions, M as MindCache } from './CloudAdapter-DOvDQswy.mjs';
2
- export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState, h as ContextRules, n as DEFAULT_KEY_ATTRIBUTES, G as GlobalListener, H as HistoryEntry, k as HistoryOptions, K as KeyAttributes, j as KeyEntry, f as KeyType, L as Listener, l as MindCacheCloudOptions, m as MindCacheIndexedDBOptions, i as STM, j as STMEntry, g as SystemTag, o as SystemTagHelpers } from './CloudAdapter-DOvDQswy.mjs';
1
+ import { e as MindCacheOptions, M as MindCache } from './CloudAdapter-CM7nyJaG.mjs';
2
+ export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState, h as ContextRules, n as DEFAULT_KEY_ATTRIBUTES, G as GlobalListener, H as HistoryEntry, k as HistoryOptions, K as KeyAttributes, j as KeyEntry, f as KeyType, L as Listener, l as MindCacheCloudOptions, m as MindCacheIndexedDBOptions, i as STM, j as STMEntry, g as SystemTag, o as SystemTagHelpers } from './CloudAdapter-CM7nyJaG.mjs';
3
3
  export { IndexedDBAdapter, IndexedDBConfig } from './server.mjs';
4
4
  import 'yjs';
5
5
 
6
+ /**
7
+ * MindCache OAuth Client
8
+ *
9
+ * Browser-compatible OAuth 2.0 client for "Sign in with MindCache"
10
+ * Supports PKCE for secure authorization
11
+ */
12
+ interface OAuthConfig {
13
+ /** Client ID from developer portal */
14
+ clientId: string;
15
+ /** Redirect URI (defaults to current URL) */
16
+ redirectUri?: string;
17
+ /** Scopes to request (default: ['read', 'write']) */
18
+ scopes?: string[];
19
+ /** MindCache authorize URL (default: production) */
20
+ authUrl?: string;
21
+ /** MindCache token URL (default: production) */
22
+ tokenUrl?: string;
23
+ /** MindCache API URL for WebSocket token exchange (default: production) */
24
+ apiUrl?: string;
25
+ /** Use PKCE for security (default: true) */
26
+ usePKCE?: boolean;
27
+ /** Storage key prefix (default: 'mindcache_oauth') */
28
+ storagePrefix?: string;
29
+ }
30
+ interface OAuthTokens {
31
+ accessToken: string;
32
+ refreshToken?: string;
33
+ expiresAt: number;
34
+ scopes: string[];
35
+ instanceId?: string;
36
+ }
37
+ interface MindCacheUser {
38
+ id: string;
39
+ email?: string;
40
+ name?: string;
41
+ instanceId?: string;
42
+ }
43
+ /**
44
+ * OAuth client for browser applications
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const oauth = new OAuthClient({ clientId: 'mc_app_abc123' });
49
+ *
50
+ * // Start OAuth flow
51
+ * await oauth.authorize();
52
+ *
53
+ * // Handle callback (on redirect page)
54
+ * const tokens = await oauth.handleCallback();
55
+ *
56
+ * // Get access token for API calls
57
+ * const token = await oauth.getAccessToken();
58
+ * ```
59
+ */
60
+ declare class OAuthClient {
61
+ private config;
62
+ private tokens;
63
+ private refreshPromise;
64
+ constructor(config: OAuthConfig);
65
+ /**
66
+ * Check if user is authenticated
67
+ */
68
+ isAuthenticated(): boolean;
69
+ /**
70
+ * Get stored tokens (if any)
71
+ */
72
+ getTokens(): OAuthTokens | null;
73
+ /**
74
+ * Get instance ID for this user+app
75
+ */
76
+ getInstanceId(): string | null;
77
+ /**
78
+ * Start OAuth authorization flow
79
+ * Redirects to MindCache authorization page
80
+ */
81
+ authorize(options?: {
82
+ popup?: boolean;
83
+ state?: string;
84
+ }): Promise<void>;
85
+ /**
86
+ * Handle OAuth callback
87
+ * Call this on your redirect URI page
88
+ *
89
+ * @returns Tokens if successful
90
+ */
91
+ handleCallback(): Promise<OAuthTokens>;
92
+ /**
93
+ * Get a valid access token
94
+ * Automatically refreshes if needed
95
+ */
96
+ getAccessToken(): Promise<string>;
97
+ /**
98
+ * Refresh access token
99
+ */
100
+ private refreshTokens;
101
+ /**
102
+ * Get user info from MindCache
103
+ */
104
+ getUserInfo(): Promise<MindCacheUser>;
105
+ /**
106
+ * Logout - revoke tokens and clear storage
107
+ */
108
+ logout(): Promise<void>;
109
+ /**
110
+ * Clear authentication state
111
+ */
112
+ private clearAuth;
113
+ /**
114
+ * Token provider for MindCache cloud config
115
+ * This fetches a WebSocket token (short-lived) using the OAuth access token
116
+ * Use this with MindCacheCloudOptions.tokenProvider
117
+ */
118
+ tokenProvider: () => Promise<string>;
119
+ /**
120
+ * Get raw OAuth access token (for API calls, not WebSocket)
121
+ * Use getAccessToken() for most cases
122
+ */
123
+ accessTokenProvider: () => Promise<string>;
124
+ private getStorage;
125
+ private setStorage;
126
+ private removeStorage;
127
+ private clearStorage;
128
+ private loadTokens;
129
+ private saveTokens;
130
+ }
131
+ /**
132
+ * Create OAuth client with environment-appropriate defaults
133
+ */
134
+ declare function createOAuthClient(config: OAuthConfig): OAuthClient;
135
+
6
136
  interface UseMindCacheResult {
7
137
  /** The MindCache instance, null until loaded */
8
138
  mindcache: MindCache | null;
@@ -34,4 +164,4 @@ declare function useMindCache(options?: MindCacheOptions): UseMindCacheResult;
34
164
 
35
165
  declare const mindcache: MindCache;
36
166
 
37
- export { MindCache, MindCacheOptions, type UseMindCacheResult, mindcache, useMindCache };
167
+ export { MindCache, MindCacheOptions, type MindCacheUser, OAuthClient, type OAuthConfig, type OAuthTokens, type UseMindCacheResult, createOAuthClient, mindcache, useMindCache };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,138 @@
1
- import { e as MindCacheOptions, M as MindCache } from './CloudAdapter-DOvDQswy.js';
2
- export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState, h as ContextRules, n as DEFAULT_KEY_ATTRIBUTES, G as GlobalListener, H as HistoryEntry, k as HistoryOptions, K as KeyAttributes, j as KeyEntry, f as KeyType, L as Listener, l as MindCacheCloudOptions, m as MindCacheIndexedDBOptions, i as STM, j as STMEntry, g as SystemTag, o as SystemTagHelpers } from './CloudAdapter-DOvDQswy.js';
1
+ import { e as MindCacheOptions, M as MindCache } from './CloudAdapter-CM7nyJaG.js';
2
+ export { A as AccessLevel, a as CloudAdapter, c as CloudAdapterEvents, C as CloudConfig, b as ConnectionState, h as ContextRules, n as DEFAULT_KEY_ATTRIBUTES, G as GlobalListener, H as HistoryEntry, k as HistoryOptions, K as KeyAttributes, j as KeyEntry, f as KeyType, L as Listener, l as MindCacheCloudOptions, m as MindCacheIndexedDBOptions, i as STM, j as STMEntry, g as SystemTag, o as SystemTagHelpers } from './CloudAdapter-CM7nyJaG.js';
3
3
  export { IndexedDBAdapter, IndexedDBConfig } from './server.js';
4
4
  import 'yjs';
5
5
 
6
+ /**
7
+ * MindCache OAuth Client
8
+ *
9
+ * Browser-compatible OAuth 2.0 client for "Sign in with MindCache"
10
+ * Supports PKCE for secure authorization
11
+ */
12
+ interface OAuthConfig {
13
+ /** Client ID from developer portal */
14
+ clientId: string;
15
+ /** Redirect URI (defaults to current URL) */
16
+ redirectUri?: string;
17
+ /** Scopes to request (default: ['read', 'write']) */
18
+ scopes?: string[];
19
+ /** MindCache authorize URL (default: production) */
20
+ authUrl?: string;
21
+ /** MindCache token URL (default: production) */
22
+ tokenUrl?: string;
23
+ /** MindCache API URL for WebSocket token exchange (default: production) */
24
+ apiUrl?: string;
25
+ /** Use PKCE for security (default: true) */
26
+ usePKCE?: boolean;
27
+ /** Storage key prefix (default: 'mindcache_oauth') */
28
+ storagePrefix?: string;
29
+ }
30
+ interface OAuthTokens {
31
+ accessToken: string;
32
+ refreshToken?: string;
33
+ expiresAt: number;
34
+ scopes: string[];
35
+ instanceId?: string;
36
+ }
37
+ interface MindCacheUser {
38
+ id: string;
39
+ email?: string;
40
+ name?: string;
41
+ instanceId?: string;
42
+ }
43
+ /**
44
+ * OAuth client for browser applications
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const oauth = new OAuthClient({ clientId: 'mc_app_abc123' });
49
+ *
50
+ * // Start OAuth flow
51
+ * await oauth.authorize();
52
+ *
53
+ * // Handle callback (on redirect page)
54
+ * const tokens = await oauth.handleCallback();
55
+ *
56
+ * // Get access token for API calls
57
+ * const token = await oauth.getAccessToken();
58
+ * ```
59
+ */
60
+ declare class OAuthClient {
61
+ private config;
62
+ private tokens;
63
+ private refreshPromise;
64
+ constructor(config: OAuthConfig);
65
+ /**
66
+ * Check if user is authenticated
67
+ */
68
+ isAuthenticated(): boolean;
69
+ /**
70
+ * Get stored tokens (if any)
71
+ */
72
+ getTokens(): OAuthTokens | null;
73
+ /**
74
+ * Get instance ID for this user+app
75
+ */
76
+ getInstanceId(): string | null;
77
+ /**
78
+ * Start OAuth authorization flow
79
+ * Redirects to MindCache authorization page
80
+ */
81
+ authorize(options?: {
82
+ popup?: boolean;
83
+ state?: string;
84
+ }): Promise<void>;
85
+ /**
86
+ * Handle OAuth callback
87
+ * Call this on your redirect URI page
88
+ *
89
+ * @returns Tokens if successful
90
+ */
91
+ handleCallback(): Promise<OAuthTokens>;
92
+ /**
93
+ * Get a valid access token
94
+ * Automatically refreshes if needed
95
+ */
96
+ getAccessToken(): Promise<string>;
97
+ /**
98
+ * Refresh access token
99
+ */
100
+ private refreshTokens;
101
+ /**
102
+ * Get user info from MindCache
103
+ */
104
+ getUserInfo(): Promise<MindCacheUser>;
105
+ /**
106
+ * Logout - revoke tokens and clear storage
107
+ */
108
+ logout(): Promise<void>;
109
+ /**
110
+ * Clear authentication state
111
+ */
112
+ private clearAuth;
113
+ /**
114
+ * Token provider for MindCache cloud config
115
+ * This fetches a WebSocket token (short-lived) using the OAuth access token
116
+ * Use this with MindCacheCloudOptions.tokenProvider
117
+ */
118
+ tokenProvider: () => Promise<string>;
119
+ /**
120
+ * Get raw OAuth access token (for API calls, not WebSocket)
121
+ * Use getAccessToken() for most cases
122
+ */
123
+ accessTokenProvider: () => Promise<string>;
124
+ private getStorage;
125
+ private setStorage;
126
+ private removeStorage;
127
+ private clearStorage;
128
+ private loadTokens;
129
+ private saveTokens;
130
+ }
131
+ /**
132
+ * Create OAuth client with environment-appropriate defaults
133
+ */
134
+ declare function createOAuthClient(config: OAuthConfig): OAuthClient;
135
+
6
136
  interface UseMindCacheResult {
7
137
  /** The MindCache instance, null until loaded */
8
138
  mindcache: MindCache | null;
@@ -34,4 +164,4 @@ declare function useMindCache(options?: MindCacheOptions): UseMindCacheResult;
34
164
 
35
165
  declare const mindcache: MindCache;
36
166
 
37
- export { MindCache, MindCacheOptions, type UseMindCacheResult, mindcache, useMindCache };
167
+ export { MindCache, MindCacheOptions, type MindCacheUser, OAuthClient, type OAuthConfig, type OAuthTokens, type UseMindCacheResult, createOAuthClient, mindcache, useMindCache };
package/dist/index.js CHANGED
@@ -395,10 +395,12 @@ var init_CloudAdapter = __esm({
395
395
  try {
396
396
  if (typeof event.data === "string") {
397
397
  const msg = JSON.parse(event.data);
398
+ console.log("\u2601\uFE0F CloudAdapter: Received JSON message:", msg.type, msg);
398
399
  if (msg.type === "auth_success") {
399
400
  this._state = "connected";
400
401
  this.reconnectAttempts = 0;
401
402
  this.emit("connected");
403
+ console.log("\u2601\uFE0F Connected to MindCache cloud");
402
404
  } else if (msg.type === "auth_error" || msg.type === "error") {
403
405
  this._state = "error";
404
406
  this.emit("error", new Error(msg.error));
@@ -406,6 +408,7 @@ var init_CloudAdapter = __esm({
406
408
  console.debug("MindCache Cloud: Received message type:", msg.type, msg);
407
409
  }
408
410
  } else {
411
+ console.log("\u2601\uFE0F CloudAdapter: Received binary message, length:", event.data.byteLength);
409
412
  const encoder = encoding__namespace.createEncoder();
410
413
  const decoder = decoding__namespace.createDecoder(new Uint8Array(event.data));
411
414
  if (this.mindcache) {
@@ -416,6 +419,7 @@ var init_CloudAdapter = __esm({
416
419
  if (!this._synced && (messageType === 1 || messageType === 2)) {
417
420
  this._synced = true;
418
421
  this.emit("synced");
422
+ console.log("\u2601\uFE0F Synced with cloud");
419
423
  }
420
424
  }
421
425
  }
@@ -2645,6 +2649,355 @@ var MindCache = class {
2645
2649
  init_CloudAdapter();
2646
2650
  init_CloudAdapter();
2647
2651
 
2652
+ // src/cloud/OAuthClient.ts
2653
+ var DEFAULT_AUTH_URL = "https://api.mindcache.dev/oauth/authorize";
2654
+ var DEFAULT_TOKEN_URL = "https://api.mindcache.dev/oauth/token";
2655
+ var DEFAULT_USERINFO_URL = "https://api.mindcache.dev/oauth/userinfo";
2656
+ var TOKEN_REFRESH_BUFFER = 5 * 60 * 1e3;
2657
+ function generateRandomString(length2) {
2658
+ const array = new Uint8Array(length2);
2659
+ crypto.getRandomValues(array);
2660
+ return Array.from(array).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, length2);
2661
+ }
2662
+ function base64UrlEncode(buffer) {
2663
+ const bytes = new Uint8Array(buffer);
2664
+ let binary = "";
2665
+ for (let i = 0; i < bytes.length; i++) {
2666
+ binary += String.fromCharCode(bytes[i]);
2667
+ }
2668
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
2669
+ }
2670
+ function generateCodeVerifier() {
2671
+ return generateRandomString(64);
2672
+ }
2673
+ async function generateCodeChallenge(verifier) {
2674
+ const encoder = new TextEncoder();
2675
+ const data = encoder.encode(verifier);
2676
+ const hash = await crypto.subtle.digest("SHA-256", data);
2677
+ return base64UrlEncode(hash);
2678
+ }
2679
+ var OAuthClient = class {
2680
+ config;
2681
+ tokens = null;
2682
+ refreshPromise = null;
2683
+ constructor(config) {
2684
+ let redirectUri = config.redirectUri;
2685
+ if (!redirectUri && typeof window !== "undefined") {
2686
+ const url = new URL(window.location.href);
2687
+ url.search = "";
2688
+ url.hash = "";
2689
+ redirectUri = url.toString();
2690
+ }
2691
+ this.config = {
2692
+ clientId: config.clientId,
2693
+ redirectUri: redirectUri || "",
2694
+ scopes: config.scopes || ["read", "write"],
2695
+ authUrl: config.authUrl || DEFAULT_AUTH_URL,
2696
+ tokenUrl: config.tokenUrl || DEFAULT_TOKEN_URL,
2697
+ apiUrl: config.apiUrl || (config.tokenUrl || DEFAULT_TOKEN_URL).replace("/oauth/token", ""),
2698
+ usePKCE: config.usePKCE !== false,
2699
+ // Default true
2700
+ storagePrefix: config.storagePrefix || "mindcache_oauth"
2701
+ };
2702
+ this.loadTokens();
2703
+ }
2704
+ /**
2705
+ * Check if user is authenticated
2706
+ */
2707
+ isAuthenticated() {
2708
+ return this.tokens !== null && this.tokens.expiresAt > Date.now();
2709
+ }
2710
+ /**
2711
+ * Get stored tokens (if any)
2712
+ */
2713
+ getTokens() {
2714
+ return this.tokens;
2715
+ }
2716
+ /**
2717
+ * Get instance ID for this user+app
2718
+ */
2719
+ getInstanceId() {
2720
+ return this.tokens?.instanceId || null;
2721
+ }
2722
+ /**
2723
+ * Start OAuth authorization flow
2724
+ * Redirects to MindCache authorization page
2725
+ */
2726
+ async authorize(options) {
2727
+ const state = options?.state || generateRandomString(32);
2728
+ this.setStorage("state", state);
2729
+ const url = new URL(this.config.authUrl);
2730
+ url.searchParams.set("response_type", "code");
2731
+ url.searchParams.set("client_id", this.config.clientId);
2732
+ url.searchParams.set("redirect_uri", this.config.redirectUri);
2733
+ url.searchParams.set("scope", this.config.scopes.join(" "));
2734
+ url.searchParams.set("state", state);
2735
+ if (this.config.usePKCE) {
2736
+ const codeVerifier = generateCodeVerifier();
2737
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
2738
+ this.setStorage("code_verifier", codeVerifier);
2739
+ url.searchParams.set("code_challenge", codeChallenge);
2740
+ url.searchParams.set("code_challenge_method", "S256");
2741
+ }
2742
+ if (options?.popup) {
2743
+ const popup = window.open(url.toString(), "mindcache_oauth", "width=500,height=600");
2744
+ if (!popup) {
2745
+ throw new Error("Popup blocked. Please allow popups for this site.");
2746
+ }
2747
+ } else {
2748
+ window.location.href = url.toString();
2749
+ }
2750
+ }
2751
+ /**
2752
+ * Handle OAuth callback
2753
+ * Call this on your redirect URI page
2754
+ *
2755
+ * @returns Tokens if successful
2756
+ */
2757
+ async handleCallback() {
2758
+ if (typeof window === "undefined") {
2759
+ throw new Error("handleCallback must be called in browser");
2760
+ }
2761
+ const url = new URL(window.location.href);
2762
+ const code = url.searchParams.get("code");
2763
+ const state = url.searchParams.get("state");
2764
+ const error = url.searchParams.get("error");
2765
+ const errorDescription = url.searchParams.get("error_description");
2766
+ if (error) {
2767
+ this.clearStorage();
2768
+ throw new Error(errorDescription || error);
2769
+ }
2770
+ const storedState = this.getStorage("state");
2771
+ if (!state || state !== storedState) {
2772
+ this.clearStorage();
2773
+ throw new Error("Invalid state parameter");
2774
+ }
2775
+ if (!code) {
2776
+ this.clearStorage();
2777
+ throw new Error("No authorization code received");
2778
+ }
2779
+ const body = {
2780
+ grant_type: "authorization_code",
2781
+ code,
2782
+ client_id: this.config.clientId,
2783
+ redirect_uri: this.config.redirectUri
2784
+ };
2785
+ if (this.config.usePKCE) {
2786
+ const codeVerifier = this.getStorage("code_verifier");
2787
+ if (!codeVerifier) {
2788
+ throw new Error("Missing code verifier");
2789
+ }
2790
+ body.code_verifier = codeVerifier;
2791
+ }
2792
+ const response = await fetch(this.config.tokenUrl, {
2793
+ method: "POST",
2794
+ headers: {
2795
+ "Content-Type": "application/json"
2796
+ },
2797
+ body: JSON.stringify(body)
2798
+ });
2799
+ if (!response.ok) {
2800
+ const data2 = await response.json().catch(() => ({}));
2801
+ throw new Error(data2.error_description || data2.error || "Token exchange failed");
2802
+ }
2803
+ const data = await response.json();
2804
+ this.tokens = {
2805
+ accessToken: data.access_token,
2806
+ refreshToken: data.refresh_token,
2807
+ expiresAt: Date.now() + data.expires_in * 1e3,
2808
+ scopes: data.scope?.split(" ") || this.config.scopes,
2809
+ instanceId: data.instance_id
2810
+ };
2811
+ this.saveTokens();
2812
+ url.searchParams.delete("code");
2813
+ url.searchParams.delete("state");
2814
+ window.history.replaceState({}, "", url.toString());
2815
+ this.removeStorage("state");
2816
+ this.removeStorage("code_verifier");
2817
+ return this.tokens;
2818
+ }
2819
+ /**
2820
+ * Get a valid access token
2821
+ * Automatically refreshes if needed
2822
+ */
2823
+ async getAccessToken() {
2824
+ if (!this.tokens) {
2825
+ throw new Error("Not authenticated. Call authorize() first.");
2826
+ }
2827
+ const needsRefresh = this.tokens.expiresAt - Date.now() < TOKEN_REFRESH_BUFFER;
2828
+ if (needsRefresh && this.tokens.refreshToken) {
2829
+ if (!this.refreshPromise) {
2830
+ this.refreshPromise = this.refreshTokens();
2831
+ }
2832
+ return this.refreshPromise;
2833
+ }
2834
+ return this.tokens.accessToken;
2835
+ }
2836
+ /**
2837
+ * Refresh access token
2838
+ */
2839
+ async refreshTokens() {
2840
+ if (!this.tokens?.refreshToken) {
2841
+ throw new Error("No refresh token available");
2842
+ }
2843
+ try {
2844
+ const response = await fetch(this.config.tokenUrl, {
2845
+ method: "POST",
2846
+ headers: {
2847
+ "Content-Type": "application/json"
2848
+ },
2849
+ body: JSON.stringify({
2850
+ grant_type: "refresh_token",
2851
+ refresh_token: this.tokens.refreshToken,
2852
+ client_id: this.config.clientId
2853
+ })
2854
+ });
2855
+ if (!response.ok) {
2856
+ this.clearAuth();
2857
+ throw new Error("Session expired. Please sign in again.");
2858
+ }
2859
+ const data = await response.json();
2860
+ this.tokens = {
2861
+ accessToken: data.access_token,
2862
+ refreshToken: data.refresh_token || this.tokens.refreshToken,
2863
+ expiresAt: Date.now() + data.expires_in * 1e3,
2864
+ scopes: data.scope?.split(" ") || this.tokens.scopes,
2865
+ instanceId: data.instance_id || this.tokens.instanceId
2866
+ };
2867
+ this.saveTokens();
2868
+ return this.tokens.accessToken;
2869
+ } finally {
2870
+ this.refreshPromise = null;
2871
+ }
2872
+ }
2873
+ /**
2874
+ * Get user info from MindCache
2875
+ */
2876
+ async getUserInfo() {
2877
+ const token = await this.getAccessToken();
2878
+ const response = await fetch(DEFAULT_USERINFO_URL, {
2879
+ headers: {
2880
+ Authorization: `Bearer ${token}`
2881
+ }
2882
+ });
2883
+ if (!response.ok) {
2884
+ throw new Error("Failed to get user info");
2885
+ }
2886
+ const data = await response.json();
2887
+ return {
2888
+ id: data.sub,
2889
+ email: data.email,
2890
+ name: data.name,
2891
+ instanceId: data.instance_id
2892
+ };
2893
+ }
2894
+ /**
2895
+ * Logout - revoke tokens and clear storage
2896
+ */
2897
+ async logout() {
2898
+ if (this.tokens?.accessToken) {
2899
+ try {
2900
+ await fetch(this.config.tokenUrl.replace("/token", "/revoke"), {
2901
+ method: "POST",
2902
+ headers: {
2903
+ "Content-Type": "application/json"
2904
+ },
2905
+ body: JSON.stringify({
2906
+ token: this.tokens.accessToken
2907
+ })
2908
+ });
2909
+ } catch {
2910
+ }
2911
+ }
2912
+ this.clearAuth();
2913
+ }
2914
+ /**
2915
+ * Clear authentication state
2916
+ */
2917
+ clearAuth() {
2918
+ this.tokens = null;
2919
+ this.removeStorage("tokens");
2920
+ }
2921
+ /**
2922
+ * Token provider for MindCache cloud config
2923
+ * This fetches a WebSocket token (short-lived) using the OAuth access token
2924
+ * Use this with MindCacheCloudOptions.tokenProvider
2925
+ */
2926
+ tokenProvider = async () => {
2927
+ const accessToken = await this.getAccessToken();
2928
+ const instanceId = this.getInstanceId();
2929
+ if (!instanceId) {
2930
+ throw new Error("No instance ID available. Complete OAuth flow first.");
2931
+ }
2932
+ const response = await fetch(`${this.config.apiUrl}/api/ws-token`, {
2933
+ method: "POST",
2934
+ headers: {
2935
+ "Content-Type": "application/json",
2936
+ "Authorization": `Bearer ${accessToken}`
2937
+ },
2938
+ body: JSON.stringify({
2939
+ instanceId,
2940
+ permission: "write"
2941
+ })
2942
+ });
2943
+ if (!response.ok) {
2944
+ const data2 = await response.json().catch(() => ({}));
2945
+ throw new Error(data2.error || "Failed to get WebSocket token");
2946
+ }
2947
+ const data = await response.json();
2948
+ return data.token;
2949
+ };
2950
+ /**
2951
+ * Get raw OAuth access token (for API calls, not WebSocket)
2952
+ * Use getAccessToken() for most cases
2953
+ */
2954
+ accessTokenProvider = async () => {
2955
+ return this.getAccessToken();
2956
+ };
2957
+ // Storage helpers
2958
+ getStorage(key) {
2959
+ if (typeof localStorage === "undefined") {
2960
+ return null;
2961
+ }
2962
+ return localStorage.getItem(`${this.config.storagePrefix}_${key}`);
2963
+ }
2964
+ setStorage(key, value) {
2965
+ if (typeof localStorage === "undefined") {
2966
+ return;
2967
+ }
2968
+ localStorage.setItem(`${this.config.storagePrefix}_${key}`, value);
2969
+ }
2970
+ removeStorage(key) {
2971
+ if (typeof localStorage === "undefined") {
2972
+ return;
2973
+ }
2974
+ localStorage.removeItem(`${this.config.storagePrefix}_${key}`);
2975
+ }
2976
+ clearStorage() {
2977
+ this.removeStorage("state");
2978
+ this.removeStorage("code_verifier");
2979
+ this.removeStorage("tokens");
2980
+ }
2981
+ loadTokens() {
2982
+ const stored = this.getStorage("tokens");
2983
+ if (stored) {
2984
+ try {
2985
+ this.tokens = JSON.parse(stored);
2986
+ } catch {
2987
+ this.tokens = null;
2988
+ }
2989
+ }
2990
+ }
2991
+ saveTokens() {
2992
+ if (this.tokens) {
2993
+ this.setStorage("tokens", JSON.stringify(this.tokens));
2994
+ }
2995
+ }
2996
+ };
2997
+ function createOAuthClient(config) {
2998
+ return new OAuthClient(config);
2999
+ }
3000
+
2648
3001
  // src/local/index.ts
2649
3002
  init_IndexedDBAdapter();
2650
3003
  function useMindCache(options) {
@@ -2687,7 +3040,9 @@ var mindcache = new MindCache();
2687
3040
 
2688
3041
  exports.DEFAULT_KEY_ATTRIBUTES = DEFAULT_KEY_ATTRIBUTES;
2689
3042
  exports.MindCache = MindCache;
3043
+ exports.OAuthClient = OAuthClient;
2690
3044
  exports.SystemTagHelpers = SystemTagHelpers;
3045
+ exports.createOAuthClient = createOAuthClient;
2691
3046
  exports.mindcache = mindcache;
2692
3047
  exports.useMindCache = useMindCache;
2693
3048
  //# sourceMappingURL=index.js.map