camo-gemini 0.1.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.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/client/camofox-client.d.ts +21 -0
  4. package/dist/client/camofox-client.d.ts.map +1 -0
  5. package/dist/client/camofox-client.js +260 -0
  6. package/dist/client/camofox-client.js.map +1 -0
  7. package/dist/config.d.ts +3 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +94 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/core/browser-js.d.ts +27 -0
  12. package/dist/core/browser-js.d.ts.map +1 -0
  13. package/dist/core/browser-js.js +172 -0
  14. package/dist/core/browser-js.js.map +1 -0
  15. package/dist/core/constants.d.ts +78 -0
  16. package/dist/core/constants.d.ts.map +1 -0
  17. package/dist/core/constants.js +115 -0
  18. package/dist/core/constants.js.map +1 -0
  19. package/dist/core/error-messages.d.ts +8 -0
  20. package/dist/core/error-messages.d.ts.map +1 -0
  21. package/dist/core/error-messages.js +121 -0
  22. package/dist/core/error-messages.js.map +1 -0
  23. package/dist/core/failover.d.ts +21 -0
  24. package/dist/core/failover.d.ts.map +1 -0
  25. package/dist/core/failover.js +47 -0
  26. package/dist/core/failover.js.map +1 -0
  27. package/dist/core/logger.d.ts +13 -0
  28. package/dist/core/logger.d.ts.map +1 -0
  29. package/dist/core/logger.js +37 -0
  30. package/dist/core/logger.js.map +1 -0
  31. package/dist/core/request-builder.d.ts +20 -0
  32. package/dist/core/request-builder.d.ts.map +1 -0
  33. package/dist/core/request-builder.js +210 -0
  34. package/dist/core/request-builder.js.map +1 -0
  35. package/dist/core/response-parser.d.ts +12 -0
  36. package/dist/core/response-parser.d.ts.map +1 -0
  37. package/dist/core/response-parser.js +221 -0
  38. package/dist/core/response-parser.js.map +1 -0
  39. package/dist/core/retry.d.ts +10 -0
  40. package/dist/core/retry.d.ts.map +1 -0
  41. package/dist/core/retry.js +132 -0
  42. package/dist/core/retry.js.map +1 -0
  43. package/dist/core/stream-parser.d.ts +9 -0
  44. package/dist/core/stream-parser.d.ts.map +1 -0
  45. package/dist/core/stream-parser.js +69 -0
  46. package/dist/core/stream-parser.js.map +1 -0
  47. package/dist/core/token-manager.d.ts +9 -0
  48. package/dist/core/token-manager.d.ts.map +1 -0
  49. package/dist/core/token-manager.js +64 -0
  50. package/dist/core/token-manager.js.map +1 -0
  51. package/dist/core/utils.d.ts +2 -0
  52. package/dist/core/utils.d.ts.map +1 -0
  53. package/dist/core/utils.js +15 -0
  54. package/dist/core/utils.js.map +1 -0
  55. package/dist/dashboard/server.d.ts +31 -0
  56. package/dist/dashboard/server.d.ts.map +1 -0
  57. package/dist/dashboard/server.js +190 -0
  58. package/dist/dashboard/server.js.map +1 -0
  59. package/dist/errors.d.ts +32 -0
  60. package/dist/errors.d.ts.map +1 -0
  61. package/dist/errors.js +59 -0
  62. package/dist/errors.js.map +1 -0
  63. package/dist/index.d.ts +3 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +36 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/server.d.ts +31 -0
  68. package/dist/server.d.ts.map +1 -0
  69. package/dist/server.js +54 -0
  70. package/dist/server.js.map +1 -0
  71. package/dist/services/account.d.ts +16 -0
  72. package/dist/services/account.d.ts.map +1 -0
  73. package/dist/services/account.js +55 -0
  74. package/dist/services/account.js.map +1 -0
  75. package/dist/services/auth.d.ts +39 -0
  76. package/dist/services/auth.d.ts.map +1 -0
  77. package/dist/services/auth.js +285 -0
  78. package/dist/services/auth.js.map +1 -0
  79. package/dist/services/chat.d.ts +18 -0
  80. package/dist/services/chat.d.ts.map +1 -0
  81. package/dist/services/chat.js +151 -0
  82. package/dist/services/chat.js.map +1 -0
  83. package/dist/services/cookie-rotation.d.ts +25 -0
  84. package/dist/services/cookie-rotation.d.ts.map +1 -0
  85. package/dist/services/cookie-rotation.js +138 -0
  86. package/dist/services/cookie-rotation.js.map +1 -0
  87. package/dist/services/gems.d.ts +33 -0
  88. package/dist/services/gems.d.ts.map +1 -0
  89. package/dist/services/gems.js +202 -0
  90. package/dist/services/gems.js.map +1 -0
  91. package/dist/services/generate.d.ts +27 -0
  92. package/dist/services/generate.d.ts.map +1 -0
  93. package/dist/services/generate.js +149 -0
  94. package/dist/services/generate.js.map +1 -0
  95. package/dist/services/health.d.ts +20 -0
  96. package/dist/services/health.d.ts.map +1 -0
  97. package/dist/services/health.js +77 -0
  98. package/dist/services/health.js.map +1 -0
  99. package/dist/services/upload.d.ts +17 -0
  100. package/dist/services/upload.d.ts.map +1 -0
  101. package/dist/services/upload.js +120 -0
  102. package/dist/services/upload.js.map +1 -0
  103. package/dist/setup.d.ts +7 -0
  104. package/dist/setup.d.ts.map +1 -0
  105. package/dist/setup.js +165 -0
  106. package/dist/setup.js.map +1 -0
  107. package/dist/state.d.ts +57 -0
  108. package/dist/state.d.ts.map +1 -0
  109. package/dist/state.js +260 -0
  110. package/dist/state.js.map +1 -0
  111. package/dist/tools/account.d.ts +4 -0
  112. package/dist/tools/account.d.ts.map +1 -0
  113. package/dist/tools/account.js +29 -0
  114. package/dist/tools/account.js.map +1 -0
  115. package/dist/tools/auth.d.ts +4 -0
  116. package/dist/tools/auth.d.ts.map +1 -0
  117. package/dist/tools/auth.js +56 -0
  118. package/dist/tools/auth.js.map +1 -0
  119. package/dist/tools/chat.d.ts +4 -0
  120. package/dist/tools/chat.d.ts.map +1 -0
  121. package/dist/tools/chat.js +101 -0
  122. package/dist/tools/chat.js.map +1 -0
  123. package/dist/tools/gems.d.ts +4 -0
  124. package/dist/tools/gems.d.ts.map +1 -0
  125. package/dist/tools/gems.js +93 -0
  126. package/dist/tools/gems.js.map +1 -0
  127. package/dist/tools/health.d.ts +4 -0
  128. package/dist/tools/health.d.ts.map +1 -0
  129. package/dist/tools/health.js +13 -0
  130. package/dist/tools/health.js.map +1 -0
  131. package/dist/tools/media.d.ts +4 -0
  132. package/dist/tools/media.d.ts.map +1 -0
  133. package/dist/tools/media.js +65 -0
  134. package/dist/tools/media.js.map +1 -0
  135. package/dist/types.d.ts +292 -0
  136. package/dist/types.d.ts.map +1 -0
  137. package/dist/types.js +2 -0
  138. package/dist/types.js.map +1 -0
  139. package/package.json +66 -0
@@ -0,0 +1,149 @@
1
+ import { buildGenerateExpression } from "../core/browser-js.js";
2
+ import { buildBatchExpression } from "../core/browser-js.js";
3
+ import { GrpcId } from "../core/constants.js";
4
+ import { RequestBuilder } from "../core/request-builder.js";
5
+ import { ResponseParser } from "../core/response-parser.js";
6
+ import { StreamParser } from "../core/stream-parser.js";
7
+ import { withFailover } from "../core/failover.js";
8
+ import { withRetry } from "../core/retry.js";
9
+ export class GenerateService {
10
+ deps;
11
+ streamParser;
12
+ responseParser;
13
+ requestBuilder;
14
+ constructor(deps) {
15
+ this.deps = deps;
16
+ this.streamParser = new StreamParser();
17
+ this.responseParser = new ResponseParser();
18
+ this.requestBuilder = new RequestBuilder();
19
+ }
20
+ async generate(options) {
21
+ const accountIndex = this.resolveAccountIndex(options.accountIndex);
22
+ if (this.deps.state.getAllAccounts().length <= 1) {
23
+ return this.generateForAccount(options, accountIndex);
24
+ }
25
+ const failoverResult = await withFailover(this.deps.state, { accountIndex }, async (resolvedAccountIndex) => this.generateForAccount({ ...options, accountIndex: resolvedAccountIndex }, resolvedAccountIndex));
26
+ if (this.deps.state.activeAccountIndex !== failoverResult.usedAccountIndex) {
27
+ this.deps.state.setActiveAccount(failoverResult.usedAccountIndex);
28
+ }
29
+ return failoverResult.result;
30
+ }
31
+ async generateForAccount(options, accountIndex) {
32
+ return withRetry(async () => {
33
+ const session = await this.deps.auth.ensureSession(accountIndex);
34
+ const tokens = await this.deps.auth.getTokens(accountIndex);
35
+ const bardPayload = this.requestBuilder.buildBardActivityPayload(tokens, accountIndex);
36
+ const generatePayload = options.usePro
37
+ ? this.requestBuilder.buildImageGeneratePayload(options.prompt, {
38
+ model: options.model,
39
+ accountIndex,
40
+ chatMetadata: options.chatMetadata,
41
+ gemId: options.gemId,
42
+ images: options.images,
43
+ usePro: options.usePro,
44
+ files: options.files
45
+ }, tokens, accountIndex)
46
+ : this.requestBuilder.buildGeneratePayload({
47
+ prompt: options.prompt,
48
+ model: options.model,
49
+ gemId: options.gemId,
50
+ images: options.images?.map((image) => ({ url: image.url }))
51
+ }, tokens, accountIndex, options.chatMetadata);
52
+ const expression = buildGenerateExpression({
53
+ url: generatePayload.url,
54
+ headers: generatePayload.headers,
55
+ body: generatePayload.body,
56
+ bardActivityUrl: bardPayload.url,
57
+ bardActivityHeaders: bardPayload.headers,
58
+ bardActivityBody: bardPayload.body
59
+ });
60
+ const evalResult = await this.deps.client.evaluateExtended(session.tabId, expression, session.userId, 120_000);
61
+ if (!evalResult.ok) {
62
+ const error = new Error(`Evaluate failed: ${evalResult.error ?? "unknown"}`);
63
+ if (evalResult.errorType) {
64
+ error.errorType = evalResult.errorType;
65
+ }
66
+ throw error;
67
+ }
68
+ const fetchResult = evalResult.result;
69
+ if (!fetchResult?.ok || typeof fetchResult.data !== "string") {
70
+ throw new Error(`Gemini fetch failed: ${fetchResult?.error ?? "no data"}`);
71
+ }
72
+ const frames = this.streamParser.extractFrames(fetchResult.data);
73
+ const parseResult = this.responseParser.parseGenerateResponse(frames);
74
+ if (!parseResult.ok) {
75
+ const error = new Error(parseResult.error.message);
76
+ error.code = parseResult.error.code;
77
+ error.parseErrorCode = parseResult.error.code;
78
+ throw error;
79
+ }
80
+ return {
81
+ output: parseResult.data,
82
+ rawFrameCount: frames.length,
83
+ conversationId: typeof parseResult.data.metadata[0] === "string" && parseResult.data.metadata[0]
84
+ ? parseResult.data.metadata[0]
85
+ : null,
86
+ generatedImages: parseResult.data.candidates.flatMap((candidate) => candidate.generatedImages.map((image) => ({
87
+ url: image.url,
88
+ alt: image.alt,
89
+ title: image.title,
90
+ description: image.alt
91
+ })))
92
+ };
93
+ }, { maxRetries: 5 });
94
+ }
95
+ async deleteConversation(accountIndex, conversationId) {
96
+ if (!conversationId) {
97
+ return;
98
+ }
99
+ const session = await this.deps.auth.ensureSession(accountIndex);
100
+ const tokens = await this.deps.auth.getTokens(accountIndex);
101
+ const payload = {
102
+ rpcId: GrpcId.DELETE_CHAT,
103
+ payload: JSON.stringify([conversationId]),
104
+ identifier: "generic"
105
+ };
106
+ await this.executeBatch(payload, tokens, session.tabId, session.userId, accountIndex);
107
+ }
108
+ async executeBatch(payload, tokens, tabId, userId, accountIndex) {
109
+ const batch = this.requestBuilder.buildBatchPayload([payload], tokens, accountIndex);
110
+ const expression = buildBatchExpression({
111
+ url: batch.url,
112
+ headers: batch.headers,
113
+ body: batch.body
114
+ });
115
+ const evalResult = await this.deps.client.evaluateExtended(tabId, expression, userId, 120_000);
116
+ if (!evalResult.ok) {
117
+ throw new Error(`Evaluate failed: ${evalResult.error ?? "unknown"}`);
118
+ }
119
+ const fetchResult = evalResult.result;
120
+ if (!fetchResult?.ok || typeof fetchResult.data !== "string") {
121
+ throw new Error(`Gem batch fetch failed: ${fetchResult?.error ?? "no data"}`);
122
+ }
123
+ const frames = this.streamParser.extractFrames(fetchResult.data);
124
+ const parsed = this.responseParser.parseBatchResponse(frames, payload.rpcId);
125
+ if (!parsed.ok) {
126
+ const error = new Error(parsed.error.message);
127
+ error.code = parsed.error.code;
128
+ throw error;
129
+ }
130
+ return parsed.data;
131
+ }
132
+ resolveAccountIndex(accountIndex) {
133
+ return accountIndex ?? this.deps.state.activeAccountIndex ?? 0;
134
+ }
135
+ resetReqId() {
136
+ this.requestBuilder.resetReqId();
137
+ }
138
+ getRequestBuilder() {
139
+ return this.requestBuilder;
140
+ }
141
+ async generateImage(prompt, options = {}) {
142
+ return this.generate({
143
+ prompt,
144
+ usePro: true,
145
+ ...options
146
+ });
147
+ }
148
+ }
149
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/services/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { CamofoxClient } from "../client/camofox-client.js";
2
+ import type { StateManager } from "../state.js";
3
+ import type { Config } from "../types.js";
4
+ import type { HealthCheckResult } from "../types.js";
5
+ export declare class HealthService {
6
+ private client;
7
+ private state;
8
+ private config;
9
+ private checkInterval;
10
+ constructor(client: CamofoxClient, state: StateManager, config: Config);
11
+ /** Start periodic health checking */
12
+ startPeriodicCheck(intervalMs?: number): void;
13
+ /** Stop periodic health checking */
14
+ stopPeriodicCheck(): void;
15
+ /** Check health of all accounts */
16
+ checkAllAccounts(): Promise<HealthCheckResult>;
17
+ /** Check if CamoFox browser is reachable */
18
+ private checkCamofox;
19
+ }
20
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/services/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE,qBAAa,aAAa;IAItB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,aAAa,CAA+B;gBAG1C,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM;IAGxB,qCAAqC;IACrC,kBAAkB,CAAC,UAAU,SAAS,GAAG,IAAI;IAU7C,oCAAoC;IACpC,iBAAiB,IAAI,IAAI;IAOzB,mCAAmC;IAC7B,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAwCpD,4CAA4C;YAC9B,YAAY;CAS3B"}
@@ -0,0 +1,77 @@
1
+ export class HealthService {
2
+ client;
3
+ state;
4
+ config;
5
+ checkInterval = null;
6
+ constructor(client, state, config) {
7
+ this.client = client;
8
+ this.state = state;
9
+ this.config = config;
10
+ }
11
+ /** Start periodic health checking */
12
+ startPeriodicCheck(intervalMs = 60_000) {
13
+ this.stopPeriodicCheck();
14
+ this.checkInterval = setInterval(() => {
15
+ this.checkAllAccounts().catch(() => { });
16
+ }, intervalMs);
17
+ if (typeof this.checkInterval === "object" && "unref" in this.checkInterval) {
18
+ this.checkInterval.unref();
19
+ }
20
+ }
21
+ /** Stop periodic health checking */
22
+ stopPeriodicCheck() {
23
+ if (this.checkInterval) {
24
+ clearInterval(this.checkInterval);
25
+ this.checkInterval = null;
26
+ }
27
+ }
28
+ /** Check health of all accounts */
29
+ async checkAllAccounts() {
30
+ const accounts = this.state.getAllAccounts();
31
+ const camofoxConnected = await this.checkCamofox();
32
+ const now = Date.now();
33
+ for (const account of accounts) {
34
+ if (account.health === "cooldown" && now >= account.cooldownUntil) {
35
+ this.state.setHealth(account.accountIndex, "degraded");
36
+ }
37
+ }
38
+ const refreshedAccounts = this.state.getAllAccounts();
39
+ const healthyCount = this.state.getHealthyAccounts().length;
40
+ const activeIndex = this.state.activeAccountIndex;
41
+ let overall = "offline";
42
+ if (healthyCount > 0) {
43
+ overall = healthyCount === refreshedAccounts.length ? "healthy" : "degraded";
44
+ }
45
+ else if (refreshedAccounts.some((account) => account.health === "cooldown")) {
46
+ overall = "cooldown";
47
+ }
48
+ return {
49
+ overall: refreshedAccounts.length === 0 ? "offline" : overall,
50
+ camofoxConnected,
51
+ accounts: refreshedAccounts.map((account) => ({
52
+ accountIndex: account.accountIndex,
53
+ health: account.health,
54
+ isLoggedIn: account.isLoggedIn,
55
+ isActive: account.accountIndex === activeIndex,
56
+ lastSuccessAt: account.lastSuccessAt || null,
57
+ lastErrorAt: account.lastErrorAt || null,
58
+ cooldownUntil: account.cooldownUntil || null
59
+ })),
60
+ activeAccountIndex: activeIndex,
61
+ totalAccounts: refreshedAccounts.length,
62
+ healthyAccounts: healthyCount
63
+ };
64
+ }
65
+ /** Check if CamoFox browser is reachable */
66
+ async checkCamofox() {
67
+ try {
68
+ const camofoxUrl = new URL(this.config.camofoxUrl);
69
+ const response = await fetch(`${camofoxUrl.origin}/health`);
70
+ return response.ok;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/services/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { CamofoxClient } from "../client/camofox-client.js";
2
+ import type { Config, UploadOptions, UploadResult } from "../types.js";
3
+ import type { AuthService } from "./auth.js";
4
+ export interface UploadServiceDeps {
5
+ client: CamofoxClient;
6
+ auth: AuthService;
7
+ config: Config;
8
+ }
9
+ export declare class UploadService {
10
+ private deps;
11
+ constructor(deps: UploadServiceDeps);
12
+ uploadFile(options: UploadOptions): Promise<UploadResult>;
13
+ private splitIntoChunks;
14
+ private detectMimeType;
15
+ private cleanupPartialUpload;
16
+ }
17
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/services/upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAgB7C,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,qBAAa,aAAa;IACZ,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;IAErC,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAoF/D,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,cAAc;YAUR,oBAAoB;CAUnC"}
@@ -0,0 +1,120 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { buildUploadChunkPushExpression, buildUploadFinalizeExpression } from "../core/browser-js.js";
3
+ import { MAX_UPLOAD_SIZE_BYTES, UPLOAD_URL } from "../core/constants.js";
4
+ import { withRetry } from "../core/retry.js";
5
+ import { AppError } from "../errors.js";
6
+ const BASE64_CHUNK_SIZE = 40 * 1024;
7
+ const MIME_TYPES_BY_EXTENSION = {
8
+ ".jpg": "image/jpeg",
9
+ ".jpeg": "image/jpeg",
10
+ ".png": "image/png",
11
+ ".gif": "image/gif",
12
+ ".webp": "image/webp",
13
+ ".pdf": "application/pdf",
14
+ ".txt": "text/plain",
15
+ ".mp4": "video/mp4",
16
+ ".mp3": "audio/mpeg"
17
+ };
18
+ export class UploadService {
19
+ deps;
20
+ constructor(deps) {
21
+ this.deps = deps;
22
+ }
23
+ async uploadFile(options) {
24
+ const estimatedSizeBytes = Math.ceil(options.fileBase64.length * (3 / 4));
25
+ if (estimatedSizeBytes > MAX_UPLOAD_SIZE_BYTES) {
26
+ throw new AppError("INTERNAL_ERROR", `Upload failed for ${options.filename}: file size ${estimatedSizeBytes} bytes exceeds max ${MAX_UPLOAD_SIZE_BYTES} bytes`);
27
+ }
28
+ const accountIndex = options.accountIndex ?? 0;
29
+ const mimeType = options.mimeType ?? this.detectMimeType(options.filename);
30
+ this.deps.auth.pauseRotation(accountIndex);
31
+ try {
32
+ return await withRetry(async () => {
33
+ const session = await this.deps.auth.ensureSession(accountIndex);
34
+ const tokens = await this.deps.auth.getTokens(accountIndex);
35
+ const uploadId = randomUUID();
36
+ const chunks = this.splitIntoChunks(options.fileBase64);
37
+ let chunkFailed = false;
38
+ try {
39
+ for (let index = 0; index < chunks.length; index += 1) {
40
+ const chunk = chunks[index] ?? "";
41
+ const expression = buildUploadChunkPushExpression(uploadId, chunk, index);
42
+ const chunkResult = await this.deps.client.evaluate(session.tabId, expression, session.userId);
43
+ if (!chunkResult.ok) {
44
+ chunkFailed = true;
45
+ throw new Error(`Chunk ${index} push failed: ${chunkResult.error ?? "unknown error"}`);
46
+ }
47
+ }
48
+ const finalizeExpression = buildUploadFinalizeExpression({
49
+ uploadId,
50
+ filename: options.filename,
51
+ mimeType,
52
+ uploadUrl: UPLOAD_URL,
53
+ snlm0e: tokens.snlm0e,
54
+ accountIndex
55
+ });
56
+ const finalizeResult = await this.deps.client.evaluateExtended(session.tabId, finalizeExpression, session.userId, 120_000);
57
+ if (!finalizeResult.ok) {
58
+ throw new Error(`Upload finalize evaluate failed: ${finalizeResult.error ?? "unknown error"}`);
59
+ }
60
+ const parsed = finalizeResult.result;
61
+ if (!parsed?.ok) {
62
+ throw new Error(`Upload finalize failed: ${parsed?.error ?? "unknown error"}`);
63
+ }
64
+ if (typeof parsed.data !== "string" || parsed.data.length === 0) {
65
+ throw new Error("Upload finalize failed: missing file URI");
66
+ }
67
+ return {
68
+ fileUri: parsed.data,
69
+ filename: options.filename
70
+ };
71
+ }
72
+ catch (error) {
73
+ if (chunkFailed) {
74
+ await this.cleanupPartialUpload(session.tabId, session.userId, uploadId);
75
+ }
76
+ throw error;
77
+ }
78
+ }, { maxRetries: 2 });
79
+ }
80
+ catch (error) {
81
+ if (error instanceof AppError) {
82
+ throw error;
83
+ }
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ throw new AppError("INTERNAL_ERROR", `Upload failed for ${options.filename}: ${message}`);
86
+ }
87
+ finally {
88
+ this.deps.auth.resumeRotation(accountIndex);
89
+ }
90
+ }
91
+ splitIntoChunks(base64) {
92
+ if (base64.length === 0) {
93
+ return [];
94
+ }
95
+ const chunks = [];
96
+ for (let offset = 0; offset < base64.length; offset += BASE64_CHUNK_SIZE) {
97
+ chunks.push(base64.slice(offset, offset + BASE64_CHUNK_SIZE));
98
+ }
99
+ return chunks;
100
+ }
101
+ detectMimeType(filename) {
102
+ const dotIndex = filename.lastIndexOf(".");
103
+ if (dotIndex < 0) {
104
+ return "application/octet-stream";
105
+ }
106
+ const extension = filename.slice(dotIndex).toLowerCase();
107
+ return MIME_TYPES_BY_EXTENSION[extension] ?? "application/octet-stream";
108
+ }
109
+ async cleanupPartialUpload(tabId, userId, uploadId) {
110
+ const globalKey = `__cg_upload_${uploadId}`;
111
+ const cleanupExpression = `delete window[${JSON.stringify(globalKey)}]; true`;
112
+ try {
113
+ await this.deps.client.evaluate(tabId, cleanupExpression, userId);
114
+ }
115
+ catch {
116
+ // cleanup is best-effort
117
+ }
118
+ }
119
+ }
120
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/services/upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CamoGemini Setup Wizard
4
+ * Checks prerequisites and outputs per-client MCP config
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
package/dist/setup.js ADDED
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CamoGemini Setup Wizard
4
+ * Checks prerequisites and outputs per-client MCP config
5
+ */
6
+ import { existsSync } from 'node:fs';
7
+ import { homedir, platform } from 'node:os';
8
+ import { join } from 'node:path';
9
+ const CAMOFOX_URL = process.env.CAMOFOX_URL || 'http://localhost:9377';
10
+ function detectClients() {
11
+ const home = homedir();
12
+ const os = platform();
13
+ const clients = [
14
+ {
15
+ name: 'VS Code',
16
+ configPath: os === 'darwin'
17
+ ? join(home, 'Library', 'Application Support', 'Code', 'User')
18
+ : os === 'win32'
19
+ ? join(home, 'AppData', 'Roaming', 'Code', 'User')
20
+ : join(home, '.config', 'Code', 'User'),
21
+ configKey: 'servers',
22
+ detected: false,
23
+ },
24
+ {
25
+ name: 'Claude Desktop',
26
+ configPath: os === 'darwin'
27
+ ? join(home, 'Library', 'Application Support', 'Claude')
28
+ : os === 'win32'
29
+ ? join(home, 'AppData', 'Roaming', 'Claude')
30
+ : join(home, '.config', 'Claude'),
31
+ configKey: 'mcpServers',
32
+ detected: false,
33
+ },
34
+ {
35
+ name: 'Cursor',
36
+ configPath: join(home, '.cursor'),
37
+ configKey: 'mcpServers',
38
+ detected: false,
39
+ },
40
+ {
41
+ name: 'Windsurf',
42
+ configPath: os === 'darwin'
43
+ ? join(home, '.codeium', 'windsurf')
44
+ : os === 'win32'
45
+ ? join(home, '.codeium', 'windsurf')
46
+ : join(home, '.codeium', 'windsurf'),
47
+ configKey: 'mcpServers',
48
+ detected: false,
49
+ },
50
+ ];
51
+ for (const client of clients) {
52
+ client.detected = existsSync(client.configPath);
53
+ }
54
+ return clients;
55
+ }
56
+ function generateConfig(configKey) {
57
+ if (configKey === 'servers') {
58
+ return JSON.stringify({
59
+ servers: {
60
+ "camo-gemini": {
61
+ type: 'stdio',
62
+ command: 'npx',
63
+ args: ['-y', 'camo-gemini@latest'],
64
+ env: { CAMOFOX_URL },
65
+ },
66
+ },
67
+ }, null, 2);
68
+ }
69
+ return JSON.stringify({
70
+ mcpServers: {
71
+ "camo-gemini": {
72
+ command: 'npx',
73
+ args: ['-y', 'camo-gemini@latest'],
74
+ env: { CAMOFOX_URL },
75
+ },
76
+ },
77
+ }, null, 2);
78
+ }
79
+ async function checkCamofox() {
80
+ try {
81
+ const response = await fetch(`${CAMOFOX_URL}/health`, { signal: AbortSignal.timeout(5000) });
82
+ return response.ok;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ function checkNodeVersion() {
89
+ const [major] = process.versions.node.split('.').map(Number);
90
+ return major >= 18;
91
+ }
92
+ function printHeader() {
93
+ console.log('');
94
+ console.log(' ╔══════════════════════════════════════╗');
95
+ console.log(' ║ CamoGemini Setup Wizard ║');
96
+ console.log(' ╚══════════════════════════════════════╝');
97
+ console.log('');
98
+ }
99
+ function printCheck(ok, label, detail) {
100
+ const icon = ok ? '✅' : '❌';
101
+ console.log(` ${icon} ${label}: ${detail}`);
102
+ }
103
+ async function main() {
104
+ printHeader();
105
+ console.log(' Checking prerequisites...\n');
106
+ let allOk = true;
107
+ const nodeOk = checkNodeVersion();
108
+ printCheck(nodeOk, 'Node.js', nodeOk ? `v${process.versions.node} (OK)` : `v${process.versions.node} (require >= 18)`);
109
+ if (!nodeOk)
110
+ allOk = false;
111
+ const camofoxOk = await checkCamofox();
112
+ printCheck(camofoxOk, 'CamoFox Browser', camofoxOk ? `Running on ${CAMOFOX_URL}` : `Not reachable at ${CAMOFOX_URL}`);
113
+ if (!camofoxOk) {
114
+ allOk = false;
115
+ console.log('');
116
+ console.log(' 💡 Start CamoFox with Docker:');
117
+ console.log('');
118
+ console.log(' docker run -d -p 9377:9377 --name camofox ghcr.io/redf0x1/camofox-browser:latest');
119
+ console.log('');
120
+ }
121
+ if (!allOk) {
122
+ console.log(' ⚠️ Fix the issues above and run setup again.\n');
123
+ process.exit(1);
124
+ }
125
+ console.log('');
126
+ console.log(' All checks passed! Add the config below to your MCP client:\n');
127
+ const clients = detectClients();
128
+ const detected = clients.filter(c => c.detected);
129
+ const showAll = detected.length === 0;
130
+ const clientsToShow = showAll ? clients : detected;
131
+ if (showAll) {
132
+ console.log(' (No MCP clients detected — showing all configs)\n');
133
+ }
134
+ for (const client of clientsToShow) {
135
+ const marker = client.detected ? ' ← detected' : '';
136
+ console.log(` ── ${client.name}${marker} ${'─'.repeat(Math.max(1, 38 - client.name.length - marker.length))}`);
137
+ console.log('');
138
+ const config = generateConfig(client.configKey);
139
+ for (const line of config.split('\n')) {
140
+ console.log(` ${line}`);
141
+ }
142
+ console.log('');
143
+ }
144
+ console.log(' ── Next Steps ─────────────────────────────');
145
+ console.log('');
146
+ console.log(' 1. Copy the config above into your editor\'s MCP config file');
147
+ console.log(' 2. Restart your editor');
148
+ console.log(' 3. Use the gemini_login tool to authenticate with Google');
149
+ console.log('');
150
+ console.log(' ── Verify Installation ────────────────────');
151
+ console.log('');
152
+ console.log(' Paste this prompt into your AI agent:');
153
+ console.log('');
154
+ console.log(' Verify my CamoGemini setup:');
155
+ console.log(' 1) Call gemini_health — is CamoFox connected?');
156
+ console.log(' 2) Call gemini_login to authenticate');
157
+ console.log(' 3) Call gemini_generate with "Say hello in 5 words"');
158
+ console.log(' Report pass/fail for each step.');
159
+ console.log('');
160
+ }
161
+ main().catch((err) => {
162
+ console.error('Setup failed:', err);
163
+ process.exit(1);
164
+ });
165
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,uBAAuB,CAAC;AASvE,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEtB,MAAM,OAAO,GAAiB;QAC5B;YACE,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAAE,KAAK,QAAQ;gBACzB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,CAAC;gBAC9D,CAAC,CAAC,EAAE,KAAK,OAAO;oBACd,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;oBAClD,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;YAC3C,SAAS,EAAE,SAAS;YACpB,QAAQ,EAAE,KAAK;SAChB;QACD;YACE,IAAI,EAAE,gBAAgB;YACtB,UAAU,EAAE,EAAE,KAAK,QAAQ;gBACzB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,CAAC;gBACxD,CAAC,CAAC,EAAE,KAAK,OAAO;oBACd,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;oBAC5C,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;YACrC,SAAS,EAAE,YAAY;YACvB,QAAQ,EAAE,KAAK;SAChB;QACD;YACE,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;YACjC,SAAS,EAAE,YAAY;YACvB,QAAQ,EAAE,KAAK;SAChB;QACD;YACE,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,EAAE,KAAK,QAAQ;gBACzB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC;gBACpC,CAAC,CAAC,EAAE,KAAK,OAAO;oBACd,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC;oBACpC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC;YACxC,SAAS,EAAE,YAAY;YACvB,QAAQ,EAAE,KAAK;SAChB;KACF,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,CAAC,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,SAAmC;IACzD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,OAAO,EAAE;gBACP,aAAa,EAAE;oBACb,IAAI,EAAE,OAAO;oBACb,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC;oBAClC,GAAG,EAAE,EAAE,WAAW,EAAE;iBACrB;aACF;SACF,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC;gBAClC,GAAG,EAAE,EAAE,WAAW,EAAE;aACrB;SACF;KACF,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACd,CAAC;AAED,KAAK,UAAU,YAAY;IACzB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,SAAS,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7F,OAAO,QAAQ,CAAC,EAAE,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7D,OAAO,KAAK,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,UAAU,CAAC,EAAW,EAAE,KAAa,EAAE,MAAc;IAC5D,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,WAAW,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAE7C,IAAI,KAAK,GAAG,IAAI,CAAC;IAEjB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,CAAC;IACvH,IAAI,CAAC,MAAM;QAAE,KAAK,GAAG,KAAK,CAAC;IAE3B,MAAM,SAAS,GAAG,MAAM,YAAY,EAAE,CAAC;IACvC,UAAU,CAAC,SAAS,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC,CAAC,cAAc,WAAW,EAAE,CAAC,CAAC,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;IACtH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,KAAK,GAAG,KAAK,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;QACrG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;IAE/E,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEnD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,IAAI,GAAG,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;QAChH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}