geminimock 0.1.2 → 0.1.4
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 +244 -10
- package/dist/auth/account-store.d.ts +36 -0
- package/dist/auth/account-store.js +366 -0
- package/dist/auth/account-store.js.map +1 -0
- package/dist/auth/credential-store.d.ts +2 -0
- package/dist/auth/credential-store.js +33 -1
- package/dist/auth/credential-store.js.map +1 -1
- package/dist/auth/oauth-flow.d.ts +0 -2
- package/dist/auth/oauth-flow.js +122 -15
- package/dist/auth/oauth-flow.js.map +1 -1
- package/dist/auth/oauth-service.d.ts +12 -3
- package/dist/auth/oauth-service.js +90 -29
- package/dist/auth/oauth-service.js.map +1 -1
- package/dist/cli.js +336 -14
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth-login.d.ts +16 -0
- package/dist/commands/auth-login.js +114 -0
- package/dist/commands/auth-login.js.map +1 -0
- package/dist/commands/auth-logout.d.ts +19 -0
- package/dist/commands/auth-logout.js +178 -0
- package/dist/commands/auth-logout.js.map +1 -0
- package/dist/config/env.d.ts +1 -0
- package/dist/config/env.js +3 -1
- package/dist/config/env.js.map +1 -1
- package/dist/gemini/code-assist-client.d.ts +15 -1
- package/dist/gemini/code-assist-client.js +101 -37
- package/dist/gemini/code-assist-client.js.map +1 -1
- package/dist/gemini/errors.d.ts +8 -0
- package/dist/gemini/errors.js +29 -0
- package/dist/gemini/errors.js.map +1 -0
- package/dist/server/app.js +8 -3
- package/dist/server/app.js.map +1 -1
- package/dist/server/background-service.d.ts +46 -0
- package/dist/server/background-service.js +332 -0
- package/dist/server/background-service.js.map +1 -0
- package/package.json +14 -1
package/README.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
OpenAI-compatible chat API server backed by Gemini Code Assist OAuth.
|
|
4
4
|
|
|
5
|
+
## Terms of Service Warning
|
|
6
|
+
|
|
7
|
+
> [!CAUTION]
|
|
8
|
+
> Using this project may violate Google's Terms of Service. Some users have reported account suspension or shadow restrictions.
|
|
9
|
+
>
|
|
10
|
+
> High-risk scenarios:
|
|
11
|
+
> - Fresh Google accounts are more likely to be flagged
|
|
12
|
+
> - Newly created accounts with Pro/Ultra subscriptions may be reviewed or restricted quickly
|
|
13
|
+
>
|
|
14
|
+
> By using this project, you acknowledge:
|
|
15
|
+
> - This is an unofficial tool and is not endorsed by Google
|
|
16
|
+
> - Your account access may be limited, suspended, or permanently banned
|
|
17
|
+
> - You accept full responsibility for any risk or loss resulting from use
|
|
18
|
+
>
|
|
19
|
+
> Recommendation:
|
|
20
|
+
> - Prefer an established account that is not critical to your primary services
|
|
21
|
+
> - Avoid creating new accounts specifically for this workflow
|
|
22
|
+
|
|
5
23
|
## Install
|
|
6
24
|
|
|
7
25
|
- global: `npm i -g geminimock`
|
|
@@ -9,8 +27,15 @@ OpenAI-compatible chat API server backed by Gemini Code Assist OAuth.
|
|
|
9
27
|
|
|
10
28
|
Installed CLI command:
|
|
11
29
|
|
|
30
|
+
- `geminimock server start`
|
|
31
|
+
- `geminimock server stop`
|
|
32
|
+
- `geminimock server status`
|
|
12
33
|
- `geminimock auth login`
|
|
13
34
|
- `geminimock auth logout`
|
|
35
|
+
- `geminimock auth logout --all`
|
|
36
|
+
- `geminimock auth accounts list`
|
|
37
|
+
- `geminimock auth accounts use <id|email>`
|
|
38
|
+
- `geminimock auth accounts remove <id|email>`
|
|
14
39
|
- `geminimock models list`
|
|
15
40
|
- `geminimock update`
|
|
16
41
|
- `geminimock serve`
|
|
@@ -19,7 +44,12 @@ Installed CLI command:
|
|
|
19
44
|
|
|
20
45
|
- `bun run auth:login`
|
|
21
46
|
- `bun run auth:logout`
|
|
47
|
+
- `bun run auth:logout:all`
|
|
48
|
+
- `bun run auth:accounts:list`
|
|
22
49
|
- `bun run models:list`
|
|
50
|
+
- `bun run server:start`
|
|
51
|
+
- `bun run server:stop`
|
|
52
|
+
- `bun run server:status`
|
|
23
53
|
- `bun run self:update`
|
|
24
54
|
- `bun run dev`
|
|
25
55
|
- `bun run start`
|
|
@@ -33,39 +63,243 @@ Installed CLI command:
|
|
|
33
63
|
## Environment
|
|
34
64
|
|
|
35
65
|
- `GEMINI_CLI_API_HOST` default: `127.0.0.1`
|
|
36
|
-
- `GEMINI_CLI_API_PORT` default: `
|
|
66
|
+
- `GEMINI_CLI_API_PORT` default: `43173`
|
|
37
67
|
- `GEMINI_CLI_MODEL` default: `gemini-2.5-pro`
|
|
38
68
|
- `CODE_ASSIST_ENDPOINT` default: `https://cloudcode-pa.googleapis.com`
|
|
39
69
|
- `CODE_ASSIST_API_VERSION` default: `v1internal`
|
|
70
|
+
- `GEMINI_CLI_API_ACCOUNTS_PATH` default: `~/.geminimock/accounts.json`
|
|
40
71
|
- `GEMINI_CLI_API_OAUTH_PATH` default: `~/.geminimock/oauth_creds.json`
|
|
41
72
|
- `GEMINI_CLI_OAUTH_FALLBACK_PATH` default: `~/.gemini/oauth_creds.json`
|
|
42
|
-
- `GEMINI_CLI_OAUTH_CLIENT_ID`
|
|
43
|
-
- `GEMINI_CLI_OAUTH_CLIENT_SECRET`
|
|
73
|
+
- `GEMINI_CLI_OAUTH_CLIENT_ID` optional override
|
|
74
|
+
- `GEMINI_CLI_OAUTH_CLIENT_SECRET` optional
|
|
75
|
+
- `GEMINI_CLI_OAUTH_SOURCE_PATH` optional explicit path to Gemini CLI `oauth2.js` for auto-discovery
|
|
76
|
+
- `GEMINI_CLI_OAUTH_AUTO_DISCOVERY` default: `1` (`0` disables Gemini CLI client auto-discovery)
|
|
77
|
+
- `GEMINI_CLI_BIN_PATH` optional explicit path to `gemini` executable
|
|
44
78
|
- `GOOGLE_CLOUD_PROJECT` optional
|
|
45
79
|
- `GOOGLE_CLOUD_PROJECT_ID` optional
|
|
46
80
|
|
|
47
81
|
## OAuth Login
|
|
48
82
|
|
|
49
83
|
1. Run `bun run auth:login`
|
|
50
|
-
2. Browser opens automatically
|
|
51
|
-
3. If
|
|
52
|
-
4.
|
|
84
|
+
2. Browser OAuth opens automatically with local callback and account selection prompt
|
|
85
|
+
3. If callback cannot complete, paste the authorization code or callback URL in terminal
|
|
86
|
+
4. OAuth client config is resolved in this order: explicit env vars, installed Gemini CLI auto-discovery
|
|
87
|
+
5. `auth login` uses keyboard TUI (`Up/Down`, `Enter`, `Q/Esc`) to start login, repeat login, or finish
|
|
88
|
+
6. `Login Completed` screen shows `Last login account: <email>`
|
|
89
|
+
7. `auth logout` uses keyboard TUI (`Up/Down`, `Enter`, `Q/Esc`) to choose which account to logout
|
|
90
|
+
8. In the logout list, `[*]` means the current active account
|
|
91
|
+
9. Choosing `Logout ALL accounts` opens a second TUI confirm selector (`No` / `Yes`)
|
|
92
|
+
10. `auth logout --all` clears all registered accounts and fallback Gemini auth state
|
|
93
|
+
|
|
94
|
+
## Multi-Account Rotation
|
|
95
|
+
|
|
96
|
+
- accounts are stored in `~/.geminimock/accounts.json`
|
|
97
|
+
- active account is used by default
|
|
98
|
+
- automatic rotation occurs on API failures indicating rate/capacity/auth blocking:
|
|
99
|
+
- HTTP `429`, `503`, `401`, `403`
|
|
100
|
+
- or error body containing quota/capacity/resource-exhausted indicators
|
|
101
|
+
- current account is put on temporary cooldown and next available account is selected
|
|
102
|
+
- project cache is invalidated automatically when active account changes (manual switch or auto-rotation), so server restart is not required
|
|
103
|
+
- use `geminimock auth accounts list` to inspect active account and IDs
|
|
104
|
+
- use `geminimock auth accounts use <id|email>` to pin a specific account manually
|
|
105
|
+
|
|
106
|
+
## Service Usage Guide
|
|
107
|
+
|
|
108
|
+
### 1) Start service
|
|
109
|
+
|
|
110
|
+
Run OAuth login first:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
geminimock auth login
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Start in background:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
geminimock server start
|
|
120
|
+
geminimock server status
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- default URL is `http://127.0.0.1:43173`
|
|
124
|
+
- if `43173` is in use, an available port is selected automatically
|
|
125
|
+
- always check actual URL with `geminimock server status`
|
|
126
|
+
- log file: `~/.geminimock/server.log`
|
|
127
|
+
|
|
128
|
+
Run in foreground:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
geminimock serve
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Quick health check:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
curl -sS http://127.0.0.1:43173/health
|
|
138
|
+
```
|
|
53
139
|
|
|
54
|
-
|
|
140
|
+
### 2) API endpoints
|
|
55
141
|
|
|
56
142
|
- `GET /health`
|
|
57
143
|
- `GET /v1/auth/status`
|
|
58
144
|
- `GET /v1/models`
|
|
59
145
|
- `POST /v1/chat/completions`
|
|
60
146
|
|
|
61
|
-
|
|
147
|
+
Check auth status:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
curl -sS http://127.0.0.1:43173/v1/auth/status
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Response:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{"authenticated":true}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
List available models from current account/project:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
curl -sS http://127.0.0.1:43173/v1/models
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Response format (OpenAI-style model list):
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"object": "list",
|
|
170
|
+
"data": [
|
|
171
|
+
{
|
|
172
|
+
"id": "gemini-2.5-flash",
|
|
173
|
+
"object": "model",
|
|
174
|
+
"created": 0,
|
|
175
|
+
"owned_by": "google-code-assist"
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 3) Chat completion call pattern
|
|
182
|
+
|
|
183
|
+
Basic request:
|
|
62
184
|
|
|
63
185
|
```bash
|
|
64
|
-
curl -sS -X POST http://127.0.0.1:
|
|
186
|
+
curl -sS -X POST http://127.0.0.1:43173/v1/chat/completions \
|
|
65
187
|
-H 'content-type: application/json' \
|
|
66
188
|
-d '{"model":"gemini-2.5-flash","messages":[{"role":"user","content":"Hello"}]}'
|
|
67
189
|
```
|
|
68
190
|
|
|
191
|
+
Basic response format (OpenAI-style):
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"id": "chatcmpl-...",
|
|
196
|
+
"object": "chat.completion",
|
|
197
|
+
"created": 1772175296,
|
|
198
|
+
"model": "gemini-2.5-flash",
|
|
199
|
+
"choices": [
|
|
200
|
+
{
|
|
201
|
+
"index": 0,
|
|
202
|
+
"finish_reason": "STOP",
|
|
203
|
+
"message": {
|
|
204
|
+
"role": "assistant",
|
|
205
|
+
"content": "Hello! How can I help you today?"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
"usage": {
|
|
210
|
+
"prompt_tokens": 1,
|
|
211
|
+
"completion_tokens": 9,
|
|
212
|
+
"total_tokens": 31
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Streaming request (`stream: true`, SSE):
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
curl -N -sS -X POST http://127.0.0.1:43173/v1/chat/completions \
|
|
221
|
+
-H 'content-type: application/json' \
|
|
222
|
+
-d '{"model":"gemini-2.5-flash","stream":true,"messages":[{"role":"user","content":"Hello"}]}'
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Streaming response format:
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant","content":"Hel"}}]}
|
|
229
|
+
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":"lo"}}]}
|
|
230
|
+
data: {"id":"...","object":"chat.completion.chunk","choices":[{"finish_reason":"stop","delta":{}}]}
|
|
231
|
+
data: [DONE]
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 4) How answers are generated
|
|
235
|
+
|
|
236
|
+
- API is stateless per request
|
|
237
|
+
- server does not keep conversation memory between calls
|
|
238
|
+
- to continue a conversation, send full history in `messages` each call
|
|
239
|
+
- response text is mapped to `choices[0].message.content`
|
|
240
|
+
- token usage is mapped to `usage.prompt_tokens`, `usage.completion_tokens`, `usage.total_tokens`
|
|
241
|
+
|
|
242
|
+
Model resolution behavior:
|
|
243
|
+
|
|
244
|
+
- if requested model is unavailable, alias mapping may be applied
|
|
245
|
+
- example: `gemini-3-flash` -> `gemini-3-flash-preview` (when available)
|
|
246
|
+
- model list normalizes `_vertex` suffix
|
|
247
|
+
|
|
248
|
+
### 5) System prompt and role mapping
|
|
249
|
+
|
|
250
|
+
System prompt usage example:
|
|
251
|
+
|
|
69
252
|
```bash
|
|
70
|
-
curl -sS http://127.0.0.1:
|
|
253
|
+
curl -sS -X POST http://127.0.0.1:43173/v1/chat/completions \
|
|
254
|
+
-H 'content-type: application/json' \
|
|
255
|
+
-d '{"model":"gemini-2.5-flash","messages":[{"role":"system","content":"You are concise."},{"role":"user","content":"Summarize OAuth in one sentence."}]}'
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Role mapping rules:
|
|
259
|
+
|
|
260
|
+
- `system` messages are merged and sent as Gemini `systemInstruction`
|
|
261
|
+
- `assistant` maps to Gemini `model`
|
|
262
|
+
- `user` maps to Gemini `user`
|
|
263
|
+
- `developer` and `tool` are accepted but mapped as `user`
|
|
264
|
+
|
|
265
|
+
Important:
|
|
266
|
+
|
|
267
|
+
- include at least one non-`system` message (`user` or `assistant`)
|
|
268
|
+
- sending only `system` may fail with `400 INVALID_ARGUMENT` from upstream
|
|
269
|
+
|
|
270
|
+
### 6) Error response style
|
|
271
|
+
|
|
272
|
+
Validation/route errors:
|
|
273
|
+
|
|
274
|
+
```json
|
|
275
|
+
{"error":{"message":"..."}}
|
|
71
276
|
```
|
|
277
|
+
|
|
278
|
+
Common upstream errors:
|
|
279
|
+
|
|
280
|
+
- `403 PERMISSION_DENIED`: active account lacks permission for resolved project/model
|
|
281
|
+
- `404 NOT_FOUND`: requested model or entity does not exist in current project/account
|
|
282
|
+
- `429 RESOURCE_EXHAUSTED`: quota/capacity/rate limit
|
|
283
|
+
|
|
284
|
+
Troubleshooting steps:
|
|
285
|
+
|
|
286
|
+
1. Check current auth: `curl -sS http://127.0.0.1:43173/v1/auth/status`
|
|
287
|
+
2. Check available models: `geminimock models list`
|
|
288
|
+
3. Check active account and switch if needed:
|
|
289
|
+
- `geminimock auth accounts list`
|
|
290
|
+
- `geminimock auth accounts use <id|email>`
|
|
291
|
+
|
|
292
|
+
## GitHub Release Automation
|
|
293
|
+
|
|
294
|
+
- On push to `main`, GitHub Actions reads `package.json` version and creates a release tag `v<version>` if it does not exist.
|
|
295
|
+
- Release notes are generated automatically from the merged changes.
|
|
296
|
+
- On each push to `main`, `npm-publish.yml` publishes to npm using Trusted Publishing (OIDC) if that version is not already published.
|
|
297
|
+
- To publish a new npm release: bump `package.json` version, commit, and push to `main`.
|
|
298
|
+
|
|
299
|
+
Trusted Publisher setup values for npm:
|
|
300
|
+
|
|
301
|
+
- Publisher: `GitHub Actions`
|
|
302
|
+
- Organization or user: `yldst-dev`
|
|
303
|
+
- Repository: `GeminiMock`
|
|
304
|
+
- Workflow filename: `npm-publish.yml`
|
|
305
|
+
- Environment name: leave empty
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { StoredCredentials } from "./credential-store.js";
|
|
3
|
+
declare const accountSchema: z.ZodObject<{
|
|
4
|
+
id: z.ZodString;
|
|
5
|
+
email: z.ZodOptional<z.ZodString>;
|
|
6
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
7
|
+
created_at: z.ZodNumber;
|
|
8
|
+
updated_at: z.ZodNumber;
|
|
9
|
+
last_used_at: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
cooldown_until: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
last_error: z.ZodOptional<z.ZodString>;
|
|
12
|
+
credentials: z.ZodObject<{
|
|
13
|
+
access_token: z.ZodString;
|
|
14
|
+
refresh_token: z.ZodOptional<z.ZodString>;
|
|
15
|
+
expiry_date: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
token_type: z.ZodOptional<z.ZodString>;
|
|
17
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export type StoredAccount = z.infer<typeof accountSchema>;
|
|
21
|
+
export type AccountStore = ReturnType<typeof createAccountStore>;
|
|
22
|
+
export declare function createAccountStore(accountsPath: string, legacyOAuthPath?: string, fallbackOAuthPath?: string): {
|
|
23
|
+
accountsPath: string;
|
|
24
|
+
listAccounts(): Promise<StoredAccount[]>;
|
|
25
|
+
getActiveAccount(): Promise<StoredAccount | null>;
|
|
26
|
+
getAccountCount(): Promise<number>;
|
|
27
|
+
addOrUpdateAccount(credentials: StoredCredentials, email?: string): Promise<StoredAccount>;
|
|
28
|
+
setActiveAccount(idOrEmail: string): Promise<StoredAccount>;
|
|
29
|
+
removeAccount(idOrEmail: string): Promise<boolean>;
|
|
30
|
+
logoutActive(): Promise<StoredAccount | null>;
|
|
31
|
+
markActiveUsed(): Promise<void>;
|
|
32
|
+
updateActiveCredentials(credentials: StoredCredentials, email?: string): Promise<StoredAccount>;
|
|
33
|
+
rotateActiveAccount(reason: string, cooldownMs: number): Promise<StoredAccount | null>;
|
|
34
|
+
clearAll(): Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
export {};
|