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.
Files changed (36) hide show
  1. package/README.md +244 -10
  2. package/dist/auth/account-store.d.ts +36 -0
  3. package/dist/auth/account-store.js +366 -0
  4. package/dist/auth/account-store.js.map +1 -0
  5. package/dist/auth/credential-store.d.ts +2 -0
  6. package/dist/auth/credential-store.js +33 -1
  7. package/dist/auth/credential-store.js.map +1 -1
  8. package/dist/auth/oauth-flow.d.ts +0 -2
  9. package/dist/auth/oauth-flow.js +122 -15
  10. package/dist/auth/oauth-flow.js.map +1 -1
  11. package/dist/auth/oauth-service.d.ts +12 -3
  12. package/dist/auth/oauth-service.js +90 -29
  13. package/dist/auth/oauth-service.js.map +1 -1
  14. package/dist/cli.js +336 -14
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/auth-login.d.ts +16 -0
  17. package/dist/commands/auth-login.js +114 -0
  18. package/dist/commands/auth-login.js.map +1 -0
  19. package/dist/commands/auth-logout.d.ts +19 -0
  20. package/dist/commands/auth-logout.js +178 -0
  21. package/dist/commands/auth-logout.js.map +1 -0
  22. package/dist/config/env.d.ts +1 -0
  23. package/dist/config/env.js +3 -1
  24. package/dist/config/env.js.map +1 -1
  25. package/dist/gemini/code-assist-client.d.ts +15 -1
  26. package/dist/gemini/code-assist-client.js +101 -37
  27. package/dist/gemini/code-assist-client.js.map +1 -1
  28. package/dist/gemini/errors.d.ts +8 -0
  29. package/dist/gemini/errors.js +29 -0
  30. package/dist/gemini/errors.js.map +1 -0
  31. package/dist/server/app.js +8 -3
  32. package/dist/server/app.js.map +1 -1
  33. package/dist/server/background-service.d.ts +46 -0
  34. package/dist/server/background-service.js +332 -0
  35. package/dist/server/background-service.js.map +1 -0
  36. 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: `8080`
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` required for fresh OAuth login
43
- - `GEMINI_CLI_OAUTH_CLIENT_SECRET` required for fresh OAuth login
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 and listens on a local callback URL
51
- 3. If browser callback is not available, paste either authorization code or full callback URL
52
- 4. If OAuth client env values are not set but `~/.gemini/oauth_creds.json` exists, stored credentials are reused
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
- ## API
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
- Example:
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:8080/v1/chat/completions \
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:8080/v1/models
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 {};