opencode-gemini-business 2.1.0 → 2.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/CHANGELOG.md +26 -0
- package/README.en.md +278 -0
- package/README.md +116 -102
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +69 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -36
- package/dist/index.js.map +1 -1
- package/dist/opencode-gemini-business-2.3.0.tgz +0 -0
- package/dist/src/account-manager.d.ts +5 -7
- package/dist/src/account-manager.d.ts.map +1 -1
- package/dist/src/account-manager.js +31 -24
- package/dist/src/account-manager.js.map +1 -1
- package/dist/src/browser-auth.d.ts +35 -0
- package/dist/src/browser-auth.d.ts.map +1 -0
- package/dist/src/browser-auth.js +212 -0
- package/dist/src/browser-auth.js.map +1 -0
- package/dist/src/gemini-business-api.d.ts +1 -0
- package/dist/src/gemini-business-api.d.ts.map +1 -1
- package/dist/src/gemini-business-api.js +25 -16
- package/dist/src/gemini-business-api.js.map +1 -1
- package/dist/src/types.d.ts +23 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +4 -2
- package/README.ru.md +0 -264
- package/dist/opencode-gemini-business-2.1.0.tgz +0 -0
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Multi-account Gemini Business pool with automatic rotation
|
|
4
4
|
*/
|
|
5
5
|
import { AccountManager } from './src/account-manager.js';
|
|
6
|
-
import { GeminiBusinessAPI } from './src/gemini-business-api.js';
|
|
6
|
+
import { GeminiBusinessAPI, SESSION_TTL_MS } from './src/gemini-business-api.js';
|
|
7
7
|
function isAsyncIterable(value) {
|
|
8
8
|
return (value !== null &&
|
|
9
9
|
typeof value === 'object' &&
|
|
@@ -18,12 +18,11 @@ function toSSEStream(chunks) {
|
|
|
18
18
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
|
|
19
19
|
}
|
|
20
20
|
controller.enqueue(encoder.encode('data: [DONE]\n\n'));
|
|
21
|
+
controller.close();
|
|
21
22
|
}
|
|
22
23
|
catch (error) {
|
|
23
24
|
controller.error(error);
|
|
24
|
-
return;
|
|
25
25
|
}
|
|
26
|
-
controller.close();
|
|
27
26
|
},
|
|
28
27
|
});
|
|
29
28
|
}
|
|
@@ -43,55 +42,58 @@ export const GeminiBusinessPlugin = async (_ctx) => {
|
|
|
43
42
|
' opencode-gemini-business help\n');
|
|
44
43
|
return {};
|
|
45
44
|
}
|
|
46
|
-
console.log(
|
|
47
|
-
` Strategy: ${accountManager.getConfig().rotation_strategy}\n`);
|
|
45
|
+
console.log(`✅ Gemini Business: ${accounts.length} account(s), ${accountManager.getConfig().rotation_strategy}`);
|
|
48
46
|
return {
|
|
49
47
|
apiKey: '',
|
|
50
48
|
async fetch(_input, init) {
|
|
51
|
-
|
|
49
|
+
const config = accountManager.getConfig();
|
|
50
|
+
let lastError = null;
|
|
51
|
+
for (let attempt = 0; attempt < config.max_retries; attempt++) {
|
|
52
52
|
const account = accountManager.getNextAccount();
|
|
53
53
|
if (!account) {
|
|
54
54
|
throw new Error('No available accounts');
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
try {
|
|
57
|
+
const api = new GeminiBusinessAPI(account);
|
|
58
|
+
if (api.needsSessionRefresh()) {
|
|
59
|
+
await api.refreshSession();
|
|
60
|
+
await accountManager.updateSession(account.id, account.session_id, SESSION_TTL_MS);
|
|
61
|
+
}
|
|
62
|
+
const requestBody = init?.body
|
|
63
|
+
? JSON.parse(init.body)
|
|
64
|
+
: {};
|
|
65
|
+
const response = await api.chatCompletion(requestBody);
|
|
66
|
+
accountManager.resetAccountErrors(account.id);
|
|
67
|
+
if (requestBody.stream) {
|
|
68
|
+
if (!isAsyncIterable(response)) {
|
|
69
|
+
throw new Error('Provider returned non-stream response for stream request');
|
|
70
|
+
}
|
|
71
|
+
return new Response(toSSEStream(response), {
|
|
72
|
+
status: 200,
|
|
73
|
+
headers: {
|
|
74
|
+
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
75
|
+
'Cache-Control': 'no-cache',
|
|
76
|
+
Connection: 'keep-alive',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
70
79
|
}
|
|
71
|
-
return new Response(
|
|
80
|
+
return new Response(JSON.stringify(response), {
|
|
72
81
|
status: 200,
|
|
73
82
|
headers: {
|
|
74
|
-
'Content-Type': '
|
|
75
|
-
'Cache-Control': 'no-cache',
|
|
76
|
-
Connection: 'keep-alive',
|
|
83
|
+
'Content-Type': 'application/json',
|
|
77
84
|
},
|
|
78
85
|
});
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
headers: {
|
|
83
|
-
'Content-Type': 'application/json',
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
89
|
-
const account = accountManager.getNextAccount();
|
|
90
|
-
if (account) {
|
|
87
|
+
catch (error) {
|
|
88
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
91
89
|
accountManager.markAccountError(account.id, errorMessage);
|
|
90
|
+
lastError = error instanceof Error ? error : new Error(errorMessage);
|
|
91
|
+
if (attempt < config.max_retries - 1) {
|
|
92
|
+
await new Promise((r) => setTimeout(r, config.retry_delay));
|
|
93
|
+
}
|
|
92
94
|
}
|
|
93
|
-
throw new Error(`Gemini Business API Error: ${errorMessage}`);
|
|
94
95
|
}
|
|
96
|
+
throw new Error(`Gemini Business API Error after ${config.max_retries} attempts: ${lastError?.message}`);
|
|
95
97
|
},
|
|
96
98
|
};
|
|
97
99
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
@@ -5,15 +5,17 @@ import { GeminiBusinessAccount, PoolConfig } from './types.js';
|
|
|
5
5
|
export declare class AccountManager {
|
|
6
6
|
private config;
|
|
7
7
|
private currentIndex;
|
|
8
|
+
private writeQueue;
|
|
8
9
|
constructor(config?: Partial<PoolConfig>);
|
|
9
10
|
/**
|
|
10
11
|
* Load accounts from config file
|
|
11
12
|
*/
|
|
12
13
|
loadAccounts(): Promise<void>;
|
|
13
14
|
/**
|
|
14
|
-
* Save accounts to config file
|
|
15
|
+
* Save accounts to config file (queued to prevent concurrent writes)
|
|
15
16
|
*/
|
|
16
17
|
saveAccounts(): Promise<void>;
|
|
18
|
+
private writeToDisk;
|
|
17
19
|
/**
|
|
18
20
|
* Add a new account
|
|
19
21
|
*/
|
|
@@ -34,18 +36,14 @@ export declare class AccountManager {
|
|
|
34
36
|
* Reset account errors (e.g., after successful request)
|
|
35
37
|
*/
|
|
36
38
|
resetAccountErrors(accountId: string): void;
|
|
37
|
-
/**
|
|
38
|
-
* Check if session needs refresh
|
|
39
|
-
*/
|
|
40
|
-
needsSessionRefresh(account: GeminiBusinessAccount): boolean;
|
|
41
39
|
/**
|
|
42
40
|
* Update account session
|
|
43
41
|
*/
|
|
44
42
|
updateSession(accountId: string, sessionId: string, expiresIn: number): Promise<void>;
|
|
45
43
|
/**
|
|
46
|
-
* Update
|
|
44
|
+
* Update cached JWT token
|
|
47
45
|
*/
|
|
48
|
-
|
|
46
|
+
updateCachedJWT(accountId: string, token: string, expiresIn: number): Promise<void>;
|
|
49
47
|
/**
|
|
50
48
|
* Get all accounts
|
|
51
49
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-manager.d.ts","sourceRoot":"","sources":["../../src/account-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"account-manager.d.ts","sourceRoot":"","sources":["../../src/account-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ/D,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,UAAU,CAAoC;gBAE1C,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAYxC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiCnC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAMrB,WAAW;IAWzB;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAc7E;;OAEG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASjD;;OAEG;IACH,cAAc,IAAI,qBAAqB,GAAG,IAAI;IAqC9C;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAiBxD;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ3C;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3F;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzF;;OAEG;IACH,WAAW,IAAI,qBAAqB,EAAE;IAItC;;OAEG;IACH,SAAS,IAAI,UAAU;CAGxB"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Account Manager for multi-account rotation
|
|
3
3
|
*/
|
|
4
|
-
import { readFile, writeFile } from 'fs/promises';
|
|
5
|
-
import { existsSync } from 'fs';
|
|
4
|
+
import { readFile, writeFile, access, mkdir } from 'fs/promises';
|
|
6
5
|
import { homedir } from 'os';
|
|
7
6
|
import { join } from 'path';
|
|
8
7
|
const CONFIG_DIR = join(homedir(), '.config', 'opencode');
|
|
@@ -10,6 +9,7 @@ const ACCOUNTS_FILE = join(CONFIG_DIR, 'gemini-business-accounts.json');
|
|
|
10
9
|
export class AccountManager {
|
|
11
10
|
config;
|
|
12
11
|
currentIndex = 0;
|
|
12
|
+
writeQueue = Promise.resolve();
|
|
13
13
|
constructor(config) {
|
|
14
14
|
this.config = {
|
|
15
15
|
accounts: [],
|
|
@@ -25,7 +25,10 @@ export class AccountManager {
|
|
|
25
25
|
* Load accounts from config file
|
|
26
26
|
*/
|
|
27
27
|
async loadAccounts() {
|
|
28
|
-
|
|
28
|
+
try {
|
|
29
|
+
await access(ACCOUNTS_FILE);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
29
32
|
console.warn(`No accounts file found at ${ACCOUNTS_FILE}`);
|
|
30
33
|
return;
|
|
31
34
|
}
|
|
@@ -33,7 +36,15 @@ export class AccountManager {
|
|
|
33
36
|
const data = await readFile(ACCOUNTS_FILE, 'utf-8');
|
|
34
37
|
const saved = JSON.parse(data);
|
|
35
38
|
this.config.accounts = saved.accounts || [];
|
|
36
|
-
//
|
|
39
|
+
// Migrate deprecated xsrf_token → cached_jwt
|
|
40
|
+
for (const account of this.config.accounts) {
|
|
41
|
+
if (account.xsrf_token && !account.cached_jwt) {
|
|
42
|
+
account.cached_jwt = account.xsrf_token;
|
|
43
|
+
account.cached_jwt_expires = account.xsrf_expires;
|
|
44
|
+
delete account.xsrf_token;
|
|
45
|
+
delete account.xsrf_expires;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
37
48
|
if (saved.rotation_strategy)
|
|
38
49
|
this.config.rotation_strategy = saved.rotation_strategy;
|
|
39
50
|
if (saved.max_retries !== undefined)
|
|
@@ -46,13 +57,18 @@ export class AccountManager {
|
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
/**
|
|
49
|
-
* Save accounts to config file
|
|
60
|
+
* Save accounts to config file (queued to prevent concurrent writes)
|
|
50
61
|
*/
|
|
51
62
|
async saveAccounts() {
|
|
63
|
+
const op = this.writeQueue.then(() => this.writeToDisk());
|
|
64
|
+
this.writeQueue = op.catch(() => { }); // queue stays healthy
|
|
65
|
+
return op; // caller sees the real result
|
|
66
|
+
}
|
|
67
|
+
async writeToDisk() {
|
|
52
68
|
try {
|
|
69
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
53
70
|
const data = JSON.stringify(this.config, null, 2);
|
|
54
71
|
await writeFile(ACCOUNTS_FILE, data, 'utf-8');
|
|
55
|
-
console.log(`Saved ${this.config.accounts.length} accounts to ${ACCOUNTS_FILE}`);
|
|
56
72
|
}
|
|
57
73
|
catch (error) {
|
|
58
74
|
console.error('Failed to save accounts:', error);
|
|
@@ -63,12 +79,12 @@ export class AccountManager {
|
|
|
63
79
|
* Add a new account
|
|
64
80
|
*/
|
|
65
81
|
async addAccount(account) {
|
|
66
|
-
const id = `account-${Date.now()}-${Math.random().toString(36).
|
|
82
|
+
const id = `account-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
67
83
|
const newAccount = {
|
|
84
|
+
error_count: 0,
|
|
68
85
|
...account,
|
|
69
86
|
id,
|
|
70
|
-
enabled: true,
|
|
71
|
-
error_count: 0,
|
|
87
|
+
enabled: account.enabled !== undefined ? account.enabled : true,
|
|
72
88
|
};
|
|
73
89
|
this.config.accounts.push(newAccount);
|
|
74
90
|
await this.saveAccounts();
|
|
@@ -126,10 +142,11 @@ export class AccountManager {
|
|
|
126
142
|
return;
|
|
127
143
|
account.error_count = (account.error_count || 0) + 1;
|
|
128
144
|
account.last_error = error;
|
|
129
|
-
// Disable account if error threshold reached
|
|
130
145
|
if (account.error_count >= this.config.error_threshold) {
|
|
131
146
|
account.enabled = false;
|
|
132
147
|
console.warn(`Account ${account.name} (${accountId}) disabled after ${account.error_count} errors`);
|
|
148
|
+
// Persist the disabled state so it survives restart
|
|
149
|
+
this.saveAccounts().catch((err) => console.error('Failed to persist account state:', err));
|
|
133
150
|
}
|
|
134
151
|
}
|
|
135
152
|
/**
|
|
@@ -142,16 +159,6 @@ export class AccountManager {
|
|
|
142
159
|
account.error_count = 0;
|
|
143
160
|
account.last_error = undefined;
|
|
144
161
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Check if session needs refresh
|
|
147
|
-
*/
|
|
148
|
-
needsSessionRefresh(account) {
|
|
149
|
-
if (!account.session_id || !account.session_expires)
|
|
150
|
-
return true;
|
|
151
|
-
const now = Date.now();
|
|
152
|
-
const expiresIn = account.session_expires - now;
|
|
153
|
-
return expiresIn < this.config.session_refresh_threshold * 1000;
|
|
154
|
-
}
|
|
155
162
|
/**
|
|
156
163
|
* Update account session
|
|
157
164
|
*/
|
|
@@ -164,14 +171,14 @@ export class AccountManager {
|
|
|
164
171
|
await this.saveAccounts();
|
|
165
172
|
}
|
|
166
173
|
/**
|
|
167
|
-
* Update
|
|
174
|
+
* Update cached JWT token
|
|
168
175
|
*/
|
|
169
|
-
async
|
|
176
|
+
async updateCachedJWT(accountId, token, expiresIn) {
|
|
170
177
|
const account = this.config.accounts.find(acc => acc.id === accountId);
|
|
171
178
|
if (!account)
|
|
172
179
|
return;
|
|
173
|
-
account.
|
|
174
|
-
account.
|
|
180
|
+
account.cached_jwt = token;
|
|
181
|
+
account.cached_jwt_expires = Date.now() + expiresIn;
|
|
175
182
|
await this.saveAccounts();
|
|
176
183
|
}
|
|
177
184
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-manager.js","sourceRoot":"","sources":["../../src/account-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"account-manager.js","sourceRoot":"","sources":["../../src/account-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,+BAA+B,CAAC,CAAC;AAExE,MAAM,OAAO,cAAc;IACjB,MAAM,CAAa;IACnB,YAAY,GAAW,CAAC,CAAC;IACzB,UAAU,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEtD,YAAY,MAA4B;QACtC,IAAI,CAAC,MAAM,GAAG;YACZ,QAAQ,EAAE,EAAE;YACZ,iBAAiB,EAAE,aAAa;YAChC,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,IAAI;YACjB,yBAAyB,EAAE,GAAG,EAAE,YAAY;YAC5C,eAAe,EAAE,CAAC;YAClB,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,6BAA6B,aAAa,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;YAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;YAE5C,6CAA6C;YAC7C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC3C,IAAI,OAAO,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;oBAC9C,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;oBACxC,OAAO,CAAC,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;oBAClD,OAAO,OAAO,CAAC,UAAU,CAAC;oBAC1B,OAAO,OAAO,CAAC,YAAY,CAAC;gBAC9B,CAAC;YACH,CAAC;YAED,IAAI,KAAK,CAAC,iBAAiB;gBAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC;YACrF,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;gBAAE,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;YAEjF,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,WAAW,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,sBAAsB;QAC5D,OAAO,EAAE,CAAC,CAAC,8BAA8B;IAC3C,CAAC;IAEO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAClD,MAAM,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,OAA0C;QACzD,MAAM,EAAE,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAClF,MAAM,UAAU,GAA0B;YACxC,WAAW,EAAE,CAAC;YACd,GAAG,OAAO;YACV,EAAE;YACF,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;SAChE,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,EAAU;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAE/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAExE,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,OAA8B,CAAC;QAEnC,QAAQ,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;YACtC,KAAK,aAAa;gBAChB,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;gBACtE,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM;YAER,KAAK,YAAY;gBACf,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;oBAClD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;oBACvC,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC;oBAC3C,OAAO,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;gBACnD,CAAC,CAAC,CAAC;gBACH,MAAM;YAER,KAAK,QAAQ;gBACX,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC9E,MAAM;YAER;gBACE,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;QAED,6BAA6B;QAC7B,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,SAAiB,EAAE,KAAa;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,OAAO,CAAC,WAAW,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACrD,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC;QAE3B,IAAI,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACvD,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,IAAI,KAAK,SAAS,oBAAoB,OAAO,CAAC,WAAW,SAAS,CAAC,CAAC;YACpG,oDAAoD;YACpD,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAChC,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,SAAiB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC;QACxB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB,EAAE,SAAiB,EAAE,SAAiB;QACzE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;QAC/B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACjD,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,SAAiB,EAAE,KAAa,EAAE,SAAiB;QACvE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC;QAC3B,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACpD,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based credential capture for Gemini Business accounts.
|
|
3
|
+
*
|
|
4
|
+
* Launches system Chrome via puppeteer-core, lets the user authenticate,
|
|
5
|
+
* then extracts cookies and intercepts network requests to capture
|
|
6
|
+
* csesidx and team_id automatically.
|
|
7
|
+
*/
|
|
8
|
+
import { BrowserAuthOptions, CapturedCredentials } from './types.js';
|
|
9
|
+
export declare class BrowserAuth {
|
|
10
|
+
private options;
|
|
11
|
+
constructor(options?: BrowserAuthOptions);
|
|
12
|
+
/**
|
|
13
|
+
* Find system Chrome/Chromium installation.
|
|
14
|
+
* Throws a descriptive error if not found.
|
|
15
|
+
*/
|
|
16
|
+
findChrome(): string;
|
|
17
|
+
/**
|
|
18
|
+
* Launch headful Chrome with a temporary profile and navigate to Gemini Business.
|
|
19
|
+
*/
|
|
20
|
+
private launchBrowser;
|
|
21
|
+
/**
|
|
22
|
+
* Poll cookies until login is detected.
|
|
23
|
+
* Returns captured cookies or null on timeout.
|
|
24
|
+
*/
|
|
25
|
+
private waitForCookies;
|
|
26
|
+
/**
|
|
27
|
+
* Set up request interception to capture csesidx and team_id.
|
|
28
|
+
*/
|
|
29
|
+
private setupRequestInterception;
|
|
30
|
+
/**
|
|
31
|
+
* Main orchestrator: launch browser, wait for login, capture credentials.
|
|
32
|
+
*/
|
|
33
|
+
captureCredentials(onStatus?: (message: string) => void): Promise<CapturedCredentials>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=browser-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-auth.d.ts","sourceRoot":"","sources":["../../src/browser-auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWrE,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA+B;gBAElC,OAAO,CAAC,EAAE,kBAAkB;IAIxC;;;OAGG;IACH,UAAU,IAAI,MAAM;IAepB;;OAEG;YACW,aAAa;IAkB3B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA2ChC;;OAEG;IACG,kBAAkB,CACtB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACnC,OAAO,CAAC,mBAAmB,CAAC;CA8FhC"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based credential capture for Gemini Business accounts.
|
|
3
|
+
*
|
|
4
|
+
* Launches system Chrome via puppeteer-core, lets the user authenticate,
|
|
5
|
+
* then extracts cookies and intercepts network requests to capture
|
|
6
|
+
* csesidx and team_id automatically.
|
|
7
|
+
*/
|
|
8
|
+
import puppeteer from 'puppeteer-core';
|
|
9
|
+
import * as ChromeLauncher from 'chrome-launcher';
|
|
10
|
+
const GEMINI_BUSINESS_URL = 'https://business.gemini.google';
|
|
11
|
+
const DEFAULT_OPTIONS = {
|
|
12
|
+
timeout: 10 * 60 * 1000, // 10 minutes
|
|
13
|
+
reminderDelay: 5 * 60 * 1000, // 5 minutes
|
|
14
|
+
pollInterval: 2000, // 2 seconds
|
|
15
|
+
name: '',
|
|
16
|
+
};
|
|
17
|
+
export class BrowserAuth {
|
|
18
|
+
options;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Find system Chrome/Chromium installation.
|
|
24
|
+
* Throws a descriptive error if not found.
|
|
25
|
+
*/
|
|
26
|
+
findChrome() {
|
|
27
|
+
const installations = ChromeLauncher.Launcher.getInstallations();
|
|
28
|
+
if (installations.length === 0) {
|
|
29
|
+
throw new Error('❌ Google Chrome not found on this system.\n\n' +
|
|
30
|
+
' Install Chrome: https://www.google.com/chrome/\n\n' +
|
|
31
|
+
' Or add an account manually:\n' +
|
|
32
|
+
' opencode-gemini-business add-account --manual <name> <team_id> <secure_c_ses> <host_c_oses> <csesidx> [user_agent]');
|
|
33
|
+
}
|
|
34
|
+
return installations[0];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Launch headful Chrome with a temporary profile and navigate to Gemini Business.
|
|
38
|
+
*/
|
|
39
|
+
async launchBrowser(chromePath) {
|
|
40
|
+
const browser = await puppeteer.launch({
|
|
41
|
+
executablePath: chromePath,
|
|
42
|
+
headless: false,
|
|
43
|
+
args: [
|
|
44
|
+
'--no-first-run',
|
|
45
|
+
'--no-default-browser-check',
|
|
46
|
+
'--disable-extensions',
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
const pages = await browser.pages();
|
|
50
|
+
const page = pages[0] || await browser.newPage();
|
|
51
|
+
await page.goto(GEMINI_BUSINESS_URL, { waitUntil: 'networkidle2' });
|
|
52
|
+
return { browser, page };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Poll cookies until login is detected.
|
|
56
|
+
* Returns captured cookies or null on timeout.
|
|
57
|
+
*/
|
|
58
|
+
waitForCookies(page, signal) {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
const interval = setInterval(async () => {
|
|
61
|
+
if (signal.aborted) {
|
|
62
|
+
clearInterval(interval);
|
|
63
|
+
resolve(null);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const cookies = await page.cookies(GEMINI_BUSINESS_URL);
|
|
68
|
+
const secureCses = cookies.find((c) => c.name === '__Secure-C_SES');
|
|
69
|
+
const hostCoses = cookies.find((c) => c.name === '__Host-C_OSES');
|
|
70
|
+
if (secureCses && hostCoses) {
|
|
71
|
+
clearInterval(interval);
|
|
72
|
+
resolve({
|
|
73
|
+
secure_c_ses: secureCses.value,
|
|
74
|
+
host_c_oses: hostCoses.value,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Page may have been closed
|
|
80
|
+
clearInterval(interval);
|
|
81
|
+
resolve(null);
|
|
82
|
+
}
|
|
83
|
+
}, this.options.pollInterval);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Set up request interception to capture csesidx and team_id.
|
|
88
|
+
*/
|
|
89
|
+
setupRequestInterception(page) {
|
|
90
|
+
let csesidx = null;
|
|
91
|
+
let team_id = null;
|
|
92
|
+
page.on('request', (request) => {
|
|
93
|
+
const url = request.url();
|
|
94
|
+
// Capture csesidx from getoxsrf request
|
|
95
|
+
if (url.includes('getoxsrf') && !csesidx) {
|
|
96
|
+
try {
|
|
97
|
+
const parsed = new URL(url);
|
|
98
|
+
const value = parsed.searchParams.get('csesidx');
|
|
99
|
+
if (value) {
|
|
100
|
+
csesidx = value;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Ignore URL parse errors
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Capture team_id (configId) from widgetCreateSession request
|
|
108
|
+
if (url.includes('widgetCreateSession') && !team_id) {
|
|
109
|
+
try {
|
|
110
|
+
const postData = request.postData();
|
|
111
|
+
if (postData) {
|
|
112
|
+
const body = JSON.parse(postData);
|
|
113
|
+
if (body.configId) {
|
|
114
|
+
team_id = body.configId;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Ignore JSON parse errors
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
getCaptured: () => ({ csesidx, team_id }),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Main orchestrator: launch browser, wait for login, capture credentials.
|
|
129
|
+
*/
|
|
130
|
+
async captureCredentials(onStatus) {
|
|
131
|
+
const log = onStatus || (() => { });
|
|
132
|
+
// Find Chrome
|
|
133
|
+
const chromePath = this.findChrome();
|
|
134
|
+
log('🚀 Launching Chrome...');
|
|
135
|
+
// Launch browser
|
|
136
|
+
const { browser, page } = await this.launchBrowser(chromePath);
|
|
137
|
+
// Capture User-Agent
|
|
138
|
+
const userAgent = await page.evaluate('navigator.userAgent');
|
|
139
|
+
// Set up request interception
|
|
140
|
+
const { getCaptured } = this.setupRequestInterception(page);
|
|
141
|
+
// Set up abort controller for timeout
|
|
142
|
+
const controller = new AbortController();
|
|
143
|
+
const { signal } = controller;
|
|
144
|
+
// Overall timeout
|
|
145
|
+
const timeoutId = setTimeout(() => {
|
|
146
|
+
controller.abort();
|
|
147
|
+
}, this.options.timeout);
|
|
148
|
+
// Handle browser close
|
|
149
|
+
let browserClosed = false;
|
|
150
|
+
browser.on('disconnected', () => {
|
|
151
|
+
browserClosed = true;
|
|
152
|
+
controller.abort();
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
log('🔑 Waiting for login... Please sign in to Gemini Business in the browser window.');
|
|
156
|
+
// Phase 1: Wait for cookies (login detection)
|
|
157
|
+
const cookies = await this.waitForCookies(page, signal);
|
|
158
|
+
if (!cookies) {
|
|
159
|
+
if (browserClosed) {
|
|
160
|
+
throw new Error('Browser closed before login completed.');
|
|
161
|
+
}
|
|
162
|
+
throw new Error('Timeout — login not detected within the time limit. Try again or use --manual.');
|
|
163
|
+
}
|
|
164
|
+
log('✅ Logged in! Now send any message in the Gemini Business chat...');
|
|
165
|
+
// Phase 2: Wait for network requests (csesidx + team_id)
|
|
166
|
+
const reminderTimeout = setTimeout(() => {
|
|
167
|
+
log('⏳ Still waiting... Please send a message in the Gemini Business chat to complete setup.');
|
|
168
|
+
}, this.options.reminderDelay);
|
|
169
|
+
const networkResult = await new Promise((resolve, reject) => {
|
|
170
|
+
const checkInterval = setInterval(() => {
|
|
171
|
+
if (signal.aborted) {
|
|
172
|
+
clearInterval(checkInterval);
|
|
173
|
+
clearTimeout(reminderTimeout);
|
|
174
|
+
if (browserClosed) {
|
|
175
|
+
reject(new Error('Browser closed before all credentials were captured.'));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
reject(new Error('Timeout — try again or use --manual.'));
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const captured = getCaptured();
|
|
183
|
+
if (captured.csesidx && captured.team_id) {
|
|
184
|
+
clearInterval(checkInterval);
|
|
185
|
+
clearTimeout(reminderTimeout);
|
|
186
|
+
resolve({ csesidx: captured.csesidx, team_id: captured.team_id });
|
|
187
|
+
}
|
|
188
|
+
}, this.options.pollInterval);
|
|
189
|
+
});
|
|
190
|
+
// Close browser
|
|
191
|
+
clearTimeout(timeoutId);
|
|
192
|
+
await browser.close();
|
|
193
|
+
return {
|
|
194
|
+
cookies,
|
|
195
|
+
csesidx: networkResult.csesidx,
|
|
196
|
+
team_id: networkResult.team_id,
|
|
197
|
+
user_agent: userAgent,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
clearTimeout(timeoutId);
|
|
202
|
+
try {
|
|
203
|
+
await browser.close();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Browser may already be closed
|
|
207
|
+
}
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=browser-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-auth.js","sourceRoot":"","sources":["../../src/browser-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - https://biz-discoveryengine.googleapis.com/v1alpha/locations/global/widgetStreamAssist (chat)
|
|
8
8
|
*/
|
|
9
9
|
import { GeminiBusinessAccount, ChatCompletionRequest, ChatCompletionResponse } from './types.js';
|
|
10
|
+
export declare const SESSION_TTL_MS: number;
|
|
10
11
|
export declare class GeminiBusinessAPI {
|
|
11
12
|
private account;
|
|
12
13
|
constructor(account: GeminiBusinessAccount);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini-business-api.d.ts","sourceRoot":"","sources":["../../src/gemini-business-api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EAEvB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"gemini-business-api.d.ts","sourceRoot":"","sources":["../../src/gemini-business-api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EAEvB,MAAM,YAAY,CAAC;AASpB,eAAO,MAAM,cAAc,QAAiB,CAAC;AAI7C,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAwB;gBAE3B,OAAO,EAAE,qBAAqB;IAI1C;;OAEG;IACH,OAAO,CAAC,SAAS;IAqCjB;;;OAGG;YACW,MAAM;IA6CpB;;;OAGG;YACW,aAAa;IAsD3B;;OAEG;IACG,cAAc,CAClB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,sBAAsB,GAAG,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAsC1E;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmC7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAsBvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAYlB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8C7B;;OAEG;YACY,oBAAoB;IAkHnC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiBlE;;OAEG;IACH,mBAAmB,IAAI,OAAO;IAY9B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CAQtC"}
|