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 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
+ ![Banner](https://nc-cdn.oss-accelerate.aliyuncs.com/nx/a772a980daeb.png)
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