saros-proxy 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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +620 -0
  3. package/dist/cli/opencode-config.d.ts +28 -0
  4. package/dist/cli/opencode-config.js +126 -0
  5. package/dist/cli/opencode-config.js.map +1 -0
  6. package/dist/cli/setup.d.ts +29 -0
  7. package/dist/cli/setup.js +669 -0
  8. package/dist/cli/setup.js.map +1 -0
  9. package/dist/cli/ui.d.ts +27 -0
  10. package/dist/cli/ui.js +116 -0
  11. package/dist/cli/ui.js.map +1 -0
  12. package/dist/config.d.ts +50 -0
  13. package/dist/config.js +341 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/constants.d.ts +25 -0
  16. package/dist/constants.js +162 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/dashboard-parser.d.ts +47 -0
  19. package/dist/dashboard-parser.js +88 -0
  20. package/dist/dashboard-parser.js.map +1 -0
  21. package/dist/firefox-cookies.d.ts +42 -0
  22. package/dist/firefox-cookies.js +170 -0
  23. package/dist/firefox-cookies.js.map +1 -0
  24. package/dist/index.d.ts +11 -0
  25. package/dist/index.js +101 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/key-encryption.d.ts +21 -0
  28. package/dist/key-encryption.js +59 -0
  29. package/dist/key-encryption.js.map +1 -0
  30. package/dist/logger.d.ts +11 -0
  31. package/dist/logger.js +35 -0
  32. package/dist/logger.js.map +1 -0
  33. package/dist/proxy-logic.d.ts +108 -0
  34. package/dist/proxy-logic.js +353 -0
  35. package/dist/proxy-logic.js.map +1 -0
  36. package/dist/proxy.d.ts +35 -0
  37. package/dist/proxy.js +551 -0
  38. package/dist/proxy.js.map +1 -0
  39. package/dist/scraper.d.ts +70 -0
  40. package/dist/scraper.js +239 -0
  41. package/dist/scraper.js.map +1 -0
  42. package/dist/validation.d.ts +34 -0
  43. package/dist/validation.js +64 -0
  44. package/dist/validation.js.map +1 -0
  45. package/package.json +73 -0
@@ -0,0 +1,126 @@
1
+ /**
2
+ * opencode-config.ts — OpenCode client configuration management.
3
+ *
4
+ * Handles reading, merging, and writing the user's opencode.json
5
+ * to add or update the proxy provider configuration.
6
+ */
7
+ import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync } from 'node:fs';
8
+ import { dirname, join } from 'node:path';
9
+ import { homedir } from 'node:os';
10
+ import { OPENCODE_MODELS } from '../constants.js';
11
+ // ---------------------------------------------------------------------------
12
+ // Path detection
13
+ // ---------------------------------------------------------------------------
14
+ /** Return the default opencode.json path for the current platform. */
15
+ export function getDefaultOpencodeConfigPath() {
16
+ const home = homedir();
17
+ return join(home, '.config', 'opencode', 'opencode.json');
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Core update function
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * Update or create the user's opencode.json with the proxy provider.
24
+ *
25
+ * @param port — The proxy port to use in baseURL
26
+ * @param options.configPath — Explicit path to opencode.json (optional)
27
+ * @returns Result object with success status and path
28
+ */
29
+ export function updateOpencodeConfig(port, options = {}) {
30
+ const configPath = options.configPath ?? getDefaultOpencodeConfigPath();
31
+ try {
32
+ let config;
33
+ let created = false;
34
+ if (existsSync(configPath)) {
35
+ // Read and parse existing config
36
+ const raw = readFileSync(configPath, 'utf-8');
37
+ try {
38
+ config = JSON.parse(raw);
39
+ }
40
+ catch {
41
+ return {
42
+ success: false,
43
+ path: configPath,
44
+ error: 'Existing opencode.json contains invalid JSON. Please fix it manually.',
45
+ };
46
+ }
47
+ // Create backup before modifying
48
+ const backupPath = `${configPath}.backup`;
49
+ copyFileSync(configPath, backupPath);
50
+ }
51
+ else {
52
+ // Create new config
53
+ config = {};
54
+ created = true;
55
+ // Ensure parent directories exist
56
+ const dir = dirname(configPath);
57
+ if (!existsSync(dir)) {
58
+ mkdirSync(dir, { recursive: true });
59
+ }
60
+ }
61
+ // Build provider configuration
62
+ const providerConfig = {
63
+ npm: '@ai-sdk/openai-compatible',
64
+ name: 'Saros',
65
+ options: {
66
+ baseURL: `http://127.0.0.1:${port}/zen/go/v1`,
67
+ apiKey: 'not-used',
68
+ },
69
+ models: OPENCODE_MODELS,
70
+ };
71
+ // Merge into existing config
72
+ const existingProvider = config.provider ?? {};
73
+ config.provider = {
74
+ ...existingProvider,
75
+ 'saros-proxy': providerConfig,
76
+ };
77
+ // Write updated config
78
+ const json = JSON.stringify(config, null, 2);
79
+ writeFileSync(configPath, json, 'utf-8');
80
+ // Validate: re-read and parse to ensure we didn't corrupt it
81
+ try {
82
+ const verifyRaw = readFileSync(configPath, 'utf-8');
83
+ JSON.parse(verifyRaw);
84
+ }
85
+ catch {
86
+ // Restore from backup if available
87
+ const backupPath = `${configPath}.backup`;
88
+ if (existsSync(backupPath)) {
89
+ copyFileSync(backupPath, configPath);
90
+ }
91
+ return {
92
+ success: false,
93
+ path: configPath,
94
+ error: 'Failed to write valid JSON. Original file restored from backup.',
95
+ };
96
+ }
97
+ return { success: true, path: configPath, created };
98
+ }
99
+ catch (err) {
100
+ const message = err instanceof Error ? err.message : String(err);
101
+ return { success: false, path: configPath, error: message };
102
+ }
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // Manual config snippet (for users who decline automatic setup)
106
+ // ---------------------------------------------------------------------------
107
+ /**
108
+ * Generate a manual configuration snippet that users can paste.
109
+ */
110
+ export function generateManualConfigSnippet(port) {
111
+ const providerConfig = {
112
+ npm: '@ai-sdk/openai-compatible',
113
+ name: 'Saros',
114
+ options: {
115
+ baseURL: `http://127.0.0.1:${port}/zen/go/v1`,
116
+ apiKey: 'not-used',
117
+ },
118
+ models: OPENCODE_MODELS,
119
+ };
120
+ return JSON.stringify({
121
+ provider: {
122
+ 'saros-proxy': providerConfig,
123
+ },
124
+ }, null, 2);
125
+ }
126
+ //# sourceMappingURL=opencode-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-config.js","sourceRoot":"","sources":["../../src/cli/opencode-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * setup.ts — Interactive CLI setup wizard for Saros.
4
+ *
5
+ * Usage:
6
+ * npx tsx src/cli/setup.ts
7
+ * npm run setup
8
+ *
9
+ * Prompts for configuration values, writes config.yaml, and runs a quick
10
+ * smoke test to verify the proxy starts and responds to health checks.
11
+ */
12
+ export interface SetupConfig {
13
+ port: number;
14
+ upstreamBaseUrl: string;
15
+ keys: Array<{
16
+ label: string;
17
+ key: string;
18
+ }>;
19
+ scrapingAccounts?: Array<{
20
+ workspaceId: string;
21
+ authCookie: string;
22
+ }>;
23
+ scrapingThreshold?: number;
24
+ scrapingIntervalMs?: number;
25
+ }
26
+ export declare function generateYaml(cfg: SetupConfig, encryptionEnabled?: boolean): string;
27
+ export declare function testProxy(port: number, timeoutMs?: number, cwd?: string, encryptionKey?: string, configPath?: string): Promise<void>;
28
+ export declare function backupExistingConfig(configDir?: string): boolean;
29
+ export declare function setup(configDir?: string, skipSmokeTest?: boolean): Promise<void>;