@hasna/connectors 0.5.0 → 0.5.2

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 (223) hide show
  1. package/bin/index.js +147 -6
  2. package/bin/mcp.js +92 -1
  3. package/bin/serve.js +91 -0
  4. package/connectors/connect-ably/.env.example +11 -0
  5. package/connectors/connect-ably/CLAUDE.md +111 -0
  6. package/connectors/connect-ably/README.md +193 -0
  7. package/connectors/connect-ably/package.json +54 -0
  8. package/connectors/connect-ably/scripts/release.ts +179 -0
  9. package/connectors/connect-ably/src/api/channels.ts +33 -0
  10. package/connectors/connect-ably/src/api/client.ts +203 -0
  11. package/connectors/connect-ably/src/api/index.ts +59 -0
  12. package/connectors/connect-ably/src/api/messages.ts +48 -0
  13. package/connectors/connect-ably/src/api/presence.ts +39 -0
  14. package/connectors/connect-ably/src/api/stats.ts +29 -0
  15. package/connectors/connect-ably/src/cli/index.ts +397 -0
  16. package/connectors/connect-ably/src/index.ts +102 -0
  17. package/connectors/connect-ably/src/types/index.ts +294 -0
  18. package/connectors/connect-ably/src/utils/auth.ts +274 -0
  19. package/connectors/connect-ably/src/utils/bulk.ts +212 -0
  20. package/connectors/connect-ably/src/utils/config.ts +323 -0
  21. package/connectors/connect-ably/src/utils/output.ts +175 -0
  22. package/connectors/connect-ably/src/utils/settings.ts +114 -0
  23. package/connectors/connect-ably/src/utils/storage.ts +198 -0
  24. package/connectors/connect-ably/tsconfig.json +16 -0
  25. package/connectors/connect-box/.env.example +11 -0
  26. package/connectors/connect-box/CLAUDE.md +272 -0
  27. package/connectors/connect-box/README.md +193 -0
  28. package/connectors/connect-box/package.json +51 -0
  29. package/connectors/connect-box/scripts/release.ts +179 -0
  30. package/connectors/connect-box/src/api/client.ts +213 -0
  31. package/connectors/connect-box/src/api/example.ts +48 -0
  32. package/connectors/connect-box/src/api/index.ts +51 -0
  33. package/connectors/connect-box/src/cli/index.ts +254 -0
  34. package/connectors/connect-box/src/index.ts +103 -0
  35. package/connectors/connect-box/src/types/index.ts +237 -0
  36. package/connectors/connect-box/src/utils/auth.ts +274 -0
  37. package/connectors/connect-box/src/utils/bulk.ts +212 -0
  38. package/connectors/connect-box/src/utils/config.ts +326 -0
  39. package/connectors/connect-box/src/utils/output.ts +175 -0
  40. package/connectors/connect-box/src/utils/settings.ts +114 -0
  41. package/connectors/connect-box/src/utils/storage.ts +198 -0
  42. package/connectors/connect-box/tsconfig.json +16 -0
  43. package/connectors/connect-clearbit/.env.example +11 -0
  44. package/connectors/connect-clearbit/CLAUDE.md +272 -0
  45. package/connectors/connect-clearbit/README.md +193 -0
  46. package/connectors/connect-clearbit/package.json +51 -0
  47. package/connectors/connect-clearbit/scripts/release.ts +179 -0
  48. package/connectors/connect-clearbit/src/api/client.ts +213 -0
  49. package/connectors/connect-clearbit/src/api/example.ts +48 -0
  50. package/connectors/connect-clearbit/src/api/index.ts +51 -0
  51. package/connectors/connect-clearbit/src/cli/index.ts +254 -0
  52. package/connectors/connect-clearbit/src/index.ts +103 -0
  53. package/connectors/connect-clearbit/src/types/index.ts +237 -0
  54. package/connectors/connect-clearbit/src/utils/auth.ts +274 -0
  55. package/connectors/connect-clearbit/src/utils/bulk.ts +212 -0
  56. package/connectors/connect-clearbit/src/utils/config.ts +326 -0
  57. package/connectors/connect-clearbit/src/utils/output.ts +175 -0
  58. package/connectors/connect-clearbit/src/utils/settings.ts +114 -0
  59. package/connectors/connect-clearbit/src/utils/storage.ts +198 -0
  60. package/connectors/connect-clearbit/tsconfig.json +16 -0
  61. package/connectors/connect-coda/.env.example +11 -0
  62. package/connectors/connect-coda/CLAUDE.md +272 -0
  63. package/connectors/connect-coda/README.md +193 -0
  64. package/connectors/connect-coda/package.json +51 -0
  65. package/connectors/connect-coda/scripts/release.ts +179 -0
  66. package/connectors/connect-coda/src/api/client.ts +213 -0
  67. package/connectors/connect-coda/src/api/example.ts +48 -0
  68. package/connectors/connect-coda/src/api/index.ts +51 -0
  69. package/connectors/connect-coda/src/cli/index.ts +254 -0
  70. package/connectors/connect-coda/src/index.ts +103 -0
  71. package/connectors/connect-coda/src/types/index.ts +237 -0
  72. package/connectors/connect-coda/src/utils/auth.ts +274 -0
  73. package/connectors/connect-coda/src/utils/bulk.ts +212 -0
  74. package/connectors/connect-coda/src/utils/config.ts +326 -0
  75. package/connectors/connect-coda/src/utils/output.ts +175 -0
  76. package/connectors/connect-coda/src/utils/settings.ts +114 -0
  77. package/connectors/connect-coda/src/utils/storage.ts +198 -0
  78. package/connectors/connect-coda/tsconfig.json +16 -0
  79. package/connectors/connect-dropbox/.env.example +11 -0
  80. package/connectors/connect-dropbox/CLAUDE.md +119 -0
  81. package/connectors/connect-dropbox/README.md +193 -0
  82. package/connectors/connect-dropbox/package.json +51 -0
  83. package/connectors/connect-dropbox/src/api/client.ts +222 -0
  84. package/connectors/connect-dropbox/src/api/index.ts +395 -0
  85. package/connectors/connect-dropbox/src/cli/index.ts +627 -0
  86. package/connectors/connect-dropbox/src/index.ts +20 -0
  87. package/connectors/connect-dropbox/src/types/index.ts +516 -0
  88. package/connectors/connect-dropbox/src/utils/config.ts +197 -0
  89. package/connectors/connect-dropbox/tsconfig.json +16 -0
  90. package/connectors/connect-linode/.env.example +11 -0
  91. package/connectors/connect-linode/CLAUDE.md +272 -0
  92. package/connectors/connect-linode/README.md +193 -0
  93. package/connectors/connect-linode/package.json +51 -0
  94. package/connectors/connect-linode/scripts/release.ts +179 -0
  95. package/connectors/connect-linode/src/api/client.ts +213 -0
  96. package/connectors/connect-linode/src/api/example.ts +48 -0
  97. package/connectors/connect-linode/src/api/index.ts +51 -0
  98. package/connectors/connect-linode/src/cli/index.ts +254 -0
  99. package/connectors/connect-linode/src/index.ts +103 -0
  100. package/connectors/connect-linode/src/types/index.ts +237 -0
  101. package/connectors/connect-linode/src/utils/auth.ts +274 -0
  102. package/connectors/connect-linode/src/utils/bulk.ts +212 -0
  103. package/connectors/connect-linode/src/utils/config.ts +326 -0
  104. package/connectors/connect-linode/src/utils/output.ts +175 -0
  105. package/connectors/connect-linode/src/utils/settings.ts +114 -0
  106. package/connectors/connect-linode/src/utils/storage.ts +198 -0
  107. package/connectors/connect-linode/tsconfig.json +16 -0
  108. package/connectors/connect-mailgun/.env.example +11 -0
  109. package/connectors/connect-mailgun/CLAUDE.md +272 -0
  110. package/connectors/connect-mailgun/README.md +193 -0
  111. package/connectors/connect-mailgun/package.json +51 -0
  112. package/connectors/connect-mailgun/scripts/release.ts +179 -0
  113. package/connectors/connect-mailgun/src/api/client.ts +213 -0
  114. package/connectors/connect-mailgun/src/api/example.ts +48 -0
  115. package/connectors/connect-mailgun/src/api/index.ts +51 -0
  116. package/connectors/connect-mailgun/src/cli/index.ts +254 -0
  117. package/connectors/connect-mailgun/src/index.ts +103 -0
  118. package/connectors/connect-mailgun/src/types/index.ts +237 -0
  119. package/connectors/connect-mailgun/src/utils/auth.ts +274 -0
  120. package/connectors/connect-mailgun/src/utils/bulk.ts +212 -0
  121. package/connectors/connect-mailgun/src/utils/config.ts +326 -0
  122. package/connectors/connect-mailgun/src/utils/output.ts +175 -0
  123. package/connectors/connect-mailgun/src/utils/settings.ts +114 -0
  124. package/connectors/connect-mailgun/src/utils/storage.ts +198 -0
  125. package/connectors/connect-mailgun/tsconfig.json +16 -0
  126. package/connectors/connect-messagebird/.env.example +11 -0
  127. package/connectors/connect-messagebird/CLAUDE.md +272 -0
  128. package/connectors/connect-messagebird/README.md +193 -0
  129. package/connectors/connect-messagebird/package.json +51 -0
  130. package/connectors/connect-messagebird/scripts/release.ts +179 -0
  131. package/connectors/connect-messagebird/src/api/client.ts +213 -0
  132. package/connectors/connect-messagebird/src/api/example.ts +48 -0
  133. package/connectors/connect-messagebird/src/api/index.ts +51 -0
  134. package/connectors/connect-messagebird/src/cli/index.ts +254 -0
  135. package/connectors/connect-messagebird/src/index.ts +103 -0
  136. package/connectors/connect-messagebird/src/types/index.ts +237 -0
  137. package/connectors/connect-messagebird/src/utils/auth.ts +274 -0
  138. package/connectors/connect-messagebird/src/utils/bulk.ts +212 -0
  139. package/connectors/connect-messagebird/src/utils/config.ts +326 -0
  140. package/connectors/connect-messagebird/src/utils/output.ts +175 -0
  141. package/connectors/connect-messagebird/src/utils/settings.ts +114 -0
  142. package/connectors/connect-messagebird/src/utils/storage.ts +198 -0
  143. package/connectors/connect-messagebird/tsconfig.json +16 -0
  144. package/connectors/connect-miro/.env.example +11 -0
  145. package/connectors/connect-miro/CLAUDE.md +272 -0
  146. package/connectors/connect-miro/README.md +193 -0
  147. package/connectors/connect-miro/package.json +51 -0
  148. package/connectors/connect-miro/scripts/release.ts +179 -0
  149. package/connectors/connect-miro/src/api/client.ts +213 -0
  150. package/connectors/connect-miro/src/api/example.ts +48 -0
  151. package/connectors/connect-miro/src/api/index.ts +51 -0
  152. package/connectors/connect-miro/src/cli/index.ts +254 -0
  153. package/connectors/connect-miro/src/index.ts +103 -0
  154. package/connectors/connect-miro/src/types/index.ts +237 -0
  155. package/connectors/connect-miro/src/utils/auth.ts +274 -0
  156. package/connectors/connect-miro/src/utils/bulk.ts +212 -0
  157. package/connectors/connect-miro/src/utils/config.ts +326 -0
  158. package/connectors/connect-miro/src/utils/output.ts +175 -0
  159. package/connectors/connect-miro/src/utils/settings.ts +114 -0
  160. package/connectors/connect-miro/src/utils/storage.ts +198 -0
  161. package/connectors/connect-miro/tsconfig.json +16 -0
  162. package/connectors/connect-monday/.env.example +11 -0
  163. package/connectors/connect-monday/CLAUDE.md +128 -0
  164. package/connectors/connect-monday/README.md +193 -0
  165. package/connectors/connect-monday/package.json +52 -0
  166. package/connectors/connect-monday/src/api/client.ts +59 -0
  167. package/connectors/connect-monday/src/api/index.ts +539 -0
  168. package/connectors/connect-monday/src/cli/index.ts +479 -0
  169. package/connectors/connect-monday/src/index.ts +19 -0
  170. package/connectors/connect-monday/src/types/index.ts +274 -0
  171. package/connectors/connect-monday/src/utils/config.ts +197 -0
  172. package/connectors/connect-monday/src/utils/output.ts +119 -0
  173. package/connectors/connect-monday/tsconfig.json +16 -0
  174. package/connectors/connect-pipedrive/.env.example +11 -0
  175. package/connectors/connect-pipedrive/CLAUDE.md +128 -0
  176. package/connectors/connect-pipedrive/README.md +193 -0
  177. package/connectors/connect-pipedrive/package.json +52 -0
  178. package/connectors/connect-pipedrive/src/api/client.ts +121 -0
  179. package/connectors/connect-pipedrive/src/api/index.ts +306 -0
  180. package/connectors/connect-pipedrive/src/cli/index.ts +824 -0
  181. package/connectors/connect-pipedrive/src/index.ts +19 -0
  182. package/connectors/connect-pipedrive/src/types/index.ts +335 -0
  183. package/connectors/connect-pipedrive/src/utils/config.ts +171 -0
  184. package/connectors/connect-pipedrive/src/utils/output.ts +119 -0
  185. package/connectors/connect-pipedrive/tsconfig.json +16 -0
  186. package/connectors/connect-pusher/.env.example +11 -0
  187. package/connectors/connect-pusher/CLAUDE.md +272 -0
  188. package/connectors/connect-pusher/README.md +193 -0
  189. package/connectors/connect-pusher/package.json +51 -0
  190. package/connectors/connect-pusher/scripts/release.ts +179 -0
  191. package/connectors/connect-pusher/src/api/client.ts +213 -0
  192. package/connectors/connect-pusher/src/api/example.ts +48 -0
  193. package/connectors/connect-pusher/src/api/index.ts +51 -0
  194. package/connectors/connect-pusher/src/cli/index.ts +254 -0
  195. package/connectors/connect-pusher/src/index.ts +103 -0
  196. package/connectors/connect-pusher/src/types/index.ts +237 -0
  197. package/connectors/connect-pusher/src/utils/auth.ts +274 -0
  198. package/connectors/connect-pusher/src/utils/bulk.ts +212 -0
  199. package/connectors/connect-pusher/src/utils/config.ts +326 -0
  200. package/connectors/connect-pusher/src/utils/output.ts +175 -0
  201. package/connectors/connect-pusher/src/utils/settings.ts +114 -0
  202. package/connectors/connect-pusher/src/utils/storage.ts +198 -0
  203. package/connectors/connect-pusher/tsconfig.json +16 -0
  204. package/connectors/connect-vonage/.env.example +11 -0
  205. package/connectors/connect-vonage/CLAUDE.md +272 -0
  206. package/connectors/connect-vonage/README.md +193 -0
  207. package/connectors/connect-vonage/package.json +51 -0
  208. package/connectors/connect-vonage/scripts/release.ts +179 -0
  209. package/connectors/connect-vonage/src/api/client.ts +213 -0
  210. package/connectors/connect-vonage/src/api/example.ts +48 -0
  211. package/connectors/connect-vonage/src/api/index.ts +51 -0
  212. package/connectors/connect-vonage/src/cli/index.ts +254 -0
  213. package/connectors/connect-vonage/src/index.ts +103 -0
  214. package/connectors/connect-vonage/src/types/index.ts +237 -0
  215. package/connectors/connect-vonage/src/utils/auth.ts +274 -0
  216. package/connectors/connect-vonage/src/utils/bulk.ts +212 -0
  217. package/connectors/connect-vonage/src/utils/config.ts +326 -0
  218. package/connectors/connect-vonage/src/utils/output.ts +175 -0
  219. package/connectors/connect-vonage/src/utils/settings.ts +114 -0
  220. package/connectors/connect-vonage/src/utils/storage.ts +198 -0
  221. package/connectors/connect-vonage/tsconfig.json +16 -0
  222. package/dist/index.js +91 -0
  223. package/package.json +1 -1
@@ -0,0 +1,222 @@
1
+ import type { DropboxConfig, OutputFormat, DropboxErrorResponse } from '../types';
2
+ import { DropboxApiError } from '../types';
3
+
4
+ // Dropbox API endpoints
5
+ const API_BASE_URL = 'https://api.dropboxapi.com/2';
6
+ const CONTENT_BASE_URL = 'https://content.dropboxapi.com/2';
7
+
8
+ export interface RequestOptions {
9
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
10
+ body?: Record<string, unknown> | unknown[] | string;
11
+ headers?: Record<string, string>;
12
+ format?: OutputFormat;
13
+ endpoint?: 'api' | 'content'; // api for metadata, content for uploads/downloads
14
+ }
15
+
16
+ export class DropboxClient {
17
+ private readonly accessToken: string;
18
+
19
+ constructor(config: DropboxConfig) {
20
+ if (!config.accessToken) {
21
+ throw new Error('Access token is required');
22
+ }
23
+ this.accessToken = config.accessToken;
24
+ }
25
+
26
+ private getBaseUrl(endpoint: 'api' | 'content' = 'api'): string {
27
+ return endpoint === 'content' ? CONTENT_BASE_URL : API_BASE_URL;
28
+ }
29
+
30
+ /**
31
+ * Make an authenticated request to Dropbox API
32
+ * Uses Bearer token authentication
33
+ */
34
+ async request<T>(path: string, options: RequestOptions = {}): Promise<T> {
35
+ const { method = 'POST', body, headers = {}, endpoint = 'api' } = options;
36
+
37
+ const url = `${this.getBaseUrl(endpoint)}${path}`;
38
+
39
+ const requestHeaders: Record<string, string> = {
40
+ 'Authorization': `Bearer ${this.accessToken}`,
41
+ ...headers,
42
+ };
43
+
44
+ // Dropbox API uses JSON in the body for regular API calls
45
+ if (endpoint === 'api' && body) {
46
+ requestHeaders['Content-Type'] = 'application/json';
47
+ }
48
+
49
+ const fetchOptions: RequestInit = {
50
+ method,
51
+ headers: requestHeaders,
52
+ };
53
+
54
+ if (body && endpoint === 'api') {
55
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
56
+ }
57
+
58
+ const response = await fetch(url, fetchOptions);
59
+
60
+ // Handle 204 No Content
61
+ if (response.status === 204) {
62
+ return {} as T;
63
+ }
64
+
65
+ // Parse response
66
+ let data: unknown;
67
+ const contentType = response.headers.get('content-type') || '';
68
+
69
+ if (contentType.includes('application/json')) {
70
+ const text = await response.text();
71
+ if (text) {
72
+ try {
73
+ data = JSON.parse(text);
74
+ } catch {
75
+ data = text;
76
+ }
77
+ }
78
+ } else {
79
+ data = await response.text();
80
+ }
81
+
82
+ // Handle errors
83
+ if (!response.ok) {
84
+ let errorMessage: string;
85
+ let errorTag: string | undefined;
86
+ let userMessage: string | undefined;
87
+
88
+ if (typeof data === 'object' && data !== null) {
89
+ const errorData = data as DropboxErrorResponse;
90
+ errorMessage = errorData.error_summary || JSON.stringify(data);
91
+ errorTag = errorData.error?.['.tag'];
92
+ userMessage = errorData.user_message?.text;
93
+ } else {
94
+ errorMessage = String(data || response.statusText);
95
+ }
96
+
97
+ throw new DropboxApiError(errorMessage, response.status, errorTag, userMessage);
98
+ }
99
+
100
+ return data as T;
101
+ }
102
+
103
+ /**
104
+ * Make a content upload request (for file uploads)
105
+ */
106
+ async uploadRequest<T>(path: string, content: Uint8Array | string, arg: Record<string, unknown>): Promise<T> {
107
+ const url = `${CONTENT_BASE_URL}${path}`;
108
+
109
+ const requestHeaders: Record<string, string> = {
110
+ 'Authorization': `Bearer ${this.accessToken}`,
111
+ 'Content-Type': 'application/octet-stream',
112
+ 'Dropbox-API-Arg': JSON.stringify(arg),
113
+ };
114
+
115
+ const response = await fetch(url, {
116
+ method: 'POST',
117
+ headers: requestHeaders,
118
+ body: content,
119
+ });
120
+
121
+ // Parse response
122
+ let data: unknown;
123
+ const contentType = response.headers.get('content-type') || '';
124
+
125
+ if (contentType.includes('application/json')) {
126
+ const text = await response.text();
127
+ if (text) {
128
+ try {
129
+ data = JSON.parse(text);
130
+ } catch {
131
+ data = text;
132
+ }
133
+ }
134
+ } else {
135
+ data = await response.text();
136
+ }
137
+
138
+ // Handle errors
139
+ if (!response.ok) {
140
+ let errorMessage: string;
141
+ let errorTag: string | undefined;
142
+
143
+ if (typeof data === 'object' && data !== null) {
144
+ const errorData = data as DropboxErrorResponse;
145
+ errorMessage = errorData.error_summary || JSON.stringify(data);
146
+ errorTag = errorData.error?.['.tag'];
147
+ } else {
148
+ errorMessage = String(data || response.statusText);
149
+ }
150
+
151
+ throw new DropboxApiError(errorMessage, response.status, errorTag);
152
+ }
153
+
154
+ return data as T;
155
+ }
156
+
157
+ /**
158
+ * Make a content download request (for file downloads)
159
+ * Returns the file content and metadata
160
+ */
161
+ async downloadRequest(path: string, arg: Record<string, unknown>): Promise<{ content: ArrayBuffer; metadata: unknown }> {
162
+ const url = `${CONTENT_BASE_URL}${path}`;
163
+
164
+ const requestHeaders: Record<string, string> = {
165
+ 'Authorization': `Bearer ${this.accessToken}`,
166
+ 'Dropbox-API-Arg': JSON.stringify(arg),
167
+ };
168
+
169
+ const response = await fetch(url, {
170
+ method: 'POST',
171
+ headers: requestHeaders,
172
+ });
173
+
174
+ // Handle errors
175
+ if (!response.ok) {
176
+ const text = await response.text();
177
+ let errorMessage: string;
178
+ let errorTag: string | undefined;
179
+
180
+ try {
181
+ const errorData = JSON.parse(text) as DropboxErrorResponse;
182
+ errorMessage = errorData.error_summary || text;
183
+ errorTag = errorData.error?.['.tag'];
184
+ } catch {
185
+ errorMessage = text || response.statusText;
186
+ }
187
+
188
+ throw new DropboxApiError(errorMessage, response.status, errorTag);
189
+ }
190
+
191
+ // Get metadata from header
192
+ const metadataHeader = response.headers.get('Dropbox-API-Result');
193
+ let metadata: unknown = {};
194
+ if (metadataHeader) {
195
+ try {
196
+ metadata = JSON.parse(metadataHeader);
197
+ } catch {
198
+ // Ignore parse errors
199
+ }
200
+ }
201
+
202
+ const content = await response.arrayBuffer();
203
+ return { content, metadata };
204
+ }
205
+
206
+ /**
207
+ * Shorthand for POST requests (most Dropbox API calls use POST)
208
+ */
209
+ async post<T>(path: string, body?: Record<string, unknown> | object): Promise<T> {
210
+ return this.request<T>(path, { method: 'POST', body: body as Record<string, unknown> });
211
+ }
212
+
213
+ /**
214
+ * Get a preview of the access token (for display/debugging)
215
+ */
216
+ getAccessTokenPreview(): string {
217
+ if (this.accessToken.length > 10) {
218
+ return `${this.accessToken.substring(0, 6)}...${this.accessToken.substring(this.accessToken.length - 4)}`;
219
+ }
220
+ return '***';
221
+ }
222
+ }
@@ -0,0 +1,395 @@
1
+ import type {
2
+ DropboxConfig,
3
+ FileMetadata,
4
+ FolderMetadata,
5
+ Metadata,
6
+ ListFolderResult,
7
+ SearchV2Result,
8
+ SharedLinkMetadata,
9
+ SharedFolderMetadata,
10
+ ListSharedLinksResult,
11
+ ListFolderMembersResult,
12
+ Account,
13
+ SpaceUsage,
14
+ RelocationResult,
15
+ DeleteResult,
16
+ } from '../types';
17
+ import { DropboxClient } from './client';
18
+
19
+ /**
20
+ * Dropbox API wrapper
21
+ */
22
+ export class Dropbox {
23
+ private readonly client: DropboxClient;
24
+
25
+ constructor(config: DropboxConfig) {
26
+ this.client = new DropboxClient(config);
27
+ }
28
+
29
+ /**
30
+ * Create a client from environment variables
31
+ */
32
+ static fromEnv(): Dropbox {
33
+ const accessToken = process.env.DROPBOX_ACCESS_TOKEN || process.env.DROPBOX_TOKEN;
34
+
35
+ if (!accessToken) {
36
+ throw new Error('DROPBOX_ACCESS_TOKEN or DROPBOX_TOKEN environment variable is required');
37
+ }
38
+ return new Dropbox({ accessToken });
39
+ }
40
+
41
+ /**
42
+ * Get a preview of the access token (for debugging)
43
+ */
44
+ getAccessTokenPreview(): string {
45
+ return this.client.getAccessTokenPreview();
46
+ }
47
+
48
+ /**
49
+ * Get the underlying client for direct API access
50
+ */
51
+ getClient(): DropboxClient {
52
+ return this.client;
53
+ }
54
+
55
+ // ============================================
56
+ // Files API
57
+ // ============================================
58
+
59
+ /**
60
+ * Get metadata for a file or folder
61
+ */
62
+ async getMetadata(path: string, params?: {
63
+ include_media_info?: boolean;
64
+ include_deleted?: boolean;
65
+ include_has_explicit_shared_members?: boolean;
66
+ include_property_groups?: 'property_template_ids';
67
+ }): Promise<Metadata> {
68
+ return this.client.post<Metadata>('/files/get_metadata', {
69
+ path,
70
+ ...params,
71
+ });
72
+ }
73
+
74
+ /**
75
+ * List folder contents
76
+ */
77
+ async listFolder(path: string, params?: {
78
+ recursive?: boolean;
79
+ include_media_info?: boolean;
80
+ include_deleted?: boolean;
81
+ include_has_explicit_shared_members?: boolean;
82
+ include_mounted_folders?: boolean;
83
+ include_non_downloadable_files?: boolean;
84
+ limit?: number;
85
+ }): Promise<ListFolderResult> {
86
+ return this.client.post<ListFolderResult>('/files/list_folder', {
87
+ path,
88
+ ...params,
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Continue listing folder contents
94
+ */
95
+ async listFolderContinue(cursor: string): Promise<ListFolderResult> {
96
+ return this.client.post<ListFolderResult>('/files/list_folder/continue', { cursor });
97
+ }
98
+
99
+ /**
100
+ * Create a folder
101
+ */
102
+ async createFolder(path: string, autorename?: boolean): Promise<FolderMetadata> {
103
+ const result = await this.client.post<{ metadata: FolderMetadata }>('/files/create_folder_v2', {
104
+ path,
105
+ autorename: autorename ?? false,
106
+ });
107
+ return result.metadata;
108
+ }
109
+
110
+ /**
111
+ * Delete a file or folder
112
+ */
113
+ async delete(path: string): Promise<DeleteResult> {
114
+ return this.client.post<DeleteResult>('/files/delete_v2', { path });
115
+ }
116
+
117
+ /**
118
+ * Permanently delete a file or folder
119
+ */
120
+ async permanentlyDelete(path: string): Promise<void> {
121
+ await this.client.post('/files/permanently_delete', { path });
122
+ }
123
+
124
+ /**
125
+ * Copy a file or folder
126
+ */
127
+ async copy(fromPath: string, toPath: string, params?: {
128
+ autorename?: boolean;
129
+ allow_shared_folder?: boolean;
130
+ allow_ownership_transfer?: boolean;
131
+ }): Promise<RelocationResult> {
132
+ return this.client.post<RelocationResult>('/files/copy_v2', {
133
+ from_path: fromPath,
134
+ to_path: toPath,
135
+ ...params,
136
+ });
137
+ }
138
+
139
+ /**
140
+ * Move a file or folder
141
+ */
142
+ async move(fromPath: string, toPath: string, params?: {
143
+ autorename?: boolean;
144
+ allow_shared_folder?: boolean;
145
+ allow_ownership_transfer?: boolean;
146
+ }): Promise<RelocationResult> {
147
+ return this.client.post<RelocationResult>('/files/move_v2', {
148
+ from_path: fromPath,
149
+ to_path: toPath,
150
+ ...params,
151
+ });
152
+ }
153
+
154
+ /**
155
+ * Search for files and folders
156
+ */
157
+ async search(query: string, params?: {
158
+ path?: string;
159
+ max_results?: number;
160
+ file_status?: 'active' | 'deleted';
161
+ filename_only?: boolean;
162
+ file_extensions?: string[];
163
+ file_categories?: Array<'image' | 'document' | 'pdf' | 'spreadsheet' | 'presentation' | 'audio' | 'video' | 'folder' | 'paper' | 'others'>;
164
+ }): Promise<SearchV2Result> {
165
+ return this.client.post<SearchV2Result>('/files/search_v2', {
166
+ query,
167
+ options: params ? {
168
+ path: params.path,
169
+ max_results: params.max_results,
170
+ file_status: params.file_status ? { '.tag': params.file_status } : undefined,
171
+ filename_only: params.filename_only,
172
+ file_extensions: params.file_extensions,
173
+ file_categories: params.file_categories?.map(c => ({ '.tag': c })),
174
+ } : undefined,
175
+ });
176
+ }
177
+
178
+ /**
179
+ * Continue search
180
+ */
181
+ async searchContinue(cursor: string): Promise<SearchV2Result> {
182
+ return this.client.post<SearchV2Result>('/files/search/continue_v2', { cursor });
183
+ }
184
+
185
+ /**
186
+ * Upload a file (up to 150MB)
187
+ */
188
+ async upload(path: string, content: Uint8Array | string, params?: {
189
+ mode?: 'add' | 'overwrite' | 'update';
190
+ autorename?: boolean;
191
+ mute?: boolean;
192
+ strict_conflict?: boolean;
193
+ }): Promise<FileMetadata> {
194
+ return this.client.uploadRequest<FileMetadata>('/files/upload', content, {
195
+ path,
196
+ mode: params?.mode ? { '.tag': params.mode } : { '.tag': 'add' },
197
+ autorename: params?.autorename ?? false,
198
+ mute: params?.mute ?? false,
199
+ strict_conflict: params?.strict_conflict ?? false,
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Download a file
205
+ */
206
+ async download(path: string): Promise<{ content: ArrayBuffer; metadata: FileMetadata }> {
207
+ const result = await this.client.downloadRequest('/files/download', { path });
208
+ return {
209
+ content: result.content,
210
+ metadata: result.metadata as FileMetadata,
211
+ };
212
+ }
213
+
214
+ /**
215
+ * Get a temporary link to download a file
216
+ */
217
+ async getTemporaryLink(path: string): Promise<{ link: string; metadata: FileMetadata }> {
218
+ return this.client.post<{ link: string; metadata: FileMetadata }>('/files/get_temporary_link', { path });
219
+ }
220
+
221
+ /**
222
+ * Get a preview of a file (PDF, images)
223
+ */
224
+ async getPreview(path: string): Promise<{ content: ArrayBuffer; metadata: FileMetadata }> {
225
+ const result = await this.client.downloadRequest('/files/get_preview', { path });
226
+ return {
227
+ content: result.content,
228
+ metadata: result.metadata as FileMetadata,
229
+ };
230
+ }
231
+
232
+ /**
233
+ * Get a thumbnail for an image
234
+ */
235
+ async getThumbnail(path: string, params?: {
236
+ format?: 'jpeg' | 'png';
237
+ size?: 'w32h32' | 'w64h64' | 'w128h128' | 'w256h256' | 'w480h320' | 'w640h480' | 'w960h640' | 'w1024h768' | 'w2048h1536';
238
+ mode?: 'strict' | 'bestfit' | 'fitone_bestfit';
239
+ }): Promise<{ content: ArrayBuffer; metadata: FileMetadata }> {
240
+ const result = await this.client.downloadRequest('/files/get_thumbnail_v2', {
241
+ resource: { '.tag': 'path', path },
242
+ format: params?.format ? { '.tag': params.format } : { '.tag': 'jpeg' },
243
+ size: params?.size ? { '.tag': params.size } : { '.tag': 'w64h64' },
244
+ mode: params?.mode ? { '.tag': params.mode } : { '.tag': 'strict' },
245
+ });
246
+ return {
247
+ content: result.content,
248
+ metadata: result.metadata as FileMetadata,
249
+ };
250
+ }
251
+
252
+ // ============================================
253
+ // Sharing API
254
+ // ============================================
255
+
256
+ /**
257
+ * Create a shared link
258
+ */
259
+ async createSharedLink(path: string, params?: {
260
+ short_url?: boolean;
261
+ pending_upload?: 'file' | 'folder';
262
+ }): Promise<SharedLinkMetadata> {
263
+ return this.client.post<SharedLinkMetadata>('/sharing/create_shared_link_with_settings', {
264
+ path,
265
+ settings: params,
266
+ });
267
+ }
268
+
269
+ /**
270
+ * List shared links
271
+ */
272
+ async listSharedLinks(params?: {
273
+ path?: string;
274
+ cursor?: string;
275
+ direct_only?: boolean;
276
+ }): Promise<ListSharedLinksResult> {
277
+ return this.client.post<ListSharedLinksResult>('/sharing/list_shared_links', params || {});
278
+ }
279
+
280
+ /**
281
+ * Get shared link metadata
282
+ */
283
+ async getSharedLinkMetadata(url: string, params?: {
284
+ path?: string;
285
+ link_password?: string;
286
+ }): Promise<SharedLinkMetadata> {
287
+ return this.client.post<SharedLinkMetadata>('/sharing/get_shared_link_metadata', {
288
+ url,
289
+ ...params,
290
+ });
291
+ }
292
+
293
+ /**
294
+ * Revoke a shared link
295
+ */
296
+ async revokeSharedLink(url: string): Promise<void> {
297
+ await this.client.post('/sharing/revoke_shared_link', { url });
298
+ }
299
+
300
+ /**
301
+ * Share a folder
302
+ */
303
+ async shareFolder(path: string, params?: {
304
+ force_async?: boolean;
305
+ acl_update_policy?: 'owner' | 'editors';
306
+ member_policy?: 'team' | 'anyone';
307
+ shared_link_policy?: 'anyone' | 'team' | 'members';
308
+ viewer_info_policy?: 'enabled' | 'disabled';
309
+ }): Promise<SharedFolderMetadata | { '.tag': 'async_job_id'; async_job_id: string }> {
310
+ const result = await this.client.post<SharedFolderMetadata | { '.tag': 'async_job_id'; async_job_id: string } | { '.tag': 'complete'; complete: SharedFolderMetadata }>('/sharing/share_folder', {
311
+ path,
312
+ ...params,
313
+ });
314
+ if ((result as { '.tag': string })['?tag'] === 'complete') {
315
+ return (result as { '.tag': 'complete'; complete: SharedFolderMetadata }).complete;
316
+ }
317
+ return result as SharedFolderMetadata;
318
+ }
319
+
320
+ /**
321
+ * List shared folders
322
+ */
323
+ async listSharedFolders(params?: {
324
+ limit?: number;
325
+ actions?: Array<'change_options' | 'disable_viewer_info' | 'edit_contents' | 'enable_viewer_info' | 'invite_editor' | 'invite_viewer' | 'invite_viewer_no_comment' | 'relinquish_membership' | 'unmount' | 'unshare' | 'leave_a_copy' | 'share_link' | 'create_link' | 'set_access_inheritance'>;
326
+ }): Promise<{ entries: SharedFolderMetadata[]; cursor?: string }> {
327
+ return this.client.post('/sharing/list_folders', params || {});
328
+ }
329
+
330
+ /**
331
+ * Get shared folder metadata
332
+ */
333
+ async getSharedFolderMetadata(sharedFolderId: string): Promise<SharedFolderMetadata> {
334
+ return this.client.post<SharedFolderMetadata>('/sharing/get_folder_metadata', {
335
+ shared_folder_id: sharedFolderId,
336
+ });
337
+ }
338
+
339
+ /**
340
+ * List shared folder members
341
+ */
342
+ async listSharedFolderMembers(sharedFolderId: string, params?: {
343
+ actions?: string[];
344
+ limit?: number;
345
+ }): Promise<ListFolderMembersResult> {
346
+ return this.client.post<ListFolderMembersResult>('/sharing/list_folder_members', {
347
+ shared_folder_id: sharedFolderId,
348
+ ...params,
349
+ });
350
+ }
351
+
352
+ /**
353
+ * Unshare a folder
354
+ */
355
+ async unshareFolder(sharedFolderId: string, leaveACopy?: boolean): Promise<{ '.tag': 'complete' } | { '.tag': 'async_job_id'; async_job_id: string }> {
356
+ return this.client.post('/sharing/unshare_folder', {
357
+ shared_folder_id: sharedFolderId,
358
+ leave_a_copy: leaveACopy ?? false,
359
+ });
360
+ }
361
+
362
+ // ============================================
363
+ // Users API
364
+ // ============================================
365
+
366
+ /**
367
+ * Get current account
368
+ */
369
+ async getCurrentAccount(): Promise<Account> {
370
+ return this.client.post<Account>('/users/get_current_account', null);
371
+ }
372
+
373
+ /**
374
+ * Get space usage
375
+ */
376
+ async getSpaceUsage(): Promise<SpaceUsage> {
377
+ return this.client.post<SpaceUsage>('/users/get_space_usage', null);
378
+ }
379
+
380
+ /**
381
+ * Get account by account ID
382
+ */
383
+ async getAccount(accountId: string): Promise<Account> {
384
+ return this.client.post<Account>('/users/get_account', { account_id: accountId });
385
+ }
386
+
387
+ /**
388
+ * Get multiple accounts
389
+ */
390
+ async getAccountBatch(accountIds: string[]): Promise<Account[]> {
391
+ return this.client.post<Account[]>('/users/get_account_batch', { account_ids: accountIds });
392
+ }
393
+ }
394
+
395
+ export { DropboxClient } from './client';