sub-bridge 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.
Files changed (163) hide show
  1. package/.cursor/commands/mcp-only.md +1 -0
  2. package/.github/workflows/npm-publish.yml +33 -0
  3. package/.github/workflows/pages.yml +40 -0
  4. package/.github/workflows/release-please.yml +21 -0
  5. package/.release-please-manifest.json +3 -0
  6. package/CHANGELOG.md +8 -0
  7. package/DEVELOPMENT.md +31 -0
  8. package/LICENSE +21 -0
  9. package/README.md +87 -0
  10. package/api/index.ts +12 -0
  11. package/bun.lock +102 -0
  12. package/dist/auth/oauth-flow.d.ts +24 -0
  13. package/dist/auth/oauth-flow.d.ts.map +1 -0
  14. package/dist/auth/oauth-flow.js +184 -0
  15. package/dist/auth/oauth-flow.js.map +1 -0
  16. package/dist/auth/oauth-manager.d.ts +13 -0
  17. package/dist/auth/oauth-manager.d.ts.map +1 -0
  18. package/dist/auth/oauth-manager.js +25 -0
  19. package/dist/auth/oauth-manager.js.map +1 -0
  20. package/dist/auth/provider.d.ts +42 -0
  21. package/dist/auth/provider.d.ts.map +1 -0
  22. package/dist/auth/provider.js +270 -0
  23. package/dist/auth/provider.js.map +1 -0
  24. package/dist/cli.d.ts +3 -0
  25. package/dist/cli.d.ts.map +1 -0
  26. package/dist/cli.js +91 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/mcp/proxy.d.ts +16 -0
  29. package/dist/mcp/proxy.d.ts.map +1 -0
  30. package/dist/mcp/proxy.js +85 -0
  31. package/dist/mcp/proxy.js.map +1 -0
  32. package/dist/mcp.d.ts +3 -0
  33. package/dist/mcp.d.ts.map +1 -0
  34. package/dist/mcp.js +50 -0
  35. package/dist/mcp.js.map +1 -0
  36. package/dist/routes/auth.d.ts +6 -0
  37. package/dist/routes/auth.d.ts.map +1 -0
  38. package/dist/routes/auth.js +149 -0
  39. package/dist/routes/auth.js.map +1 -0
  40. package/dist/routes/chat.d.ts +6 -0
  41. package/dist/routes/chat.d.ts.map +1 -0
  42. package/dist/routes/chat.js +808 -0
  43. package/dist/routes/chat.js.map +1 -0
  44. package/dist/routes/tunnels.d.ts +7 -0
  45. package/dist/routes/tunnels.d.ts.map +1 -0
  46. package/dist/routes/tunnels.js +44 -0
  47. package/dist/routes/tunnels.js.map +1 -0
  48. package/dist/server.d.ts +25 -0
  49. package/dist/server.d.ts.map +1 -0
  50. package/dist/server.js +157 -0
  51. package/dist/server.js.map +1 -0
  52. package/dist/tunnel/providers/cloudflare.d.ts +9 -0
  53. package/dist/tunnel/providers/cloudflare.d.ts.map +1 -0
  54. package/dist/tunnel/providers/cloudflare.js +47 -0
  55. package/dist/tunnel/providers/cloudflare.js.map +1 -0
  56. package/dist/tunnel/providers/index.d.ts +4 -0
  57. package/dist/tunnel/providers/index.d.ts.map +1 -0
  58. package/dist/tunnel/providers/index.js +13 -0
  59. package/dist/tunnel/providers/index.js.map +1 -0
  60. package/dist/tunnel/providers/ngrok.d.ts +10 -0
  61. package/dist/tunnel/providers/ngrok.d.ts.map +1 -0
  62. package/dist/tunnel/providers/ngrok.js +52 -0
  63. package/dist/tunnel/providers/ngrok.js.map +1 -0
  64. package/dist/tunnel/providers/tailscale.d.ts +10 -0
  65. package/dist/tunnel/providers/tailscale.d.ts.map +1 -0
  66. package/dist/tunnel/providers/tailscale.js +48 -0
  67. package/dist/tunnel/providers/tailscale.js.map +1 -0
  68. package/dist/tunnel/registry.d.ts +14 -0
  69. package/dist/tunnel/registry.d.ts.map +1 -0
  70. package/dist/tunnel/registry.js +86 -0
  71. package/dist/tunnel/registry.js.map +1 -0
  72. package/dist/tunnel/types.d.ts +26 -0
  73. package/dist/tunnel/types.d.ts.map +1 -0
  74. package/dist/tunnel/types.js +6 -0
  75. package/dist/tunnel/types.js.map +1 -0
  76. package/dist/tunnel/utils.d.ts +18 -0
  77. package/dist/tunnel/utils.d.ts.map +1 -0
  78. package/dist/tunnel/utils.js +57 -0
  79. package/dist/tunnel/utils.js.map +1 -0
  80. package/dist/types.d.ts +52 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +4 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/utils/anthropic-to-openai-converter.d.ts +103 -0
  85. package/dist/utils/anthropic-to-openai-converter.d.ts.map +1 -0
  86. package/dist/utils/anthropic-to-openai-converter.js +376 -0
  87. package/dist/utils/anthropic-to-openai-converter.js.map +1 -0
  88. package/dist/utils/chat-to-responses.d.ts +59 -0
  89. package/dist/utils/chat-to-responses.d.ts.map +1 -0
  90. package/dist/utils/chat-to-responses.js +395 -0
  91. package/dist/utils/chat-to-responses.js.map +1 -0
  92. package/dist/utils/chatgpt-instructions.d.ts +3 -0
  93. package/dist/utils/chatgpt-instructions.d.ts.map +1 -0
  94. package/dist/utils/chatgpt-instructions.js +12 -0
  95. package/dist/utils/chatgpt-instructions.js.map +1 -0
  96. package/dist/utils/cli-args.d.ts +3 -0
  97. package/dist/utils/cli-args.d.ts.map +1 -0
  98. package/dist/utils/cli-args.js +10 -0
  99. package/dist/utils/cli-args.js.map +1 -0
  100. package/dist/utils/cors-bypass.d.ts +4 -0
  101. package/dist/utils/cors-bypass.d.ts.map +1 -0
  102. package/dist/utils/cors-bypass.js +30 -0
  103. package/dist/utils/cors-bypass.js.map +1 -0
  104. package/dist/utils/cursor-byok-bypass.d.ts +37 -0
  105. package/dist/utils/cursor-byok-bypass.d.ts.map +1 -0
  106. package/dist/utils/cursor-byok-bypass.js +53 -0
  107. package/dist/utils/cursor-byok-bypass.js.map +1 -0
  108. package/dist/utils/logger.d.ts +19 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +192 -0
  111. package/dist/utils/logger.js.map +1 -0
  112. package/dist/utils/port.d.ts +27 -0
  113. package/dist/utils/port.d.ts.map +1 -0
  114. package/dist/utils/port.js +78 -0
  115. package/dist/utils/port.js.map +1 -0
  116. package/dist/utils/setup-instructions.d.ts +10 -0
  117. package/dist/utils/setup-instructions.d.ts.map +1 -0
  118. package/dist/utils/setup-instructions.js +49 -0
  119. package/dist/utils/setup-instructions.js.map +1 -0
  120. package/env.example +25 -0
  121. package/index.html +992 -0
  122. package/package.json +57 -0
  123. package/public/.nojekyll +0 -0
  124. package/public/assets/chat.png +0 -0
  125. package/public/assets/demo.gif +0 -0
  126. package/public/assets/demo.mp4 +0 -0
  127. package/public/assets/setup.png +0 -0
  128. package/public/assets/ui.png +0 -0
  129. package/public/index.html +292 -0
  130. package/release-please-config.json +10 -0
  131. package/src/auth/provider.ts +412 -0
  132. package/src/cli.ts +97 -0
  133. package/src/mcp/proxy.ts +64 -0
  134. package/src/mcp.ts +56 -0
  135. package/src/oauth/authorize.ts +270 -0
  136. package/src/oauth/crypto.ts +198 -0
  137. package/src/oauth/dcr.ts +129 -0
  138. package/src/oauth/metadata.ts +40 -0
  139. package/src/oauth/token.ts +173 -0
  140. package/src/routes/auth.ts +149 -0
  141. package/src/routes/chat.ts +983 -0
  142. package/src/routes/oauth.ts +220 -0
  143. package/src/routes/tunnels.ts +45 -0
  144. package/src/server.ts +204 -0
  145. package/src/tunnel/providers/cloudflare.ts +50 -0
  146. package/src/tunnel/providers/index.ts +7 -0
  147. package/src/tunnel/providers/ngrok.ts +56 -0
  148. package/src/tunnel/providers/tailscale.ts +50 -0
  149. package/src/tunnel/registry.ts +96 -0
  150. package/src/tunnel/types.ts +32 -0
  151. package/src/tunnel/utils.ts +59 -0
  152. package/src/types.ts +55 -0
  153. package/src/utils/anthropic-to-openai-converter.ts +578 -0
  154. package/src/utils/chat-to-responses.ts +512 -0
  155. package/src/utils/chatgpt-instructions.ts +7 -0
  156. package/src/utils/cli-args.ts +8 -0
  157. package/src/utils/cors-bypass.ts +39 -0
  158. package/src/utils/cursor-byok-bypass.ts +56 -0
  159. package/src/utils/logger.ts +174 -0
  160. package/src/utils/port.ts +99 -0
  161. package/src/utils/setup-instructions.ts +59 -0
  162. package/tsconfig.json +22 -0
  163. package/vercel.json +20 -0
@@ -0,0 +1,96 @@
1
+ // ============================================================================
2
+ // Tunnel Registry - Manages providers and active tunnel
3
+ // ============================================================================
4
+
5
+ import type { TunnelProvider, TunnelInstance, TunnelStatus, ProviderInfo } from './types'
6
+ import {
7
+ CloudflareTunnelProvider,
8
+ NgrokTunnelProvider,
9
+ TailscaleTunnelProvider,
10
+ } from './providers'
11
+
12
+ export class TunnelRegistry {
13
+ private providers: Map<string, TunnelProvider> = new Map()
14
+ private activeTunnel: TunnelInstance | null = null
15
+ private startedAt: string | null = null
16
+ private lastError: string | null = null
17
+
18
+ constructor() {
19
+ const allProviders: TunnelProvider[] = [
20
+ new CloudflareTunnelProvider(),
21
+ new NgrokTunnelProvider(),
22
+ new TailscaleTunnelProvider(),
23
+ ]
24
+ for (const provider of allProviders) {
25
+ this.providers.set(provider.id, provider)
26
+ }
27
+ }
28
+
29
+ async getProviders(): Promise<ProviderInfo[]> {
30
+ const results: ProviderInfo[] = []
31
+ for (const [id, provider] of this.providers) {
32
+ results.push({
33
+ id,
34
+ name: provider.name,
35
+ available: await provider.isAvailable(),
36
+ supportsNamedTunnels: provider.supportsNamedTunnels,
37
+ })
38
+ }
39
+ return results
40
+ }
41
+
42
+ getStatus(): TunnelStatus {
43
+ if (this.activeTunnel) {
44
+ return {
45
+ active: true,
46
+ providerId: this.activeTunnel.providerId,
47
+ publicUrl: this.activeTunnel.publicUrl,
48
+ startedAt: this.startedAt || undefined,
49
+ }
50
+ }
51
+ return {
52
+ active: false,
53
+ error: this.lastError || undefined,
54
+ }
55
+ }
56
+
57
+ async start(providerId: string, localPort: number, namedUrl?: string): Promise<TunnelStatus> {
58
+ // Stop existing tunnel if any
59
+ if (this.activeTunnel) {
60
+ this.activeTunnel.stop()
61
+ this.activeTunnel = null
62
+ }
63
+
64
+ const provider = this.providers.get(providerId)
65
+ if (!provider) {
66
+ throw new Error(`Unknown tunnel provider: ${providerId}`)
67
+ }
68
+
69
+ if (!await provider.isAvailable()) {
70
+ throw new Error(`Tunnel provider ${provider.name} is not available`)
71
+ }
72
+
73
+ try {
74
+ this.lastError = null
75
+ this.activeTunnel = await provider.start(localPort, namedUrl)
76
+ this.startedAt = new Date().toISOString()
77
+ return this.getStatus()
78
+ } catch (error) {
79
+ this.lastError = error instanceof Error ? error.message : String(error)
80
+ throw error
81
+ }
82
+ }
83
+
84
+ stop(): TunnelStatus {
85
+ if (this.activeTunnel) {
86
+ this.activeTunnel.stop()
87
+ this.activeTunnel = null
88
+ this.startedAt = null
89
+ }
90
+ return this.getStatus()
91
+ }
92
+
93
+ getPublicUrl(): string | null {
94
+ return this.activeTunnel?.publicUrl || null
95
+ }
96
+ }
@@ -0,0 +1,32 @@
1
+ // ============================================================================
2
+ // Tunnel Types
3
+ // ============================================================================
4
+
5
+ export interface TunnelProvider {
6
+ id: string
7
+ name: string
8
+ supportsNamedTunnels: boolean
9
+ isAvailable(): Promise<boolean>
10
+ start(localPort: number, namedUrl?: string): Promise<TunnelInstance>
11
+ }
12
+
13
+ export interface TunnelInstance {
14
+ providerId: string
15
+ publicUrl: string
16
+ stop(): void
17
+ }
18
+
19
+ export interface TunnelStatus {
20
+ active: boolean
21
+ providerId?: string
22
+ publicUrl?: string
23
+ startedAt?: string
24
+ error?: string
25
+ }
26
+
27
+ export interface ProviderInfo {
28
+ id: string
29
+ name: string
30
+ available: boolean
31
+ supportsNamedTunnels: boolean
32
+ }
@@ -0,0 +1,59 @@
1
+ // ============================================================================
2
+ // Tunnel Utilities
3
+ // ============================================================================
4
+
5
+ import { exec, spawn, ChildProcess } from 'child_process'
6
+ import { promisify } from 'util'
7
+
8
+ const execAsync = promisify(exec)
9
+
10
+ /**
11
+ * Check if a binary exists in PATH
12
+ */
13
+ export async function binaryExists(binary: string): Promise<boolean> {
14
+ try {
15
+ const cmd = process.platform === 'win32' ? `where ${binary}` : `which ${binary}`
16
+ await execAsync(cmd)
17
+ return true
18
+ } catch {
19
+ return false
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Spawn a tunnel process with standard configuration
25
+ */
26
+ export function spawnTunnelProcess(command: string, args: string[]): ChildProcess {
27
+ return spawn(command, args, { stdio: ['ignore', 'pipe', 'pipe'] })
28
+ }
29
+
30
+ /**
31
+ * Poll a function until it returns a value or times out
32
+ */
33
+ export async function pollUntil<T>(
34
+ fn: () => Promise<T | null>,
35
+ timeout: number = 30000,
36
+ interval: number = 500
37
+ ): Promise<T> {
38
+ const start = Date.now()
39
+
40
+ while (Date.now() - start < timeout) {
41
+ try {
42
+ const result = await fn()
43
+ if (result !== null) return result
44
+ } catch {
45
+ // Continue polling on error
46
+ }
47
+ await new Promise(r => setTimeout(r, interval))
48
+ }
49
+
50
+ throw new Error('Polling timeout')
51
+ }
52
+
53
+ /**
54
+ * Execute shell command and return parsed JSON output
55
+ */
56
+ export async function execJson<T = any>(command: string): Promise<T> {
57
+ const { stdout } = await execAsync(command)
58
+ return JSON.parse(stdout)
59
+ }
package/src/types.ts ADDED
@@ -0,0 +1,55 @@
1
+ // Shared type definitions
2
+
3
+ export interface AnthropicRequestBody {
4
+ system?: Array<{ type: string; text: string }>
5
+ messages?: Array<any>
6
+ metadata?: {
7
+ user_id?: string
8
+ }
9
+ stream?: boolean
10
+ model: string
11
+ [key: string]: unknown
12
+ }
13
+
14
+ export interface AnthropicResponse {
15
+ id?: string
16
+ model?: string
17
+ stop_reason?: string | null
18
+ content?: Array<{
19
+ type: 'text' | 'tool_use'
20
+ text?: string
21
+ id?: string
22
+ name?: string
23
+ input?: unknown
24
+ }>
25
+ usage?: {
26
+ input_tokens: number
27
+ output_tokens: number
28
+ cache_creation_input_tokens?: number
29
+ cache_read_input_tokens?: number
30
+ }
31
+ [key: string]: unknown
32
+ }
33
+
34
+ export interface ErrorResponse {
35
+ error: string
36
+ message?: string
37
+ details?: string
38
+ }
39
+
40
+ export interface SuccessResponse {
41
+ success: boolean
42
+ message: string
43
+ }
44
+
45
+ export interface ModelInfo {
46
+ id: string
47
+ object: 'model'
48
+ created: number
49
+ owned_by: string
50
+ }
51
+
52
+ export interface ModelsListResponse {
53
+ object: 'list'
54
+ data: ModelInfo[]
55
+ }