gemini-reverse 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -1,11 +1,7 @@
1
- ![Banner](https://nc-cdn.oss-accelerate.aliyuncs.com/nx/a772a980daeb.png)
2
-
3
1
  # Gemini-Reverse
4
2
 
5
3
  An unofficial Node.js client for [gemini.google.com](https://gemini.google.com), inspired by [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) — a Python reverse engineering project by [@HanaokaYuzu](https://github.com/HanaokaYuzu).
6
4
 
7
- This package ports the core concepts and functionality of the original Python library to Node.js, with full CommonJS and TypeScript support.
8
-
9
5
  ---
10
6
 
11
7
  ## Features
@@ -14,7 +10,11 @@ This package ports the core concepts and functionality of the original Python li
14
10
  - Streaming support with text deltas
15
11
  - Multi-turn chat sessions with conversation history
16
12
  - File and image upload support
13
+ - Video and media (audio) support
17
14
  - Gem (system prompt) management — create, update, delete, fetch
15
+ - Deep research support — create plan, start, poll, and get results
16
+ - Dynamic model discovery from account RPC
17
+ - Account status detection
18
18
  - Auto cookie refresh to keep sessions alive
19
19
  - TypeScript type declarations included
20
20
  - Proxy support
@@ -31,32 +31,28 @@ npm install gemini-reverse
31
31
 
32
32
  ## Authentication
33
33
 
34
- This package uses browser cookies to authenticate with Gemini. You need to obtain your `__Secure-1PSID` cookie from your browser after logging in to [gemini.google.com](https://gemini.google.com).
35
-
36
- **Steps:**
37
- 1. Open [gemini.google.com](https://gemini.google.com) in your browser and log in
38
- 2. Open DevTools → Application → Cookies → `https://gemini.google.com`
39
- 3. Copy the value of `__Secure-1PSID` (and optionally `__Secure-1PSIDTS`)
40
-
41
- > `__Secure-1PSIDTS` is optional — the client will attempt to refresh and cache it automatically after the first successful init.
34
+ ```
35
+ 1. Open gemini.google.com and log in
36
+ 2. DevTools → Application → Cookies → https://gemini.google.com
37
+ 3. Copy __Secure-1PSID (and optionally __Secure-1PSIDTS)
38
+ ```
42
39
 
43
40
  ---
44
41
 
45
42
  ## Quick Start
46
43
 
47
44
  ```js
48
- const { GeminiClient } = require('gemini-core');
45
+ const { GeminiClient } = require('gemini-reverse');
49
46
 
50
- const client = new GeminiClient({
51
- secure_1psid: 'YOUR_SECURE_1PSID',
52
- });
47
+ const client = new GeminiClient({ secure_1psid: 'YOUR_SECURE_1PSID' });
53
48
 
54
49
  await client.init();
55
50
 
56
51
  const chat = client.startChat();
57
52
  const response = await chat.sendMessage({ prompt: 'Hello, Gemini!' });
58
-
59
53
  console.log(response.text);
54
+
55
+ await client.close();
60
56
  ```
61
57
 
62
58
  ---
@@ -66,22 +62,18 @@ console.log(response.text);
66
62
  ### Initialize Client
67
63
 
68
64
  ```js
69
- const client = new GeminiClient({
70
- secure_1psid: 'YOUR_SECURE_1PSID',
71
- secure_1psidts: 'YOUR_SECURE_1PSIDTS', // optional
72
- proxy: 'http://host:port', // optional
73
- });
74
-
75
65
  await client.init({
76
- timeout: 300000, // request timeout in ms, default 300000
77
- autoClose: false, // auto close client after inactivity
78
- closeDelay: 300000, // inactivity delay before closing in ms
79
- autoRefresh: true, // auto refresh cookies in background
80
- refreshInterval: 540000 // cookie refresh interval in ms
66
+ timeout: 300000,
67
+ autoClose: false,
68
+ closeDelay: 300000,
69
+ autoRefresh: true,
70
+ refreshInterval: 540000,
71
+ verbose: false,
72
+ watchdogTimeout: 30000,
81
73
  });
82
74
  ```
83
75
 
84
- ### Generate Content (single turn)
76
+ ### Generate Content
85
77
 
86
78
  ```js
87
79
  const response = await client.generateContent({ prompt: 'What is the capital of France?' });
@@ -99,106 +91,118 @@ for await (const chunk of client.generateContentStream({ prompt: 'Tell me a long
99
91
  ### Chat Session
100
92
 
101
93
  ```js
102
- const chat = client.startChat({ model: 'gemini-3.1-pro' });
94
+ const chat = client.startChat({ model: 'gemini-3-flash' });
103
95
 
104
96
  const res1 = await chat.sendMessage({ prompt: 'My name is Alice.' });
105
- console.log(res1.text);
106
-
107
97
  const res2 = await chat.sendMessage({ prompt: 'What is my name?' });
108
- console.log(res2.text); // remembers context
98
+ console.log(res2.text);
109
99
  ```
110
100
 
111
101
  ### Streaming in Chat
112
102
 
113
103
  ```js
114
- const chat = client.startChat({ model: 'gemini-3.0-flash' });
115
-
104
+ const chat = client.startChat();
116
105
  for await (const chunk of chat.sendMessageStream({ prompt: 'Explain quantum computing.' })) {
117
106
  process.stdout.write(chunk.text_delta);
118
107
  }
119
108
  ```
120
109
 
121
- ### Temporary Chat (no history saved)
110
+ ### Temporary Chat
122
111
 
123
112
  ```js
124
- const chat = client.startChat();
125
113
  const response = await chat.sendMessage({ prompt: 'This will not appear in history.', temporary: true });
126
114
  ```
127
115
 
128
116
  ### Send with Files
129
117
 
130
118
  ```js
131
- const chat = client.startChat();
132
119
  const response = await chat.sendMessage({
133
120
  prompt: 'Describe this image.',
134
121
  files: ['./photo.jpg'],
135
122
  });
136
- console.log(response.text);
137
123
  ```
138
124
 
139
125
  ### Multiple Candidates
140
126
 
141
127
  ```js
142
- const chat = client.startChat();
143
128
  const response = await chat.sendMessage({ prompt: 'Give me a poem.' });
144
-
145
- // list all candidates
146
129
  response.candidates.forEach((c, i) => console.log(`[${i}] ${c.text}`));
147
-
148
- // choose a specific candidate to continue the conversation
149
130
  chat.chooseCandidate(1);
150
131
  ```
151
132
 
152
133
  ### Models
153
134
 
154
135
  ```js
155
- // use model name string
156
- const chat = client.startChat({ model: 'gemini-3.1-pro' });
157
-
158
- // or use the Model constant
159
- const { Model } = require('gemini-api');
160
- const chat = client.startChat({ model: Model.G_3_0_FLASH });
161
-
162
- // or use a custom model dict
163
- const chat = client.startChat({
164
- model: {
165
- model_name: 'my-model',
166
- model_header: { 'x-goog-ext-525001261-jspb': '...' },
167
- },
136
+ const models = client.listModels();
137
+ if (models) {
138
+ for (const m of models) {
139
+ console.log(m.model_id, m.model_name, m.display_name);
140
+ }
141
+ }
142
+
143
+ const chat = client.startChat({ model: 'gemini-3-flash' });
144
+
145
+ const { Model } = require('gemini-reverse');
146
+ const chat2 = client.startChat({ model: Model.BASIC_FLASH });
147
+
148
+ const chat3 = client.startChat({
149
+ model: { model_name: 'my-model', model_header: { 'x-goog-ext-525001261-jspb': '...' } },
168
150
  });
169
151
  ```
170
152
 
171
- **Available models:**
153
+ **Built-in model constants:**
172
154
 
173
- | String | Constant |
155
+ | Constant | model_name |
174
156
  |---|---|
175
- | `gemini-3.1-pro` | `Model.G_3_1_PRO` |
176
- | `gemini-3.0-flash` | `Model.G_3_0_FLASH` |
177
- | `gemini-3.0-flash-thinking` | `Model.G_3_0_FLASH_THINKING` |
178
- | `unspecified` (default) | `Model.UNSPECIFIED` |
157
+ | `Model.UNSPECIFIED` | `unspecified` (default) |
158
+ | `Model.BASIC_PRO` | `gemini-3-pro` |
159
+ | `Model.BASIC_FLASH` | `gemini-3-flash` |
160
+ | `Model.BASIC_THINKING` | `gemini-3-flash-thinking` |
161
+ | `Model.PLUS_PRO` | `gemini-3-pro-plus` |
162
+ | `Model.PLUS_FLASH` | `gemini-3-flash-plus` |
163
+ | `Model.PLUS_THINKING` | `gemini-3-flash-thinking-plus` |
164
+ | `Model.ADVANCED_PRO` | `gemini-3-pro-advanced` |
165
+ | `Model.ADVANCED_FLASH` | `gemini-3-flash-advanced` |
166
+ | `Model.ADVANCED_THINKING` | `gemini-3-flash-thinking-advanced` |
179
167
 
180
168
  ### Images
181
169
 
182
- Responses may include web images or AI-generated images.
183
-
184
170
  ```js
185
- const response = await chat.sendMessage({ prompt: 'Send me an image of a cat.' });
186
-
187
171
  for (const img of response.images) {
188
172
  console.log(img.url, img.title, img.alt);
189
173
  await img.save({ path: './downloads', verbose: true });
190
174
  }
191
175
  ```
192
176
 
193
- ### Read Chat History
177
+ ### Videos & Media
194
178
 
195
179
  ```js
196
- const turns = await client.readChat('c_YOUR_CHAT_ID');
180
+ for (const video of response.videos) {
181
+ await video.save({ savePath: './downloads', verbose: true });
182
+ }
183
+ for (const media of response.media) {
184
+ await media.save({ savePath: './downloads', downloadType: 'both', verbose: true });
185
+ }
186
+ ```
197
187
 
198
- for (const turn of turns) {
199
- console.log('User:', turn.user_prompt);
200
- console.log('Gemini:', turn.assistant_response);
188
+ ### Chat History
189
+
190
+ ```js
191
+ const history = await client.readChat('c_YOUR_CHAT_ID');
192
+ if (history) {
193
+ for (const turn of history.turns) {
194
+ console.log(turn.role, turn.text);
195
+ }
201
196
  }
197
+
198
+ const chats = client.listChats();
199
+ if (chats) {
200
+ for (const info of chats) {
201
+ console.log(info.cid, info.title, info.is_pinned);
202
+ }
203
+ }
204
+
205
+ const sessionHistory = await chat.readHistory(10);
202
206
  ```
203
207
 
204
208
  ### Delete Chat
@@ -207,61 +211,69 @@ for (const turn of turns) {
207
211
  await client.deleteChat('c_YOUR_CHAT_ID');
208
212
  ```
209
213
 
214
+ ### Deep Research
215
+
216
+ ```js
217
+ const plan = await client.createDeepResearchPlan('History of artificial intelligence');
218
+ console.log(plan.title, plan.steps);
219
+
220
+ const startOutput = await client.startDeepResearch(plan);
221
+
222
+ const result = await client.waitForDeepResearch(plan, 10000, 600000, (status) => {
223
+ console.log(status.state, status.notes);
224
+ });
225
+ console.log(result.text);
226
+
227
+ const result2 = await client.deepResearch('Explain quantum computing', 10000, 600000);
228
+ console.log(result2.text);
229
+ ```
230
+
231
+ ### Account Status
232
+
233
+ ```js
234
+ const { AccountStatus } = require('gemini-reverse');
235
+
236
+ if (client.accountStatus === AccountStatus.UNAUTHENTICATED) {
237
+ console.error('Cookies expired.');
238
+ } else if (client.accountStatus === AccountStatus.LOCATION_REJECTED) {
239
+ console.error('Gemini not available in your region.');
240
+ }
241
+ ```
242
+
210
243
  ### Gems
211
244
 
212
245
  ```js
213
- // fetch all gems
214
246
  const gems = await client.fetchGems();
215
-
216
- // get by name
217
247
  const gem = gems.get({ name: 'Coding partner' });
218
-
219
- // filter user-created gems
220
248
  const myGems = gems.filter({ predefined: false });
249
+ const chat = client.startChat({ gem });
221
250
 
222
- // use a gem in chat
223
- const chat = client.startChat({ gem: gem });
224
-
225
- // create a gem
226
251
  const newGem = await client.createGem({
227
252
  name: 'My Assistant',
228
253
  prompt: 'You are a helpful assistant that speaks formally.',
229
- description: 'Formal assistant gem',
230
- });
231
-
232
- // update a gem
233
- await client.updateGem({
234
- gem: newGem,
235
- name: 'My Assistant v2',
236
- prompt: 'You are a helpful assistant that speaks casually.',
237
254
  });
238
255
 
239
- // delete a gem
256
+ await client.updateGem({ gem: newGem, name: 'My Assistant v2', prompt: 'Speak casually.' });
240
257
  await client.deleteGem(newGem);
241
258
  ```
242
259
 
243
- ### Close Client
244
-
245
- ```js
246
- await client.close();
247
- ```
248
-
249
260
  ---
250
261
 
251
- ## TypeScript
252
-
253
- This package includes full TypeScript declarations out of the box.
254
-
255
- ```ts
256
- import { GeminiClient, ChatSession, ModelOutput, ConversationTurn, Gem, Model } from 'gemini-api';
257
-
258
- const client = new GeminiClient({ secure_1psid: '...' });
259
- await client.init();
262
+ ## Error Handling
260
263
 
261
- const chat: ChatSession = client.startChat({ model: 'gemini-3.1-pro' });
262
- const response: ModelOutput = await chat.sendMessage({ prompt: 'Hello!' });
264
+ ```js
265
+ const { AuthError, APIError, GeminiError, TimeoutError, UsageLimitExceeded, ModelInvalid, TemporarilyBlocked } = require('gemini-reverse');
263
266
 
264
- console.log(response.text);
267
+ try {
268
+ const response = await chat.sendMessage({ prompt: 'Hello!' });
269
+ } catch (e) {
270
+ if (e instanceof AuthError) console.error('Cookie expired or invalid.');
271
+ else if (e instanceof UsageLimitExceeded) console.error('Usage limit reached.');
272
+ else if (e instanceof TemporarilyBlocked) console.error('IP temporarily blocked.');
273
+ else if (e instanceof TimeoutError) console.error('Request timed out.');
274
+ else if (e instanceof ModelInvalid) console.error('Invalid model.');
275
+ else if (e instanceof APIError) console.error('API error:', e.message);
276
+ }
265
277
  ```
266
278
 
267
279
  ---
@@ -269,77 +281,50 @@ console.log(response.text);
269
281
  ## Project Structure
270
282
 
271
283
  ```
272
- gemini-api/
273
- ├── index.js # entry point
274
- ├── index.d.ts # TypeScript declarations
275
- ├── client.js # GeminiClient + ChatSession
276
- ├── constants.js # Endpoint, GRPC, Headers, Model, ErrorCode
277
- ├── exceptions.js # custom error classes
284
+ gemini-reverse/
285
+ ├── index.js
286
+ ├── index.d.ts
287
+ ├── client.js
288
+ ├── constants.js
289
+ ├── exceptions.js
278
290
  ├── types/
291
+ │ ├── availablemodel.js
279
292
  │ ├── candidate.js
280
- │ ├── conversation.js
293
+ │ ├── chathistory.js
294
+ │ ├── chatinfo.js
281
295
  │ ├── gem.js
282
296
  │ ├── grpc.js
283
297
  │ ├── image.js
284
- └── modeloutput.js
298
+ ├── modeloutput.js
299
+ │ ├── research.js
300
+ │ ├── researchresult.js
301
+ │ └── video.js
285
302
  ├── utils/
286
303
  │ ├── accessToken.js
287
304
  │ ├── parsing.js
305
+ │ ├── research.js
288
306
  │ ├── rotate.js
289
307
  │ └── upload.js
290
308
  └── components/
291
309
  ├── chatMixin.js
292
- └── gemMixin.js
293
- ```
294
-
295
- ---
296
-
297
- ## Error Handling
298
-
299
- ```js
300
- const {
301
- AuthError,
302
- APIError,
303
- GeminiError,
304
- TimeoutError,
305
- UsageLimitExceeded,
306
- ModelInvalid,
307
- TemporarilyBlocked,
308
- } = require('gemini-api');
309
-
310
- try {
311
- const response = await chat.sendMessage({ prompt: 'Hello!' });
312
- } catch (e) {
313
- if (e instanceof AuthError) {
314
- console.error('Cookie expired or invalid.');
315
- } else if (e instanceof UsageLimitExceeded) {
316
- console.error('Usage limit reached. Try again later or switch models.');
317
- } else if (e instanceof TemporarilyBlocked) {
318
- console.error('IP temporarily blocked. Try using a proxy.');
319
- } else if (e instanceof TimeoutError) {
320
- console.error('Request timed out.');
321
- } else if (e instanceof ModelInvalid) {
322
- console.error('Invalid or unavailable model.');
323
- } else if (e instanceof APIError) {
324
- console.error('API error:', e.message);
325
- }
326
- }
310
+ ├── gemMixin.js
311
+ └── researchMixin.js
327
312
  ```
328
313
 
329
314
  ---
330
315
 
331
316
  ## Credits
332
317
 
333
- Inspired by [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) by [@HanaokaYuzu](https://github.com/HanaokaYuzu) — an unofficial Python client for Gemini through reverse engineering.
318
+ Inspired by [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) by [@HanaokaYuzu](https://github.com/HanaokaYuzu).
334
319
 
335
320
  ---
336
321
 
337
322
  ## Disclaimer
338
323
 
339
- This is an unofficial package and is not affiliated with or endorsed by Google. Use at your own risk. Cookie-based authentication may break if Google changes its internal API.
324
+ Unofficial package, not affiliated with Google. Use at your own risk.
340
325
 
341
326
  ---
342
327
 
343
328
  ## License
344
329
 
345
- MIT
330
+ MIT