@firela/billclaw-openclaw 0.1.5 → 0.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 fire-la
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,31 +1,32 @@
1
1
  /**
2
- * Gmail OAuth handler - implements Gmail OAuth 2.0 flow
2
+ * Gmail OAuth handler - OpenClaw adapter
3
3
  *
4
- * This module handles Gmail OAuth 2.0 authorization using PKCE (Proof Key for Code Exchange).
4
+ * This is an adapter layer that calls the framework-agnostic OAuth implementation
5
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality (config management).
5
6
  *
6
- * Flow:
7
- * 1. Generate authorization URL (with PKCE) - Returns { url, state }
8
- * 2. Handle callback - Receives authorization code
9
- * 3. Exchange code for access token - Returns { accessToken, refreshToken }
7
+ * @packageDocumentation
10
8
  */
11
9
  import type { OpenClawPluginApi } from "../types/openclaw-plugin.js";
12
10
  /**
13
11
  * Handle Gmail OAuth flow
14
12
  *
15
- * This integrates Gmail OAuth 2.0 with PKCE for secure authorization.
13
+ * This is an OpenClaw adapter that calls the framework-agnostic OAuth handler
14
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality.
16
15
  *
17
16
  * Flow:
18
17
  * 1. Initialize OAuth (no params) - Returns { url, state }
19
- * 2. Handle callback (code + state) - Returns { accessToken, refreshToken }
18
+ * 2. Handle callback (code + state + accountId) - Returns { accessToken, refreshToken }
19
+ * - Tokens are automatically saved to account config if accountId is provided
20
20
  *
21
21
  * @param api - OpenClaw plugin API
22
- * @param context - OAuth context with optional code and state from callback
22
+ * @param context - OAuth context with optional code, state, redirectUri, and accountId
23
23
  * @returns OAuthResult with URL and/or token
24
24
  */
25
25
  export declare function gmailOAuthHandler(api: OpenClawPluginApi, context?: {
26
26
  code?: string;
27
27
  state?: string;
28
28
  redirectUri?: string;
29
+ accountId?: string;
29
30
  }): Promise<{
30
31
  url: string;
31
32
  state?: string;
@@ -33,4 +34,15 @@ export declare function gmailOAuthHandler(api: OpenClawPluginApi, context?: {
33
34
  refreshToken?: string;
34
35
  expiresIn?: number;
35
36
  }>;
37
+ /**
38
+ * Refresh Gmail access token using refresh token
39
+ *
40
+ * @param api - OpenClaw plugin API
41
+ * @param accountId - Account ID to refresh token for
42
+ * @returns New access token and expiry info, or null if refresh failed
43
+ */
44
+ export declare function refreshGmailToken(api: OpenClawPluginApi, accountId: string): Promise<{
45
+ accessToken: string;
46
+ expiresIn: number;
47
+ } | null>;
36
48
  //# sourceMappingURL=gmail.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../src/oauth/gmail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAiMpE;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,iBAAiB,EACtB,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,OAAO,CAAC;IACT,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAsCD"}
1
+ {"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../src/oauth/gmail.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AA8FpE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,iBAAiB,EACtB,OAAO,CAAC,EAAE;IACR,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GACA,OAAO,CAAC;IACT,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CA4BD;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,iBAAiB,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4C5D"}
@@ -1,13 +1,23 @@
1
1
  /**
2
- * Gmail OAuth handler - implements Gmail OAuth 2.0 flow
2
+ * Gmail OAuth handler - OpenClaw adapter
3
3
  *
4
- * This module handles Gmail OAuth 2.0 authorization using PKCE (Proof Key for Code Exchange).
4
+ * This is an adapter layer that calls the framework-agnostic OAuth implementation
5
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality (config management).
5
6
  *
6
- * Flow:
7
- * 1. Generate authorization URL (with PKCE) - Returns { url, state }
8
- * 2. Handle callback - Receives authorization code
9
- * 3. Exchange code for access token - Returns { accessToken, refreshToken }
7
+ * @packageDocumentation
8
+ */
9
+ import { gmailOAuthHandler as coreGmailOAuthHandler, refreshGmailToken as coreRefreshGmailToken, } from "@firela/billclaw-core";
10
+ /**
11
+ * Get a logger from OpenClaw API, or provide a no-op logger
10
12
  */
13
+ function getLogger(api) {
14
+ return {
15
+ info: api.logger?.info || (() => { }),
16
+ error: api.logger?.error || (() => { }),
17
+ warn: api.logger?.warn || (() => { }),
18
+ debug: api.logger?.debug || (() => { }),
19
+ };
20
+ }
11
21
  /**
12
22
  * Get Gmail configuration from OpenClaw config
13
23
  */
@@ -25,166 +35,99 @@ function getGmailConfig(api) {
25
35
  };
26
36
  }
27
37
  /**
28
- * Generate random code verifier for PKCE
29
- */
30
- function generateCodeVerifier() {
31
- const array = new Uint8Array(32);
32
- crypto.getRandomValues(array);
33
- return base64UrlEncode(array);
34
- }
35
- /**
36
- * Generate code challenge from verifier for PKCE
37
- */
38
- async function generateCodeChallenge(verifier) {
39
- const encoder = new TextEncoder();
40
- const data = encoder.encode(verifier);
41
- const hash = await crypto.subtle.digest("SHA-256", data);
42
- return base64UrlEncode(new Uint8Array(hash));
43
- }
44
- /**
45
- * Base64URL encode a byte array
46
- */
47
- function base64UrlEncode(bytes) {
48
- const binString = Array.from(bytes, (byte) => String.fromCharCode(byte));
49
- const base64 = btoa(binString.join(""));
50
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
51
- }
52
- /**
53
- * State parameter storage (in-memory for security)
54
- * In production, this should be stored in a secure session
55
- */
56
- const oauthStateStore = new Map();
57
- /**
58
- * Clean up expired states (older than 10 minutes)
59
- */
60
- function cleanupExpiredStates() {
61
- const now = Date.now();
62
- const maxAge = 10 * 60 * 1000; // 10 minutes
63
- for (const [key, value] of oauthStateStore.entries()) {
64
- if (now - value.timestamp > maxAge) {
65
- oauthStateStore.delete(key);
66
- }
67
- }
68
- }
69
- /**
70
- * Generate Gmail OAuth authorization URL
71
- *
72
- * Uses PKCE for security without requiring client secret.
73
- */
74
- async function generateAuthorizationUrl(api, redirectUri = "http://localhost:3000/callback") {
75
- cleanupExpiredStates();
76
- const gmailConfig = getGmailConfig(api);
77
- // Generate PKCE verifier and challenge
78
- const codeVerifier = generateCodeVerifier();
79
- const codeChallenge = await generateCodeChallenge(codeVerifier);
80
- // Generate state parameter for CSRF protection
81
- const state = Array.from(crypto.getRandomValues(new Uint8Array(16)))
82
- .map((b) => b.toString(16).padStart(2, "0"))
83
- .join("");
84
- // Store state and verifier
85
- oauthStateStore.set(state, {
86
- codeVerifier,
87
- timestamp: Date.now(),
88
- });
89
- // Build authorization URL
90
- const params = new URLSearchParams();
91
- params.set("client_id", gmailConfig.clientId);
92
- params.set("redirect_uri", redirectUri);
93
- params.set("response_type", "code");
94
- params.set("scope", "https://www.googleapis.com/auth/gmail.readonly");
95
- params.set("state", state);
96
- params.set("code_challenge", codeChallenge);
97
- params.set("code_challenge_method", "S256");
98
- params.set("access_type", "offline"); // Allow refresh token
99
- params.set("prompt", "consent"); // Force consent to get refresh token
100
- const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
101
- api.logger.info?.("Gmail authorization URL generated");
102
- return { url, state };
103
- }
104
- /**
105
- * Exchange authorization code for access token
38
+ * Save Gmail OAuth tokens to account configuration
106
39
  *
107
- * Completes the OAuth flow by exchanging the authorization code
108
- * for an access token (and optionally refresh token).
40
+ * NOTE: This requires the OpenClaw runtime to support config updates.
41
+ * The actual persistence depends on the OpenClawConfigProvider implementation.
109
42
  */
110
- async function exchangeCodeForToken(api, code, state, redirectUri = "http://localhost:3000/callback") {
111
- // Retrieve stored state
112
- const storedState = oauthStateStore.get(state);
113
- if (!storedState) {
114
- throw new Error("Invalid or expired OAuth state. Please try again.");
115
- }
116
- // Clean up state
117
- oauthStateStore.delete(state);
118
- const gmailConfig = getGmailConfig(api);
119
- // Exchange code for token
120
- const tokenUrl = "https://oauth2.googleapis.com/token";
121
- const params = new URLSearchParams();
122
- params.set("code", code);
123
- params.set("client_id", gmailConfig.clientId);
124
- if (gmailConfig.clientSecret) {
125
- params.set("client_secret", gmailConfig.clientSecret);
43
+ async function saveGmailTokensToAccount(api, accountId, accessToken, refreshToken, expiresIn) {
44
+ const logger = getLogger(api);
45
+ // Calculate token expiry timestamp
46
+ const expiresAt = expiresIn
47
+ ? new Date(Date.now() + expiresIn * 1000).toISOString()
48
+ : undefined;
49
+ // Get config from OpenClaw
50
+ const config = api.pluginConfig;
51
+ // Find and update the account
52
+ const accountIndex = config.accounts?.findIndex((a) => a.id === accountId && a.type === "gmail");
53
+ if (accountIndex === -1 || accountIndex === undefined) {
54
+ logger.warn(`Gmail account ${accountId} not found in config. Tokens not saved.`);
55
+ return;
126
56
  }
127
- params.set("redirect_uri", redirectUri);
128
- params.set("grant_type", "authorization_code");
129
- params.set("code_verifier", storedState.codeVerifier);
130
- const response = await fetch(tokenUrl, {
131
- method: "POST",
132
- headers: {
133
- "Content-Type": "application/x-www-form-urlencoded",
134
- },
135
- body: params.toString(),
136
- });
137
- if (!response.ok) {
138
- const errorText = await response.text();
139
- throw new Error(`Failed to exchange token: ${response.status} ${errorText}`);
140
- }
141
- const data = (await response.json());
142
- api.logger.info?.("Gmail access token obtained successfully");
143
- return {
144
- accessToken: data.access_token,
145
- refreshToken: data.refresh_token,
146
- expiresIn: data.expires_in,
57
+ // Update account with tokens
58
+ config.accounts[accountIndex] = {
59
+ ...config.accounts[accountIndex],
60
+ gmailAccessToken: accessToken,
61
+ gmailRefreshToken: refreshToken,
62
+ gmailTokenExpiry: expiresAt,
63
+ enabled: true, // Auto-enable account after successful OAuth
147
64
  };
65
+ // Note: The actual persistence to disk depends on OpenClaw's config management
66
+ // The updated config is in memory but OpenClaw needs to handle persistence
67
+ logger.info(`Gmail tokens updated in memory for account ${accountId}. Persistence depends on OpenClaw config management.`);
148
68
  }
149
69
  /**
150
70
  * Handle Gmail OAuth flow
151
71
  *
152
- * This integrates Gmail OAuth 2.0 with PKCE for secure authorization.
72
+ * This is an OpenClaw adapter that calls the framework-agnostic OAuth handler
73
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality.
153
74
  *
154
75
  * Flow:
155
76
  * 1. Initialize OAuth (no params) - Returns { url, state }
156
- * 2. Handle callback (code + state) - Returns { accessToken, refreshToken }
77
+ * 2. Handle callback (code + state + accountId) - Returns { accessToken, refreshToken }
78
+ * - Tokens are automatically saved to account config if accountId is provided
157
79
  *
158
80
  * @param api - OpenClaw plugin API
159
- * @param context - OAuth context with optional code and state from callback
81
+ * @param context - OAuth context with optional code, state, redirectUri, and accountId
160
82
  * @returns OAuthResult with URL and/or token
161
83
  */
162
84
  export async function gmailOAuthHandler(api, context) {
163
85
  try {
164
- const { code, state, redirectUri } = context || {};
165
- // Phase 1: Generate authorization URL
166
- if (!code) {
167
- const { url: authUrl, state: newState } = await generateAuthorizationUrl(api, redirectUri);
168
- return {
169
- url: authUrl,
170
- state: newState,
171
- };
86
+ const { code, state, redirectUri, accountId } = context || {};
87
+ const config = getGmailConfig(api);
88
+ const logger = getLogger(api);
89
+ // Call the framework-agnostic OAuth handler from core
90
+ const result = await coreGmailOAuthHandler(config, { code, state, redirectUri }, logger);
91
+ // Save tokens to account config if accountId is provided and we have accessToken
92
+ if (accountId && result.accessToken && code) {
93
+ await saveGmailTokensToAccount(api, accountId, result.accessToken, result.refreshToken, result.expiresIn);
94
+ logger.info(`Gmail tokens saved for account ${accountId} (expires in ${result.expiresIn}s)`);
172
95
  }
173
- // Phase 2: Exchange authorization code for access token
174
- if (!state) {
175
- throw new Error("State parameter is required for code exchange");
176
- }
177
- const { accessToken, refreshToken, expiresIn } = await exchangeCodeForToken(api, code, state, redirectUri);
178
- return {
179
- url: "",
180
- accessToken,
181
- refreshToken,
182
- expiresIn,
183
- };
96
+ return result;
184
97
  }
185
98
  catch (error) {
186
- api.logger.error?.("Gmail OAuth error:", error);
99
+ getLogger(api).error("Gmail OAuth error:", error);
187
100
  throw error;
188
101
  }
189
102
  }
103
+ /**
104
+ * Refresh Gmail access token using refresh token
105
+ *
106
+ * @param api - OpenClaw plugin API
107
+ * @param accountId - Account ID to refresh token for
108
+ * @returns New access token and expiry info, or null if refresh failed
109
+ */
110
+ export async function refreshGmailToken(api, accountId) {
111
+ const config = api.pluginConfig;
112
+ const logger = getLogger(api);
113
+ // Find the account
114
+ const account = config.accounts?.find((a) => a.id === accountId && a.type === "gmail");
115
+ if (!account) {
116
+ logger.error(`Gmail account ${accountId} not found`);
117
+ return null;
118
+ }
119
+ const gmailConfig = getGmailConfig(api);
120
+ if (!account.gmailRefreshToken) {
121
+ logger.error(`No refresh token available for Gmail account ${accountId}. User must re-authenticate.`);
122
+ return null;
123
+ }
124
+ // Call the framework-agnostic refresh handler from core
125
+ const result = await coreRefreshGmailToken(gmailConfig, account.gmailRefreshToken, logger);
126
+ if (!result) {
127
+ return null;
128
+ }
129
+ // Save new tokens to account config
130
+ await saveGmailTokensToAccount(api, accountId, result.accessToken, account.gmailRefreshToken, result.expiresIn);
131
+ return result;
132
+ }
190
133
  //# sourceMappingURL=gmail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../src/oauth/gmail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../src/oauth/gmail.ts"],"names":[],"mappings":"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"}
@@ -1,28 +1,30 @@
1
1
  /**
2
- * Plaid OAuth handler - implements Plaid Link flow
2
+ * Plaid OAuth handler - OpenClaw adapter
3
3
  *
4
- * This module handles the Plaid Link OAuth flow for connecting bank accounts.
5
- * It supports two modes:
6
- * 1. Link token creation (for initializing Plaid Link frontend)
7
- * 2. Public token exchange (for completing the connection)
4
+ * This is an adapter layer that calls the framework-agnostic OAuth implementation
5
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality (config management).
6
+ *
7
+ * @packageDocumentation
8
8
  */
9
9
  import type { OpenClawPluginApi } from "../types/openclaw-plugin.js";
10
10
  /**
11
11
  * Handle Plaid Link OAuth flow
12
12
  *
13
- * This integrates Plaid Link (https://plaid.com/docs/link/)
14
- * for secure bank account connection.
13
+ * This is an OpenClaw adapter that calls the framework-agnostic OAuth handler
14
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality.
15
15
  *
16
16
  * Flow:
17
17
  * 1. Create Link token (no params) - Returns { url, token: linkToken }
18
18
  * 2. Handle Link success callback - Receives publicToken
19
19
  * 3. Exchange public_token for access_token - Returns { url: "", token: accessToken, itemId }
20
+ * - If accountId is provided, tokens are automatically saved to account config
20
21
  *
21
22
  * @param api - OpenClaw plugin API
22
23
  * @param publicToken - Optional public token from Plaid Link callback
24
+ * @param accountId - Optional account ID to save tokens to
23
25
  * @returns OAuthResult with URL and token
24
26
  */
25
- export declare function plaidOAuthHandler(api: OpenClawPluginApi, publicToken?: string): Promise<{
27
+ export declare function plaidOAuthHandler(api: OpenClawPluginApi, publicToken?: string, accountId?: string): Promise<{
26
28
  url: string;
27
29
  token?: string;
28
30
  itemId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"plaid.d.ts","sourceRoot":"","sources":["../../src/oauth/plaid.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAwFpE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,iBAAiB,EACtB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC;IACT,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC,CA2BD"}
1
+ {"version":3,"file":"plaid.d.ts","sourceRoot":"","sources":["../../src/oauth/plaid.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAyFpE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,iBAAiB,EACtB,WAAW,CAAC,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IACT,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAC,CA6BD"}
@@ -1,12 +1,23 @@
1
1
  /**
2
- * Plaid OAuth handler - implements Plaid Link flow
2
+ * Plaid OAuth handler - OpenClaw adapter
3
3
  *
4
- * This module handles the Plaid Link OAuth flow for connecting bank accounts.
5
- * It supports two modes:
6
- * 1. Link token creation (for initializing Plaid Link frontend)
7
- * 2. Public token exchange (for completing the connection)
4
+ * This is an adapter layer that calls the framework-agnostic OAuth implementation
5
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality (config management).
6
+ *
7
+ * @packageDocumentation
8
8
  */
9
- import { createPlaidClient } from "@firela/billclaw-core";
9
+ import { plaidOAuthHandler as corePlaidOAuthHandler, } from "@firela/billclaw-core";
10
+ /**
11
+ * Get a logger from OpenClaw API, or provide a no-op logger
12
+ */
13
+ function getLogger(api) {
14
+ return {
15
+ info: api.logger?.info || (() => { }),
16
+ error: api.logger?.error || (() => { }),
17
+ warn: api.logger?.warn || (() => { }),
18
+ debug: api.logger?.debug || (() => { }),
19
+ };
20
+ }
10
21
  /**
11
22
  * Get Plaid configuration from OpenClaw config
12
23
  *
@@ -28,80 +39,64 @@ function getPlaidConfig(api) {
28
39
  };
29
40
  }
30
41
  /**
31
- * Create Plaid Link token for initializing Link frontend
32
- */
33
- async function createLinkToken(api, accountId) {
34
- const plaidConfig = getPlaidConfig(api);
35
- const plaidClient = createPlaidClient(plaidConfig);
36
- const request = {
37
- user: {
38
- client_user_id: accountId || `user_${Date.now()}`,
39
- },
40
- client_name: "BillClaw",
41
- products: ["transactions"],
42
- country_codes: ["US"],
43
- language: "en",
44
- };
45
- const axiosResponse = await plaidClient.linkTokenCreate(request);
46
- const response = axiosResponse.data;
47
- api.logger.info?.("Plaid Link token created successfully");
48
- return { linkToken: response.link_token };
49
- }
50
- /**
51
- * Exchange Plaid public token for access token
42
+ * Save Plaid OAuth tokens to account configuration
43
+ *
44
+ * NOTE: This requires the OpenClaw runtime to support config updates.
45
+ * The actual persistence depends on the OpenClawConfigProvider implementation.
52
46
  */
53
- async function exchangePublicToken(api, publicToken) {
54
- const plaidConfig = getPlaidConfig(api);
55
- const plaidClient = createPlaidClient(plaidConfig);
56
- const request = {
57
- public_token: publicToken,
58
- };
59
- const axiosResponse = await plaidClient.itemPublicTokenExchange(request);
60
- const response = axiosResponse.data;
61
- api.logger.info?.("Plaid public token exchanged successfully");
62
- return {
63
- accessToken: response.access_token,
64
- itemId: response.item_id,
47
+ async function savePlaidTokensToAccount(api, accountId, accessToken, itemId) {
48
+ const logger = getLogger(api);
49
+ // Get config from OpenClaw
50
+ const config = api.pluginConfig;
51
+ // Find and update the account
52
+ const accountIndex = config.accounts?.findIndex((a) => a.id === accountId && a.type === "plaid");
53
+ if (accountIndex === -1 || accountIndex === undefined) {
54
+ logger.warn(`Plaid account ${accountId} not found in config. Tokens not saved.`);
55
+ return;
56
+ }
57
+ // Update account with tokens
58
+ config.accounts[accountIndex] = {
59
+ ...config.accounts[accountIndex],
60
+ plaidAccessToken: accessToken,
61
+ plaidItemId: itemId,
62
+ enabled: true, // Auto-enable account after successful OAuth
65
63
  };
64
+ // Note: The actual persistence to disk depends on OpenClaw's config management
65
+ // The updated config is in memory but OpenClaw needs to handle persistence
66
+ logger.info(`Plaid tokens updated in memory for account ${accountId}. Persistence depends on OpenClaw config management.`);
66
67
  }
67
68
  /**
68
69
  * Handle Plaid Link OAuth flow
69
70
  *
70
- * This integrates Plaid Link (https://plaid.com/docs/link/)
71
- * for secure bank account connection.
71
+ * This is an OpenClaw adapter that calls the framework-agnostic OAuth handler
72
+ * from @firela/billclaw-core and adds OpenClaw-specific functionality.
72
73
  *
73
74
  * Flow:
74
75
  * 1. Create Link token (no params) - Returns { url, token: linkToken }
75
76
  * 2. Handle Link success callback - Receives publicToken
76
77
  * 3. Exchange public_token for access_token - Returns { url: "", token: accessToken, itemId }
78
+ * - If accountId is provided, tokens are automatically saved to account config
77
79
  *
78
80
  * @param api - OpenClaw plugin API
79
81
  * @param publicToken - Optional public token from Plaid Link callback
82
+ * @param accountId - Optional account ID to save tokens to
80
83
  * @returns OAuthResult with URL and token
81
84
  */
82
- export async function plaidOAuthHandler(api, publicToken) {
85
+ export async function plaidOAuthHandler(api, publicToken, accountId) {
83
86
  try {
84
- if (!publicToken) {
85
- // No public token provided - create Link token for initializing Link
86
- const { linkToken } = await createLinkToken(api);
87
- // Return Plaid Link URL and the link token
88
- return {
89
- url: "https://cdn.plaid.com/link/v2/stable/link.html",
90
- token: linkToken,
91
- };
87
+ const config = getPlaidConfig(api);
88
+ const logger = getLogger(api);
89
+ // Call the framework-agnostic OAuth handler from core
90
+ const result = await corePlaidOAuthHandler(config, publicToken, accountId, logger);
91
+ // Save tokens to account config if accountId is provided and we have accessToken
92
+ if (accountId && result.accessToken && publicToken) {
93
+ await savePlaidTokensToAccount(api, accountId, result.accessToken, result.itemId || "");
94
+ logger.info(`Plaid tokens saved for account ${accountId}`);
92
95
  }
93
- // Public token provided - exchange for access token
94
- const { accessToken, itemId } = await exchangePublicToken(api, publicToken);
95
- // Return the access token and item ID for storage
96
- return {
97
- url: "",
98
- token: accessToken,
99
- itemId,
100
- accessToken,
101
- };
96
+ return result;
102
97
  }
103
98
  catch (error) {
104
- api.logger.error?.("Plaid OAuth error:", error);
99
+ getLogger(api).error("Plaid OAuth error:", error);
105
100
  throw error;
106
101
  }
107
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plaid.js","sourceRoot":"","sources":["../../src/oauth/plaid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plaid.js","sourceRoot":"","sources":["../../src/oauth/plaid.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAYnE;;GAEG;;;;;;kBAQa,iBAAiB;;AAPjC,wBA0NC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAYnE;;GAEG;;;;;;kBAQa,iBAAiB;;AAPjC,wBA6NC"}
package/dist/plugin.js CHANGED
@@ -176,9 +176,12 @@ export default {
176
176
  // ========================================================================
177
177
  const cfg = api.pluginConfig;
178
178
  const plaidSecret = cfg.plaid?.webhookSecret || process.env.PLAID_WEBHOOK_SECRET;
179
+ // Webhook registration is now async (initializes Core components)
179
180
  registerWebhookHandlers({
180
181
  api,
181
182
  plaidWebhookSecret: plaidSecret,
183
+ }).catch((error) => {
184
+ api.logger.error?.("Failed to register webhook handlers:", error);
182
185
  });
183
186
  // ========================================================================
184
187
  // Background Services