gemini-reverse 1.0.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 +21 -0
- package/README.md +345 -0
- package/client.js +428 -0
- package/components/chatMixin.js +104 -0
- package/components/gemMixin.js +87 -0
- package/components/index.js +6 -0
- package/constants.js +94 -0
- package/exceptions.js +35 -0
- package/index.d.ts +329 -0
- package/index.js +34 -0
- package/package.json +35 -0
- package/types/candidate.js +39 -0
- package/types/conversation.js +32 -0
- package/types/gem.js +58 -0
- package/types/grpc.js +19 -0
- package/types/image.js +74 -0
- package/types/index.js +10 -0
- package/types/modeloutput.js +39 -0
- package/utils/accessToken.js +105 -0
- package/utils/index.js +25 -0
- package/utils/parsing.js +119 -0
- package/utils/rotate.js +43 -0
- package/utils/upload.js +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Randyyyyy.
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Gemini-Reverse
|
|
4
|
+
|
|
5
|
+
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
|
+
|
|
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
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Send messages and receive responses from Gemini
|
|
14
|
+
- Streaming support with text deltas
|
|
15
|
+
- Multi-turn chat sessions with conversation history
|
|
16
|
+
- File and image upload support
|
|
17
|
+
- Gem (system prompt) management — create, update, delete, fetch
|
|
18
|
+
- Auto cookie refresh to keep sessions alive
|
|
19
|
+
- TypeScript type declarations included
|
|
20
|
+
- Proxy support
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install gemini-reverse
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Authentication
|
|
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.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
const { GeminiClient } = require('gemini-core');
|
|
49
|
+
|
|
50
|
+
const client = new GeminiClient({
|
|
51
|
+
secure_1psid: 'YOUR_SECURE_1PSID',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await client.init();
|
|
55
|
+
|
|
56
|
+
const chat = client.startChat();
|
|
57
|
+
const response = await chat.sendMessage({ prompt: 'Hello, Gemini!' });
|
|
58
|
+
|
|
59
|
+
console.log(response.text);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
### Initialize Client
|
|
67
|
+
|
|
68
|
+
```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
|
+
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
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Generate Content (single turn)
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
const response = await client.generateContent({ prompt: 'What is the capital of France?' });
|
|
88
|
+
console.log(response.text);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Streaming
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
for await (const chunk of client.generateContentStream({ prompt: 'Tell me a long story.' })) {
|
|
95
|
+
process.stdout.write(chunk.text_delta);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Chat Session
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
const chat = client.startChat({ model: 'gemini-3.1-pro' });
|
|
103
|
+
|
|
104
|
+
const res1 = await chat.sendMessage({ prompt: 'My name is Alice.' });
|
|
105
|
+
console.log(res1.text);
|
|
106
|
+
|
|
107
|
+
const res2 = await chat.sendMessage({ prompt: 'What is my name?' });
|
|
108
|
+
console.log(res2.text); // remembers context
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Streaming in Chat
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
const chat = client.startChat({ model: 'gemini-3.0-flash' });
|
|
115
|
+
|
|
116
|
+
for await (const chunk of chat.sendMessageStream({ prompt: 'Explain quantum computing.' })) {
|
|
117
|
+
process.stdout.write(chunk.text_delta);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Temporary Chat (no history saved)
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
const chat = client.startChat();
|
|
125
|
+
const response = await chat.sendMessage({ prompt: 'This will not appear in history.', temporary: true });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Send with Files
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const chat = client.startChat();
|
|
132
|
+
const response = await chat.sendMessage({
|
|
133
|
+
prompt: 'Describe this image.',
|
|
134
|
+
files: ['./photo.jpg'],
|
|
135
|
+
});
|
|
136
|
+
console.log(response.text);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Multiple Candidates
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
const chat = client.startChat();
|
|
143
|
+
const response = await chat.sendMessage({ prompt: 'Give me a poem.' });
|
|
144
|
+
|
|
145
|
+
// list all candidates
|
|
146
|
+
response.candidates.forEach((c, i) => console.log(`[${i}] ${c.text}`));
|
|
147
|
+
|
|
148
|
+
// choose a specific candidate to continue the conversation
|
|
149
|
+
chat.chooseCandidate(1);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Models
|
|
153
|
+
|
|
154
|
+
```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
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Available models:**
|
|
172
|
+
|
|
173
|
+
| String | Constant |
|
|
174
|
+
|---|---|
|
|
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` |
|
|
179
|
+
|
|
180
|
+
### Images
|
|
181
|
+
|
|
182
|
+
Responses may include web images or AI-generated images.
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
const response = await chat.sendMessage({ prompt: 'Send me an image of a cat.' });
|
|
186
|
+
|
|
187
|
+
for (const img of response.images) {
|
|
188
|
+
console.log(img.url, img.title, img.alt);
|
|
189
|
+
await img.save({ path: './downloads', verbose: true });
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Read Chat History
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
const turns = await client.readChat('c_YOUR_CHAT_ID');
|
|
197
|
+
|
|
198
|
+
for (const turn of turns) {
|
|
199
|
+
console.log('User:', turn.user_prompt);
|
|
200
|
+
console.log('Gemini:', turn.assistant_response);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Delete Chat
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
await client.deleteChat('c_YOUR_CHAT_ID');
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Gems
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
// fetch all gems
|
|
214
|
+
const gems = await client.fetchGems();
|
|
215
|
+
|
|
216
|
+
// get by name
|
|
217
|
+
const gem = gems.get({ name: 'Coding partner' });
|
|
218
|
+
|
|
219
|
+
// filter user-created gems
|
|
220
|
+
const myGems = gems.filter({ predefined: false });
|
|
221
|
+
|
|
222
|
+
// use a gem in chat
|
|
223
|
+
const chat = client.startChat({ gem: gem });
|
|
224
|
+
|
|
225
|
+
// create a gem
|
|
226
|
+
const newGem = await client.createGem({
|
|
227
|
+
name: 'My Assistant',
|
|
228
|
+
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
|
+
});
|
|
238
|
+
|
|
239
|
+
// delete a gem
|
|
240
|
+
await client.deleteGem(newGem);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Close Client
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
await client.close();
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
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();
|
|
260
|
+
|
|
261
|
+
const chat: ChatSession = client.startChat({ model: 'gemini-3.1-pro' });
|
|
262
|
+
const response: ModelOutput = await chat.sendMessage({ prompt: 'Hello!' });
|
|
263
|
+
|
|
264
|
+
console.log(response.text);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Project Structure
|
|
270
|
+
|
|
271
|
+
```
|
|
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
|
|
278
|
+
├── types/
|
|
279
|
+
│ ├── candidate.js
|
|
280
|
+
│ ├── conversation.js
|
|
281
|
+
│ ├── gem.js
|
|
282
|
+
│ ├── grpc.js
|
|
283
|
+
│ ├── image.js
|
|
284
|
+
│ └── modeloutput.js
|
|
285
|
+
├── utils/
|
|
286
|
+
│ ├── accessToken.js
|
|
287
|
+
│ ├── parsing.js
|
|
288
|
+
│ ├── rotate.js
|
|
289
|
+
│ └── upload.js
|
|
290
|
+
└── components/
|
|
291
|
+
├── 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
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Credits
|
|
332
|
+
|
|
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.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Disclaimer
|
|
338
|
+
|
|
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.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## License
|
|
344
|
+
|
|
345
|
+
MIT
|