@agent-relay/dashboard 2.0.82 → 2.0.84

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 (228) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/chunks/1028-da5d75e35d1420f1.js +1 -0
  3. package/out/_next/static/chunks/1528-78b17000a7e10bc6.js +2 -0
  4. package/out/_next/static/chunks/1695-4a5d33ba715e09b4.js +1 -0
  5. package/out/_next/static/chunks/1705-36c2180d00a4a569.js +1 -0
  6. package/out/_next/static/chunks/1dd3208c-e1f87c7b3dc1a820.js +1 -0
  7. package/out/_next/static/chunks/3663-47290254b8f6f5dd.js +1 -0
  8. package/out/_next/static/chunks/3677-4b225baf4801d9b9.js +73 -0
  9. package/out/_next/static/chunks/5118-7e8ada2df38eef07.js +1 -0
  10. package/out/_next/static/chunks/5888-15cbe97c90ed5fae.js +1 -0
  11. package/out/_next/static/chunks/6773-a45343a98df3abb5.js +1 -0
  12. package/out/_next/static/chunks/6940-b824612b605e79b3.js +9 -0
  13. package/out/_next/static/chunks/7894-f4a15249082a680d.js +1 -0
  14. package/out/_next/static/chunks/9175-b3617c1e5cbfed0e.js +1 -0
  15. package/out/_next/static/chunks/9372-1a804b8d08c7a236.js +1 -0
  16. package/out/_next/static/chunks/{ab6c8a12-0a58072fbb505134.js → ab6c8a12-91438a812d94ecf0.js} +1 -1
  17. package/out/_next/static/chunks/app/_not-found/page-8e8842f82d204726.js +1 -0
  18. package/out/_next/static/chunks/app/about/page-b78577a7da8fa459.js +1 -0
  19. package/out/_next/static/chunks/app/app/[[...slug]]/page-3dffd65b6344f53e.js +1 -0
  20. package/out/_next/static/chunks/app/app/onboarding/page-b89be9aa6264a5e1.js +1 -0
  21. package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-fbd00893ef69e499.js +1 -0
  22. package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-de2ea13649d0b6d3.js +1 -0
  23. package/out/_next/static/chunks/app/blog/page-a08e263c57a156fa.js +1 -0
  24. package/out/_next/static/chunks/app/careers/page-02228e1d6969b232.js +1 -0
  25. package/out/_next/static/chunks/app/changelog/page-1b5c1d79efc6e53a.js +1 -0
  26. package/out/_next/static/chunks/app/cloud/link/page-99654edffffb3af2.js +1 -0
  27. package/out/_next/static/chunks/app/complete-profile/page-59d146e5ddeafc5c.js +1 -0
  28. package/out/_next/static/chunks/app/connect-repos/page-995e16a976a6632c.js +1 -0
  29. package/out/_next/static/chunks/app/contact/page-273396a5ad57bcee.js +1 -0
  30. package/out/_next/static/chunks/app/dev/cli-tools/page-a71b80dcb2d5fc8d.js +1 -0
  31. package/out/_next/static/chunks/app/dev/log-viewer/page-46a6151ae1be0796.js +1 -0
  32. package/out/_next/static/chunks/app/docs/page-7c7cb603b24b7c40.js +1 -0
  33. package/out/_next/static/chunks/app/history/page-0c5cab1dab4e8886.js +1 -0
  34. package/out/_next/static/chunks/app/layout-96d72ba8ef8a43a0.js +1 -0
  35. package/out/_next/static/chunks/app/login/page-0ccbab34213df842.js +1 -0
  36. package/out/_next/static/chunks/app/metrics/page-8616272aeab9c8b0.js +1 -0
  37. package/out/_next/static/chunks/app/page-09ce10603ad9a251.js +1 -0
  38. package/out/_next/static/chunks/app/pricing/page-91c975079120c941.js +1 -0
  39. package/out/_next/static/chunks/app/privacy/{page-c21d51ac2dee3a88.js → page-a49ab271cc686644.js} +1 -1
  40. package/out/_next/static/chunks/app/providers/{page-59114505f4353512.js → page-d775d6eb5bc29e96.js} +1 -1
  41. package/out/_next/static/chunks/app/providers/setup/[provider]/page-ec4ef3cd80de807e.js +1 -0
  42. package/out/_next/static/chunks/app/security/page-d9da9bd9191e8f95.js +1 -0
  43. package/out/_next/static/chunks/app/signup/page-930eca0bf5fd299d.js +1 -0
  44. package/out/_next/static/chunks/app/terms/page-3e4827620b98613c.js +1 -0
  45. package/out/_next/static/chunks/framework-648e1ae7da590300.js +1 -0
  46. package/out/_next/static/chunks/{main-acb1b24265295d6a.js → main-2b1990080c292d92.js} +1 -1
  47. package/out/_next/static/chunks/main-app-9f6b7ff9e754a8f5.js +1 -0
  48. package/out/_next/static/chunks/pages/_app-a077b72e02273ab1.js +1 -0
  49. package/out/_next/static/chunks/pages/_error-84001666436a04e4.js +1 -0
  50. package/out/_next/static/chunks/{webpack-dd93b81e2659669c.js → webpack-7586035f1585f2db.js} +1 -1
  51. package/out/_next/static/css/eb9fc69d1e3d2bed.css +1 -0
  52. package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_buildManifest.js +1 -1
  53. package/out/about.html +2 -2
  54. package/out/about.txt +2 -2
  55. package/out/app/onboarding.html +1 -1
  56. package/out/app/onboarding.txt +2 -2
  57. package/out/app.html +1 -1
  58. package/out/app.txt +2 -2
  59. package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +3 -3
  60. package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
  61. package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
  62. package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
  63. package/out/blog.html +2 -2
  64. package/out/blog.txt +1 -1
  65. package/out/careers.html +2 -2
  66. package/out/careers.txt +2 -2
  67. package/out/changelog.html +2 -2
  68. package/out/changelog.txt +2 -2
  69. package/out/cloud/link.html +1 -1
  70. package/out/cloud/link.txt +2 -2
  71. package/out/complete-profile.html +2 -2
  72. package/out/complete-profile.txt +2 -2
  73. package/out/connect-repos.html +1 -1
  74. package/out/connect-repos.txt +2 -2
  75. package/out/contact.html +2 -2
  76. package/out/contact.txt +2 -2
  77. package/out/dev/cli-tools.html +1 -0
  78. package/out/dev/cli-tools.txt +7 -0
  79. package/out/dev/log-viewer.html +23 -0
  80. package/out/dev/log-viewer.txt +7 -0
  81. package/out/docs.html +2 -2
  82. package/out/docs.txt +2 -2
  83. package/out/history.html +1 -1
  84. package/out/history.txt +2 -2
  85. package/out/index.html +1 -1
  86. package/out/index.txt +2 -2
  87. package/out/login.html +2 -2
  88. package/out/login.txt +2 -2
  89. package/out/metrics.html +1 -1
  90. package/out/metrics.txt +2 -2
  91. package/out/pricing.html +2 -2
  92. package/out/pricing.txt +2 -2
  93. package/out/privacy.html +2 -2
  94. package/out/privacy.txt +2 -2
  95. package/out/providers/setup/claude.html +1 -1
  96. package/out/providers/setup/claude.txt +2 -2
  97. package/out/providers/setup/codex.html +1 -1
  98. package/out/providers/setup/codex.txt +2 -2
  99. package/out/providers/setup/cursor.html +1 -1
  100. package/out/providers/setup/cursor.txt +2 -2
  101. package/out/providers.html +1 -1
  102. package/out/providers.txt +2 -2
  103. package/out/security.html +2 -2
  104. package/out/security.txt +2 -2
  105. package/out/signup.html +2 -2
  106. package/out/signup.txt +2 -2
  107. package/out/terms.html +2 -2
  108. package/out/terms.txt +2 -2
  109. package/package.json +5 -1
  110. package/src/adapters/DashboardConfigProvider.tsx +56 -0
  111. package/src/adapters/cloudFetchAdapter.ts +278 -0
  112. package/src/adapters/index.ts +3 -0
  113. package/src/adapters/types.ts +508 -0
  114. package/src/app/app/[[...slug]]/DashboardPageClient.tsx +67 -18
  115. package/src/app/app/onboarding/page.tsx +870 -170
  116. package/src/app/cloud/link/page.tsx +14 -6
  117. package/src/app/connect-repos/page.tsx +9 -3
  118. package/src/app/dev/cli-tools/page.tsx +130 -0
  119. package/src/app/dev/log-viewer/MockLogViewer.tsx +132 -0
  120. package/src/app/dev/log-viewer/fixtures.ts +110 -0
  121. package/src/app/dev/log-viewer/page.tsx +288 -0
  122. package/src/app/history/page.tsx +28 -12
  123. package/src/app/page.tsx +1 -1
  124. package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +209 -59
  125. package/src/components/AgentCard.tsx +4 -4
  126. package/src/components/AgentLogPreview.tsx +2 -38
  127. package/src/components/App.tsx +441 -2624
  128. package/src/components/CliToolHarness.test.tsx +83 -0
  129. package/src/components/CliToolHarness.tsx +292 -0
  130. package/src/components/CoordinatorPanel.tsx +13 -6
  131. package/src/components/LogViewer.tsx +2 -42
  132. package/src/components/ProviderAuthFlow.tsx +201 -81
  133. package/src/components/ProvisioningProgress.tsx +1 -1
  134. package/src/components/ReactionChips.tsx +2 -1
  135. package/src/components/SpawnModal.test.tsx +51 -18
  136. package/src/components/SpawnModal.tsx +175 -207
  137. package/src/components/TerminalProviderSetup.tsx +1 -1
  138. package/src/components/ThreadPanel.tsx +2 -0
  139. package/src/components/WorkspaceContext.tsx +7 -19
  140. package/src/components/XTermLogViewer.tsx +190 -27
  141. package/src/components/channels/ChannelMessageList.tsx +94 -4
  142. package/src/components/channels/ChannelViewV1.tsx +35 -11
  143. package/src/components/channels/api.ts +21 -20
  144. package/src/components/channels/types.ts +16 -0
  145. package/src/components/hooks/index.ts +0 -19
  146. package/src/components/hooks/useMessages.test.ts +80 -0
  147. package/src/components/hooks/useMessages.ts +13 -4
  148. package/src/components/hooks/useOrchestrator.ts +1 -1
  149. package/src/components/hooks/usePresence.ts +45 -6
  150. package/src/components/hooks/useThread.ts +83 -46
  151. package/src/components/hooks/useTrajectory.ts +62 -5
  152. package/src/components/hooks/useWebSocket.test.ts +358 -0
  153. package/src/components/hooks/useWebSocket.ts +243 -5
  154. package/src/components/index.ts +2 -14
  155. package/src/components/layout/Header.tsx +9 -15
  156. package/src/components/layout/Sidebar.tsx +1 -8
  157. package/src/components/settings/SettingsPage.tsx +108 -47
  158. package/src/components/settings/index.ts +0 -3
  159. package/src/landing/blogData.ts +1 -1
  160. package/src/lib/agent-merge.test.ts +2 -2
  161. package/src/lib/api.ts +8 -38
  162. package/src/lib/identity.test.ts +139 -0
  163. package/src/lib/identity.ts +48 -0
  164. package/src/lib/relaycastMessageAdapters.test.ts +182 -0
  165. package/src/lib/relaycastMessageAdapters.ts +105 -0
  166. package/src/lib/sanitize-logs.test.ts +227 -0
  167. package/src/lib/sanitize-logs.ts +202 -0
  168. package/src/providers/AgentProvider.tsx +799 -0
  169. package/src/providers/ChannelProvider.tsx +528 -0
  170. package/src/providers/CloudWorkspaceProvider.tsx +402 -0
  171. package/src/providers/MessageProvider.tsx +875 -0
  172. package/src/providers/RelayConfigProvider.tsx +94 -0
  173. package/src/providers/SendProvider.tsx +497 -0
  174. package/src/providers/SettingsProvider.tsx +247 -0
  175. package/src/providers/index.ts +26 -0
  176. package/src/types/index.ts +10 -10
  177. package/out/_next/static/chunks/11-9a2993a37266dcb3.js +0 -9
  178. package/out/_next/static/chunks/118-ae2b650136a5a5fc.js +0 -1
  179. package/out/_next/static/chunks/1dd3208c-40ab0fc0f60392b8.js +0 -1
  180. package/out/_next/static/chunks/202-fc0763dd7488e58f.js +0 -1
  181. package/out/_next/static/chunks/259-83b77fa1b91ba5aa.js +0 -1
  182. package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +0 -1
  183. package/out/_next/static/chunks/528-f5f676996d613c25.js +0 -2
  184. package/out/_next/static/chunks/663-ddb04081febc3678.js +0 -1
  185. package/out/_next/static/chunks/687-88b6b139a6bb0e2e.js +0 -1
  186. package/out/_next/static/chunks/695-51d25b1988644374.js +0 -1
  187. package/out/_next/static/chunks/773-54a2641043c81e55.js +0 -1
  188. package/out/_next/static/chunks/app/_not-found/page-6da9b72091e5b511.js +0 -1
  189. package/out/_next/static/chunks/app/about/page-fff7c6457683f243.js +0 -1
  190. package/out/_next/static/chunks/app/app/[[...slug]]/page-f7eca1b66fb4249b.js +0 -1
  191. package/out/_next/static/chunks/app/app/onboarding/page-129abc5da2e67971.js +0 -1
  192. package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-5d5f28fd126b692f.js +0 -1
  193. package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-b194f207fbd91862.js +0 -1
  194. package/out/_next/static/chunks/app/blog/page-b9bd9d8703fca76a.js +0 -1
  195. package/out/_next/static/chunks/app/careers/page-a4bd8d5f4de8f4eb.js +0 -1
  196. package/out/_next/static/chunks/app/changelog/page-9a1f6ad1743d63c5.js +0 -1
  197. package/out/_next/static/chunks/app/cloud/link/page-0844c5699b027c3b.js +0 -1
  198. package/out/_next/static/chunks/app/complete-profile/page-39ed5a67916beb87.js +0 -1
  199. package/out/_next/static/chunks/app/connect-repos/page-297eddee0c39f2a3.js +0 -1
  200. package/out/_next/static/chunks/app/contact/page-3c1dd8690217fade.js +0 -1
  201. package/out/_next/static/chunks/app/docs/page-1875e981f2c3fd13.js +0 -1
  202. package/out/_next/static/chunks/app/history/page-2d5c5695c9e8b40c.js +0 -1
  203. package/out/_next/static/chunks/app/layout-0a4b99656da25511.js +0 -1
  204. package/out/_next/static/chunks/app/login/page-f69c076f5a6fc520.js +0 -1
  205. package/out/_next/static/chunks/app/metrics/page-bebbee055669a17e.js +0 -1
  206. package/out/_next/static/chunks/app/page-0ee604f7070d14c0.js +0 -1
  207. package/out/_next/static/chunks/app/pricing/page-eeae7d594af333b6.js +0 -1
  208. package/out/_next/static/chunks/app/providers/setup/[provider]/page-daf9b3e05e77ae19.js +0 -1
  209. package/out/_next/static/chunks/app/security/page-cd562730fe84a0a2.js +0 -1
  210. package/out/_next/static/chunks/app/signup/page-c242ca08101a84ff.js +0 -1
  211. package/out/_next/static/chunks/app/terms/page-c7001720e7941dc6.js +0 -1
  212. package/out/_next/static/chunks/framework-3664cab31236a9fa.js +0 -1
  213. package/out/_next/static/chunks/main-app-7f73a939a312a228.js +0 -1
  214. package/out/_next/static/chunks/pages/_app-10a93ab5b7c32eb3.js +0 -1
  215. package/out/_next/static/chunks/pages/_error-2d792b2a41857be4.js +0 -1
  216. package/out/_next/static/css/8968d98ed4c4d33f.css +0 -1
  217. package/src/components/BillingResult.tsx +0 -447
  218. package/src/components/CloudSessionProvider.tsx +0 -130
  219. package/src/components/SessionExpiredModal.tsx +0 -128
  220. package/src/components/WorkspaceStatusIndicator.tsx +0 -396
  221. package/src/components/hooks/useSession.ts +0 -209
  222. package/src/components/hooks/useWorkspaceMembers.ts +0 -132
  223. package/src/components/hooks/useWorkspaceStatus.ts +0 -237
  224. package/src/components/settings/BillingSettingsPanel.tsx +0 -564
  225. package/src/components/settings/TeamSettingsPanel.tsx +0 -560
  226. package/src/components/settings/WorkspaceSettingsPanel.tsx +0 -1368
  227. package/src/lib/cloudApi.ts +0 -893
  228. /package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_ssgManifest.js +0 -0
@@ -0,0 +1,56 @@
1
+ import React, { createContext, useContext, type ReactNode } from 'react';
2
+
3
+ import type {
4
+ CloudApiAdapter,
5
+ CloudAuthAdapter,
6
+ CloudSettingsSlots,
7
+ DashboardFeatures,
8
+ } from './types';
9
+
10
+ export interface DashboardConfig {
11
+ features: DashboardFeatures;
12
+ api?: CloudApiAdapter;
13
+ auth?: CloudAuthAdapter;
14
+ settingsSlots?: CloudSettingsSlots;
15
+ isCloudMode: boolean;
16
+ }
17
+
18
+ export const defaultDashboardFeatures: DashboardFeatures = {
19
+ billing: false,
20
+ teams: false,
21
+ workspaces: false,
22
+ auth: false,
23
+ };
24
+
25
+ export const defaultDashboardConfig: DashboardConfig = {
26
+ features: defaultDashboardFeatures,
27
+ api: undefined,
28
+ auth: undefined,
29
+ settingsSlots: undefined,
30
+ isCloudMode: false,
31
+ };
32
+
33
+ const DashboardConfigContext = createContext<DashboardConfig>(defaultDashboardConfig);
34
+
35
+ export interface DashboardConfigProviderProps {
36
+ config?: Partial<DashboardConfig>;
37
+ children: ReactNode;
38
+ }
39
+
40
+ export function DashboardConfigProvider({ config, children }: DashboardConfigProviderProps) {
41
+ const value: DashboardConfig = {
42
+ ...defaultDashboardConfig,
43
+ ...config,
44
+ features: {
45
+ ...defaultDashboardFeatures,
46
+ ...(config?.features ?? {}),
47
+ },
48
+ settingsSlots: config?.settingsSlots ?? defaultDashboardConfig.settingsSlots,
49
+ };
50
+
51
+ return <DashboardConfigContext.Provider value={value}>{children}</DashboardConfigContext.Provider>;
52
+ }
53
+
54
+ export function useDashboardConfig(): DashboardConfig {
55
+ return useContext(DashboardConfigContext);
56
+ }
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Lightweight Cloud API Adapter
3
+ *
4
+ * Fetch-based implementation of CloudApiAdapter for when the dashboard
5
+ * is served by the relay-cloud server. Uses the same-origin API endpoints
6
+ * with cookie-based session auth and CSRF tokens.
7
+ *
8
+ * Only implements methods that the App component actually calls.
9
+ * All other methods return stub errors — they're handled by the
10
+ * DashboardPageClient directly or by settings panels.
11
+ */
12
+
13
+ import type {
14
+ CloudApiAdapter,
15
+ CloudAuthAdapter,
16
+ CloudApiResult,
17
+ CloudApiResultWithoutSession,
18
+ SessionStatus,
19
+ CloudUser,
20
+ NangoLoginSession,
21
+ NangoLoginStatus,
22
+ NangoRepoSession,
23
+ NangoRepoStatus,
24
+ SessionExpiredCallback,
25
+ } from './types';
26
+
27
+ let _csrfToken: string | null = null;
28
+ const _sessionExpiredListeners = new Set<SessionExpiredCallback>();
29
+
30
+ /**
31
+ * Set the CSRF token (called by DashboardPageClient after session check)
32
+ */
33
+ export function setCloudCsrfToken(token: string | null): void {
34
+ _csrfToken = token;
35
+ }
36
+
37
+ /**
38
+ * Generic fetch wrapper with CSRF + credentials
39
+ */
40
+ async function cloudFetch<T>(path: string, init?: RequestInit): Promise<CloudApiResult<T>> {
41
+ const headers: Record<string, string> = {
42
+ 'Content-Type': 'application/json',
43
+ ...(init?.headers as Record<string, string> || {}),
44
+ };
45
+
46
+ if (_csrfToken) {
47
+ headers['X-CSRF-Token'] = _csrfToken;
48
+ }
49
+
50
+ try {
51
+ const res = await fetch(path, {
52
+ ...init,
53
+ credentials: 'include',
54
+ headers,
55
+ });
56
+
57
+ // Capture updated CSRF token
58
+ const newToken = res.headers.get('X-CSRF-Token');
59
+ if (newToken) {
60
+ _csrfToken = newToken;
61
+ }
62
+
63
+ if (res.status === 401) {
64
+ const err = await res.json().catch(() => ({ error: 'Session expired' }));
65
+ // Notify listeners
66
+ for (const cb of _sessionExpiredListeners) {
67
+ cb({ error: err.error || 'Session expired', code: 'SESSION_EXPIRED', message: err.message || '' });
68
+ }
69
+ return { success: false, error: err.error || 'Session expired' };
70
+ }
71
+
72
+ if (!res.ok) {
73
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
74
+ return { success: false, error: err.error || `HTTP ${res.status}` };
75
+ }
76
+
77
+ const data = await res.json();
78
+ return { success: true, data };
79
+ } catch (err) {
80
+ return { success: false, error: err instanceof Error ? err.message : 'Network error' };
81
+ }
82
+ }
83
+
84
+ function notImplemented(method: string): Promise<CloudApiResult<never>> {
85
+ return Promise.resolve({ success: false, error: `${method} not implemented in lightweight adapter` });
86
+ }
87
+
88
+ /**
89
+ * Cloud API adapter — implements methods used by the App component.
90
+ */
91
+ export function createCloudApiAdapter(): CloudApiAdapter {
92
+ return {
93
+ // ===== Methods used by App component =====
94
+
95
+ spawnAgent: (workspaceId, params) =>
96
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/agents`, {
97
+ method: 'POST',
98
+ body: JSON.stringify(params),
99
+ }),
100
+
101
+ getAgents: (workspaceId) =>
102
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/agents`),
103
+
104
+ stopAgent: (workspaceId, agentName) =>
105
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentName)}`, {
106
+ method: 'DELETE',
107
+ }),
108
+
109
+ getAccessibleWorkspaces: () =>
110
+ cloudFetch('/api/workspaces/accessible'),
111
+
112
+ getWorkspaceSummary: () =>
113
+ cloudFetch('/api/workspaces/summary'),
114
+
115
+ restartWorkspace: (id) =>
116
+ cloudFetch(`/api/workspaces/${encodeURIComponent(id)}/restart`, { method: 'POST' }),
117
+
118
+ // ===== Session & Auth =====
119
+
120
+ checkSession: async () => {
121
+ const res = await fetch('/api/auth/session', { credentials: 'include' });
122
+ if (!res.ok) return { authenticated: false };
123
+ return res.json();
124
+ },
125
+
126
+ getMe: () => cloudFetch('/api/auth/me'),
127
+
128
+ logout: async () => {
129
+ const headers: Record<string, string> = {};
130
+ if (_csrfToken) headers['X-CSRF-Token'] = _csrfToken;
131
+ const res = await fetch('/api/auth/logout', {
132
+ method: 'POST',
133
+ credentials: 'include',
134
+ headers,
135
+ });
136
+ return { success: res.ok };
137
+ },
138
+
139
+ // ===== Workspace Management =====
140
+
141
+ getWorkspaces: () => cloudFetch('/api/workspaces'),
142
+ getWorkspace: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}`),
143
+ createWorkspace: (data) => cloudFetch('/api/workspaces', { method: 'POST', body: JSON.stringify(data) }),
144
+ getPrimaryWorkspace: () => cloudFetch('/api/workspaces/primary'),
145
+ getWorkspaceStatus: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}/status`),
146
+ wakeupWorkspace: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}/restart`, { method: 'POST' }),
147
+ rebuildWorkspace: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}/rebuild`, { method: 'POST' }),
148
+ stopWorkspace: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}/stop`, { method: 'POST' }),
149
+ deleteWorkspace: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}`, { method: 'DELETE' }),
150
+ getWorkspaceDetails: (id) => cloudFetch(`/api/workspaces/${encodeURIComponent(id)}`),
151
+
152
+ // ===== Providers & Credentials =====
153
+
154
+ getProviders: (workspaceId) => cloudFetch(`/api/providers?workspaceId=${encodeURIComponent(workspaceId)}`),
155
+ disconnectProvider: (provider, workspaceId) =>
156
+ cloudFetch(`/api/providers/${encodeURIComponent(provider)}?workspaceId=${encodeURIComponent(workspaceId)}`, { method: 'DELETE' }),
157
+ getUserCredentials: () => cloudFetch('/api/credentials'),
158
+ assignCredentialToWorkspace: (credentialId, workspaceId) =>
159
+ cloudFetch(`/api/credentials/${encodeURIComponent(credentialId)}/assign`, {
160
+ method: 'POST',
161
+ body: JSON.stringify({ workspaceId }),
162
+ }),
163
+ unassignCredentialFromWorkspace: (credentialId, workspaceId) =>
164
+ cloudFetch(`/api/credentials/${encodeURIComponent(credentialId)}/unassign`, {
165
+ method: 'POST',
166
+ body: JSON.stringify({ workspaceId }),
167
+ }),
168
+
169
+ // ===== Nango Auth =====
170
+
171
+ getNangoLoginSession: () => cloudFetch('/api/nango/login/session') as Promise<CloudApiResultWithoutSession<NangoLoginSession>>,
172
+ checkNangoLoginStatus: (connectionId) =>
173
+ cloudFetch(`/api/nango/login/status?connectionId=${encodeURIComponent(connectionId)}`) as Promise<CloudApiResultWithoutSession<NangoLoginStatus>>,
174
+ getNangoRepoSession: () => cloudFetch('/api/nango/repo/session'),
175
+ checkNangoRepoStatus: (connectionId) =>
176
+ cloudFetch(`/api/nango/repo/status?connectionId=${encodeURIComponent(connectionId)}`),
177
+
178
+ // ===== Teams =====
179
+
180
+ getWorkspaceMembers: (workspaceId) => cloudFetch(`/api/teams/${encodeURIComponent(workspaceId)}/members`),
181
+ getRepoCollaborators: (workspaceId) => cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/repo-collaborators`),
182
+ inviteMember: (workspaceId, githubUsername, role) =>
183
+ cloudFetch(`/api/teams/${encodeURIComponent(workspaceId)}/invite`, {
184
+ method: 'POST',
185
+ body: JSON.stringify({ githubUsername, role }),
186
+ }),
187
+ getPendingInvites: () => cloudFetch('/api/teams/invites/pending'),
188
+ acceptInvite: (inviteId) => cloudFetch(`/api/teams/invites/${encodeURIComponent(inviteId)}/accept`, { method: 'POST' }),
189
+ declineInvite: (inviteId) => cloudFetch(`/api/teams/invites/${encodeURIComponent(inviteId)}/decline`, { method: 'POST' }),
190
+ updateMemberRole: (workspaceId, memberId, role) =>
191
+ cloudFetch(`/api/teams/${encodeURIComponent(workspaceId)}/members/${encodeURIComponent(memberId)}`, {
192
+ method: 'PATCH',
193
+ body: JSON.stringify({ role }),
194
+ }),
195
+ removeMember: (workspaceId, memberId) =>
196
+ cloudFetch(`/api/teams/${encodeURIComponent(workspaceId)}/members/${encodeURIComponent(memberId)}`, { method: 'DELETE' }),
197
+
198
+ // ===== Repos =====
199
+
200
+ addReposToWorkspace: (workspaceId, repositoryIds) =>
201
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/repos`, {
202
+ method: 'POST',
203
+ body: JSON.stringify({ repositoryIds }),
204
+ }),
205
+ getRepos: () => cloudFetch('/api/github-app/repos'),
206
+ syncRepo: (repoId) => cloudFetch(`/api/github-app/repos/${encodeURIComponent(repoId)}/sync`, { method: 'POST' }),
207
+
208
+ // ===== Custom Domain =====
209
+
210
+ setCustomDomain: (workspaceId, domain) =>
211
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/domain`, {
212
+ method: 'POST',
213
+ body: JSON.stringify({ domain }),
214
+ }),
215
+ verifyCustomDomain: (workspaceId) =>
216
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/domain/verify`, { method: 'POST' }),
217
+ removeCustomDomain: (workspaceId) =>
218
+ cloudFetch(`/api/workspaces/${encodeURIComponent(workspaceId)}/domain`, { method: 'DELETE' }),
219
+
220
+ // ===== Billing =====
221
+
222
+ getBillingPlans: () => cloudFetch('/api/billing/plans'),
223
+ getSubscription: () => cloudFetch('/api/billing/subscription'),
224
+ createCheckoutSession: (tier, interval) =>
225
+ cloudFetch('/api/billing/checkout', { method: 'POST', body: JSON.stringify({ tier, interval }) }),
226
+ createBillingPortal: () => cloudFetch('/api/billing/portal', { method: 'POST' }),
227
+ changeSubscription: (tier, interval) =>
228
+ cloudFetch('/api/billing/subscription', { method: 'PATCH', body: JSON.stringify({ tier, interval }) }),
229
+ cancelSubscription: () => cloudFetch('/api/billing/subscription/cancel', { method: 'POST' }),
230
+ resumeSubscription: () => cloudFetch('/api/billing/subscription/resume', { method: 'POST' }),
231
+ getInvoices: () => cloudFetch('/api/billing/invoices'),
232
+
233
+ // ===== Onboarding =====
234
+
235
+ getOnboardingNextStep: async () => {
236
+ const res = await fetch('/api/onboarding/next-step', { credentials: 'include' });
237
+ return res.json();
238
+ },
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Cloud auth adapter — implements auth methods used by the App component.
244
+ */
245
+ export function createCloudAuthAdapter(): CloudAuthAdapter {
246
+ return {
247
+ checkSession: async () => {
248
+ const res = await fetch('/api/auth/session', { credentials: 'include' });
249
+ const token = res.headers.get('X-CSRF-Token');
250
+ if (token) _csrfToken = token;
251
+ if (!res.ok) return { authenticated: false };
252
+ return res.json();
253
+ },
254
+
255
+ getUser: () => cloudFetch('/api/auth/me'),
256
+
257
+ logout: async () => {
258
+ const headers: Record<string, string> = {};
259
+ if (_csrfToken) headers['X-CSRF-Token'] = _csrfToken;
260
+ const res = await fetch('/api/auth/logout', {
261
+ method: 'POST',
262
+ credentials: 'include',
263
+ headers,
264
+ });
265
+ return { success: res.ok };
266
+ },
267
+
268
+ redirectToLogin: () => {
269
+ const returnTo = encodeURIComponent(window.location.pathname + window.location.search);
270
+ window.location.href = `/login?returnTo=${returnTo}`;
271
+ },
272
+
273
+ onSessionExpired: (callback: SessionExpiredCallback) => {
274
+ _sessionExpiredListeners.add(callback);
275
+ return () => { _sessionExpiredListeners.delete(callback); };
276
+ },
277
+ };
278
+ }
@@ -0,0 +1,3 @@
1
+ export * from './types';
2
+ export * from './DashboardConfigProvider';
3
+ export { createCloudApiAdapter, createCloudAuthAdapter, setCloudCsrfToken } from './cloudFetchAdapter';