@hasna/connectors 1.3.45 → 1.4.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 (118) hide show
  1. package/README.md +25 -10
  2. package/bin/index.js +1362 -11796
  3. package/bin/mcp.js +751 -10328
  4. package/bin/serve.js +2252 -11829
  5. package/connectors/cloudflare-workers/.env.example +5 -0
  6. package/connectors/cloudflare-workers/AGENTS.md +11 -0
  7. package/connectors/cloudflare-workers/CLAUDE.md +11 -0
  8. package/connectors/cloudflare-workers/README.md +45 -0
  9. package/connectors/cloudflare-workers/package.json +47 -0
  10. package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
  11. package/connectors/cloudflare-workers/src/api/client.ts +386 -0
  12. package/connectors/cloudflare-workers/src/api/index.ts +1 -0
  13. package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
  14. package/connectors/cloudflare-workers/src/index.ts +16 -0
  15. package/connectors/cloudflare-workers/src/types/index.ts +53 -0
  16. package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
  17. package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
  18. package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
  19. package/connectors/cloudflare-workers/tsconfig.json +14 -0
  20. package/connectors/tidio/.env.example +3 -2
  21. package/connectors/tidio/CLAUDE.md +21 -96
  22. package/connectors/tidio/README.md +22 -18
  23. package/connectors/tidio/package.json +4 -2
  24. package/connectors/tidio/src/api/client.ts +26 -15
  25. package/connectors/tidio/src/api/index.ts +185 -128
  26. package/connectors/tidio/src/api/tidio.test.ts +175 -44
  27. package/connectors/tidio/src/cli/index.ts +154 -388
  28. package/connectors/tidio/src/index.ts +5 -3
  29. package/connectors/tidio/src/types/index.ts +135 -82
  30. package/connectors/tidio/src/utils/config.ts +90 -44
  31. package/connectors/wandb/.env.example +7 -0
  32. package/connectors/wandb/AGENTS.md +43 -0
  33. package/connectors/wandb/CLAUDE.md +67 -0
  34. package/connectors/wandb/README.md +65 -0
  35. package/connectors/wandb/package.json +52 -0
  36. package/connectors/wandb/src/api/client.test.ts +116 -0
  37. package/connectors/wandb/src/api/client.ts +83 -0
  38. package/connectors/wandb/src/api/graphql.ts +9 -0
  39. package/connectors/wandb/src/api/index.ts +36 -0
  40. package/connectors/wandb/src/api/projects.ts +36 -0
  41. package/connectors/wandb/src/api/viewer.ts +20 -0
  42. package/connectors/wandb/src/cli/index.ts +265 -0
  43. package/connectors/wandb/src/index.ts +22 -0
  44. package/connectors/wandb/src/types/index.ts +75 -0
  45. package/connectors/wandb/src/utils/config.ts +164 -0
  46. package/connectors/wandb/src/utils/output.ts +119 -0
  47. package/connectors/wandb/tsconfig.json +16 -0
  48. package/connectors/weights-biases/.env.example +7 -0
  49. package/connectors/weights-biases/CLAUDE.md +65 -0
  50. package/connectors/weights-biases/README.md +62 -0
  51. package/connectors/weights-biases/package.json +53 -0
  52. package/connectors/weights-biases/src/api/client.test.ts +46 -0
  53. package/connectors/weights-biases/src/api/client.ts +119 -0
  54. package/connectors/weights-biases/src/api/events.ts +18 -0
  55. package/connectors/weights-biases/src/api/index.ts +56 -0
  56. package/connectors/weights-biases/src/api/runs.ts +28 -0
  57. package/connectors/weights-biases/src/api/search.ts +10 -0
  58. package/connectors/weights-biases/src/cli/index.ts +289 -0
  59. package/connectors/weights-biases/src/index.ts +19 -0
  60. package/connectors/weights-biases/src/types/index.ts +92 -0
  61. package/connectors/weights-biases/src/utils/config.ts +168 -0
  62. package/connectors/weights-biases/src/utils/output.ts +116 -0
  63. package/connectors/weights-biases/tsconfig.json +16 -0
  64. package/connectors/x/src/api/oauth.test.ts +205 -0
  65. package/connectors/zoominfo/.env.example +4 -0
  66. package/connectors/zoominfo/AGENTS.md +26 -0
  67. package/connectors/zoominfo/CLAUDE.md +20 -0
  68. package/connectors/zoominfo/README.md +69 -0
  69. package/connectors/zoominfo/package.json +52 -0
  70. package/connectors/zoominfo/src/api/client.test.ts +140 -0
  71. package/connectors/zoominfo/src/api/client.ts +228 -0
  72. package/connectors/zoominfo/src/api/index.ts +1 -0
  73. package/connectors/zoominfo/src/cli/index.ts +179 -0
  74. package/connectors/zoominfo/src/index.ts +3 -0
  75. package/connectors/zoominfo/src/types/index.ts +39 -0
  76. package/connectors/zoominfo/src/utils/config.ts +61 -0
  77. package/connectors/zoominfo/src/utils/output.ts +27 -0
  78. package/connectors/zoominfo/tsconfig.json +20 -0
  79. package/connectors/zotero/.env.example +7 -0
  80. package/connectors/zotero/.npmrc.example +2 -0
  81. package/connectors/zotero/AGENTS.md +40 -0
  82. package/connectors/zotero/CLAUDE.md +69 -0
  83. package/connectors/zotero/README.md +91 -0
  84. package/connectors/zotero/package.json +43 -0
  85. package/connectors/zotero/src/api/attachments.ts +130 -0
  86. package/connectors/zotero/src/api/client.test.ts +166 -0
  87. package/connectors/zotero/src/api/client.ts +169 -0
  88. package/connectors/zotero/src/api/collections.ts +26 -0
  89. package/connectors/zotero/src/api/index.ts +45 -0
  90. package/connectors/zotero/src/api/items.ts +64 -0
  91. package/connectors/zotero/src/cli/index.ts +386 -0
  92. package/connectors/zotero/src/index.ts +28 -0
  93. package/connectors/zotero/src/types/index.ts +129 -0
  94. package/connectors/zotero/src/utils/config.ts +245 -0
  95. package/connectors/zotero/src/utils/output.ts +119 -0
  96. package/connectors/zotero/tsconfig.json +16 -0
  97. package/connectors/zymbly/.env.example +2 -0
  98. package/connectors/zymbly/AGENTS.md +11 -0
  99. package/connectors/zymbly/CLAUDE.md +5 -0
  100. package/connectors/zymbly/README.md +35 -0
  101. package/connectors/zymbly/package.json +52 -0
  102. package/connectors/zymbly/src/api/client.test.ts +110 -0
  103. package/connectors/zymbly/src/api/client.ts +166 -0
  104. package/connectors/zymbly/src/api/index.ts +1 -0
  105. package/connectors/zymbly/src/cli/index.ts +156 -0
  106. package/connectors/zymbly/src/index.ts +12 -0
  107. package/connectors/zymbly/src/types/index.ts +34 -0
  108. package/connectors/zymbly/src/utils/config.ts +52 -0
  109. package/connectors/zymbly/src/utils/output.ts +17 -0
  110. package/connectors/zymbly/tsconfig.json +13 -0
  111. package/dist/db/database.d.ts +2 -1
  112. package/dist/db/sqlite-adapter.d.ts +43 -0
  113. package/dist/index.js +172 -9653
  114. package/dist/lib/compact-output.d.ts +40 -0
  115. package/dist/mcp/tools/jobs.d.ts +32 -0
  116. package/dist/mcp/tools/jobs.test.d.ts +1 -0
  117. package/dist/no-cloud-boundary.test.d.ts +1 -0
  118. package/package.json +3 -3
@@ -0,0 +1,64 @@
1
+ import type {
2
+ CreateItemInput,
3
+ CreateItemsResponse,
4
+ ListItemsOptions,
5
+ UpdateItemInput,
6
+ ZoteroItem,
7
+ } from '../types';
8
+ import { encodePathSegment, ZoteroClient } from './client';
9
+
10
+ export class ItemsApi {
11
+ constructor(private readonly client: ZoteroClient) {}
12
+
13
+ private itemsPath(collectionKey?: string): string {
14
+ const prefix = this.client.libraryPrefix();
15
+ if (collectionKey) {
16
+ return `${prefix}/collections/${encodePathSegment(collectionKey)}/items`;
17
+ }
18
+ return `${prefix}/items`;
19
+ }
20
+
21
+ async list(options: ListItemsOptions = {}): Promise<ZoteroItem[]> {
22
+ const { collectionKey, ...params } = options;
23
+ return this.client.get<ZoteroItem[]>(this.itemsPath(collectionKey), params);
24
+ }
25
+
26
+ async search(query: string, options: Omit<ListItemsOptions, 'q'> = {}): Promise<ZoteroItem[]> {
27
+ return this.list({ ...options, q: query });
28
+ }
29
+
30
+ async get(itemKey: string): Promise<ZoteroItem> {
31
+ const prefix = this.client.libraryPrefix();
32
+ return this.client.get<ZoteroItem>(`${prefix}/items/${encodePathSegment(itemKey)}`);
33
+ }
34
+
35
+ async create(items: CreateItemInput | CreateItemInput[]): Promise<CreateItemsResponse> {
36
+ const payload = Array.isArray(items) ? items : [items];
37
+ return this.client.post<CreateItemsResponse>(this.itemsPath(), payload);
38
+ }
39
+
40
+ async update(
41
+ itemKey: string,
42
+ item: UpdateItemInput,
43
+ version?: number | string,
44
+ method: 'PATCH' | 'PUT' = 'PATCH'
45
+ ): Promise<CreateItemsResponse> {
46
+ const prefix = this.client.libraryPrefix();
47
+ const path = `${prefix}/items/${encodePathSegment(itemKey)}`;
48
+
49
+ if (method === 'PUT') {
50
+ return this.client.request<CreateItemsResponse>(path, {
51
+ method: 'PUT',
52
+ body: item,
53
+ version,
54
+ });
55
+ }
56
+
57
+ return this.client.patch<CreateItemsResponse>(path, item, { version });
58
+ }
59
+
60
+ async delete(itemKey: string, version: number | string): Promise<void> {
61
+ const prefix = this.client.libraryPrefix();
62
+ await this.client.delete(`${prefix}/items/${encodePathSegment(itemKey)}`, { version });
63
+ }
64
+ }
@@ -0,0 +1,386 @@
1
+ #!/usr/bin/env bun
2
+ import { readFileSync } from 'fs';
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { Zotero } from '../api';
6
+ import type { OutputFormat } from '../types';
7
+ import {
8
+ getApiKey,
9
+ setApiKey,
10
+ getLibraryId,
11
+ setLibraryId,
12
+ getLibraryType,
13
+ setLibraryType,
14
+ getBaseUrl,
15
+ setBaseUrl,
16
+ getCurrentProfile,
17
+ setCurrentProfile,
18
+ listProfiles,
19
+ createProfile,
20
+ deleteProfile,
21
+ profileExists,
22
+ clearConfig,
23
+ isAuthenticated,
24
+ setProfileOverride,
25
+ } from '../utils/config';
26
+ import { print, success, error, info, heading } from '../utils/output';
27
+
28
+ const program = new Command();
29
+
30
+ function getClient(): Zotero {
31
+ const apiKey = getApiKey();
32
+ const libraryId = getLibraryId();
33
+
34
+ if (!apiKey) {
35
+ console.error(chalk.red('Error: No Zotero API key configured.'));
36
+ console.error(chalk.yellow('Set API key with: connect-zotero config set-api-key <key>'));
37
+ console.error(chalk.yellow('Or set ZOTERO_API_KEY environment variable'));
38
+ process.exit(1);
39
+ }
40
+
41
+ if (!libraryId) {
42
+ console.error(chalk.red('Error: No Zotero library ID configured.'));
43
+ console.error(chalk.yellow('Set library ID with: connect-zotero config set-library-id <id>'));
44
+ console.error(chalk.yellow('Or set ZOTERO_LIBRARY_ID environment variable'));
45
+ process.exit(1);
46
+ }
47
+
48
+ return new Zotero({
49
+ apiKey,
50
+ libraryId,
51
+ libraryType: getLibraryType(),
52
+ baseUrl: getBaseUrl(),
53
+ });
54
+ }
55
+
56
+ function getFormat(opts: { format?: string }): OutputFormat {
57
+ const format = opts.format ?? 'pretty';
58
+ if (format === 'json' || format === 'table' || format === 'pretty') {
59
+ return format;
60
+ }
61
+ return 'pretty';
62
+ }
63
+
64
+ async function runAction(action: () => Promise<unknown>, format: OutputFormat): Promise<void> {
65
+ try {
66
+ const result = await action();
67
+ print(result, format);
68
+ } catch (e) {
69
+ error((e as Error).message);
70
+ process.exit(1);
71
+ }
72
+ }
73
+
74
+ program
75
+ .name('connect-zotero')
76
+ .description('Zotero Web API v3 CLI')
77
+ .version('0.0.1')
78
+ .option('-p, --profile <name>', 'Use specific profile')
79
+ .option('-f, --format <format>', 'Output format: json, table, pretty', 'pretty')
80
+ .hook('preAction', (thisCommand) => {
81
+ const opts = thisCommand.opts();
82
+ if (opts.profile) {
83
+ setProfileOverride(opts.profile);
84
+ }
85
+ });
86
+
87
+ const configCmd = program.command('config').description('Configuration commands');
88
+
89
+ configCmd
90
+ .command('set-api-key <key>')
91
+ .description('Set API key for current profile')
92
+ .action((key: string) => {
93
+ setApiKey(key);
94
+ success(`API key saved to profile "${getCurrentProfile()}"`);
95
+ });
96
+
97
+ configCmd
98
+ .command('set-library-id <id>')
99
+ .description('Set user or group library ID')
100
+ .action((id: string) => {
101
+ setLibraryId(id);
102
+ success(`Library ID saved to profile "${getCurrentProfile()}"`);
103
+ });
104
+
105
+ configCmd
106
+ .command('set-library-type <type>')
107
+ .description('Set library type: users or groups')
108
+ .action((type: string) => {
109
+ if (type !== 'users' && type !== 'groups' && type !== 'group') {
110
+ error('Library type must be "users" or "groups"');
111
+ process.exit(1);
112
+ }
113
+ setLibraryType(type as 'users' | 'groups' | 'group');
114
+ success(`Library type set to "${type === 'group' ? 'groups' : type}"`);
115
+ });
116
+
117
+ configCmd
118
+ .command('set-base-url <url>')
119
+ .description('Set custom API base URL')
120
+ .action((url: string) => {
121
+ setBaseUrl(url);
122
+ success(`Base URL set to "${url}"`);
123
+ });
124
+
125
+ configCmd
126
+ .command('show')
127
+ .description('Show current configuration')
128
+ .action(() => {
129
+ const apiKey = getApiKey();
130
+ heading('Current Configuration');
131
+ print({
132
+ profile: getCurrentProfile(),
133
+ authenticated: isAuthenticated(),
134
+ apiKey: apiKey ? `${apiKey.substring(0, 8)}...` : 'Not set',
135
+ libraryId: getLibraryId() || 'Not set',
136
+ libraryType: getLibraryType(),
137
+ baseUrl: getBaseUrl() || 'https://api.zotero.org (default)',
138
+ });
139
+ });
140
+
141
+ configCmd
142
+ .command('clear')
143
+ .description('Clear configuration for current profile')
144
+ .action(() => {
145
+ clearConfig();
146
+ success('Configuration cleared');
147
+ });
148
+
149
+ const profileCmd = program.command('profile').description('Profile management');
150
+
151
+ profileCmd
152
+ .command('list')
153
+ .description('List all profiles')
154
+ .action(() => {
155
+ const profiles = listProfiles();
156
+ const current = getCurrentProfile();
157
+
158
+ if (profiles.length === 0) {
159
+ info('No profiles found. Using default.');
160
+ return;
161
+ }
162
+
163
+ heading('Profiles');
164
+ profiles.forEach(p => {
165
+ const marker = p === current ? chalk.green(' (active)') : '';
166
+ console.log(` ${p}${marker}`);
167
+ });
168
+ });
169
+
170
+ profileCmd
171
+ .command('use <name>')
172
+ .description('Switch to a profile')
173
+ .action((name: string) => {
174
+ if (!profileExists(name)) {
175
+ error(`Profile "${name}" does not exist`);
176
+ process.exit(1);
177
+ }
178
+ setCurrentProfile(name);
179
+ success(`Switched to profile "${name}"`);
180
+ });
181
+
182
+ profileCmd
183
+ .command('create <name>')
184
+ .description('Create a new profile')
185
+ .action((name: string) => {
186
+ try {
187
+ createProfile(name);
188
+ success(`Profile "${name}" created`);
189
+ } catch (e) {
190
+ error((e as Error).message);
191
+ process.exit(1);
192
+ }
193
+ });
194
+
195
+ profileCmd
196
+ .command('delete <name>')
197
+ .description('Delete a profile')
198
+ .action((name: string) => {
199
+ try {
200
+ deleteProfile(name);
201
+ success(`Profile "${name}" deleted`);
202
+ } catch (e) {
203
+ error((e as Error).message);
204
+ process.exit(1);
205
+ }
206
+ });
207
+
208
+ program
209
+ .command('test')
210
+ .description('Test API authentication')
211
+ .action(async function (this: Command) {
212
+ const format = getFormat(this.opts());
213
+ await runAction(() => getClient().test(), format);
214
+ });
215
+
216
+ const itemsCmd = program.command('items').description('Library item operations');
217
+
218
+ itemsCmd
219
+ .command('list')
220
+ .description('List items in the library')
221
+ .option('--collection <key>', 'Filter by collection key')
222
+ .option('--limit <n>', 'Maximum items to return', parseInt)
223
+ .option('--start <n>', 'Start index for pagination', parseInt)
224
+ .option('--tag <tag>', 'Filter by tag')
225
+ .action(async function (this: Command, options) {
226
+ const format = getFormat(this.opts());
227
+ await runAction(
228
+ () => getClient().items.list({
229
+ collectionKey: options.collection,
230
+ limit: options.limit,
231
+ start: options.start,
232
+ tag: options.tag,
233
+ }),
234
+ format
235
+ );
236
+ });
237
+
238
+ itemsCmd
239
+ .command('search <query>')
240
+ .description('Search items by query')
241
+ .option('--collection <key>', 'Filter by collection key')
242
+ .option('--limit <n>', 'Maximum items to return', parseInt)
243
+ .action(async function (this: Command, query: string, options) {
244
+ const format = getFormat(this.opts());
245
+ await runAction(
246
+ () => getClient().items.search(query, {
247
+ collectionKey: options.collection,
248
+ limit: options.limit,
249
+ }),
250
+ format
251
+ );
252
+ });
253
+
254
+ itemsCmd
255
+ .command('get <itemKey>')
256
+ .description('Get a single item by key')
257
+ .action(async function (this: Command, itemKey: string) {
258
+ const format = getFormat(this.opts());
259
+ await runAction(() => getClient().items.get(itemKey), format);
260
+ });
261
+
262
+ itemsCmd
263
+ .command('create')
264
+ .description('Create one or more items from JSON')
265
+ .requiredOption('--json <path>', 'Path to JSON file with item(s)')
266
+ .action(async function (this: Command, options) {
267
+ const format = getFormat(this.opts());
268
+ const content = readFileSync(options.json, 'utf-8');
269
+ const payload = JSON.parse(content);
270
+ await runAction(() => getClient().items.create(payload), format);
271
+ });
272
+
273
+ itemsCmd
274
+ .command('update <itemKey>')
275
+ .description('Update an item')
276
+ .requiredOption('--json <path>', 'Path to JSON file with item fields')
277
+ .option('--version <n>', 'Item version for optimistic concurrency', parseInt)
278
+ .option('--method <method>', 'HTTP method: PATCH or PUT', 'PATCH')
279
+ .action(async function (this: Command, itemKey: string, options) {
280
+ const format = getFormat(this.opts());
281
+ const content = readFileSync(options.json, 'utf-8');
282
+ const payload = JSON.parse(content);
283
+ const method = options.method === 'PUT' ? 'PUT' : 'PATCH';
284
+ await runAction(
285
+ () => getClient().items.update(itemKey, payload, options.version, method),
286
+ format
287
+ );
288
+ });
289
+
290
+ itemsCmd
291
+ .command('delete <itemKey>')
292
+ .description('Delete an item')
293
+ .requiredOption('--version <n>', 'Item version for optimistic concurrency', parseInt)
294
+ .action(async function (this: Command, itemKey: string, options) {
295
+ const format = getFormat(this.opts());
296
+ await runAction(() => getClient().items.delete(itemKey, options.version), format);
297
+ });
298
+
299
+ const collectionsCmd = program.command('collections').description('Collection operations');
300
+
301
+ collectionsCmd
302
+ .command('list')
303
+ .description('List collections')
304
+ .action(async function (this: Command) {
305
+ const format = getFormat(this.opts());
306
+ await runAction(() => getClient().collections.list(), format);
307
+ });
308
+
309
+ collectionsCmd
310
+ .command('get <collectionKey>')
311
+ .description('Get a collection by key')
312
+ .action(async function (this: Command, collectionKey: string) {
313
+ const format = getFormat(this.opts());
314
+ await runAction(() => getClient().collections.get(collectionKey), format);
315
+ });
316
+
317
+ collectionsCmd
318
+ .command('create')
319
+ .description('Create a collection from JSON')
320
+ .requiredOption('--json <path>', 'Path to JSON file with collection data')
321
+ .action(async function (this: Command, options) {
322
+ const format = getFormat(this.opts());
323
+ const content = readFileSync(options.json, 'utf-8');
324
+ const payload = JSON.parse(content);
325
+ await runAction(() => getClient().collections.create(payload), format);
326
+ });
327
+
328
+ const attachmentsCmd = program.command('attachments').description('Attachment operations');
329
+
330
+ attachmentsCmd
331
+ .command('create')
332
+ .description('Create an attachment from JSON')
333
+ .requiredOption('--json <path>', 'Path to JSON file with attachment data')
334
+ .action(async function (this: Command, options) {
335
+ const format = getFormat(this.opts());
336
+ const content = readFileSync(options.json, 'utf-8');
337
+ const payload = JSON.parse(content);
338
+ await runAction(() => getClient().attachments.create(payload), format);
339
+ });
340
+
341
+ attachmentsCmd
342
+ .command('upload')
343
+ .description('Upload a file attachment')
344
+ .requiredOption('--file <path>', 'Path to file to upload')
345
+ .option('--parent <itemKey>', 'Parent item key (required if no --attachment-key)')
346
+ .option('--attachment-key <key>', 'Existing attachment item key')
347
+ .option('--content-type <type>', 'MIME type')
348
+ .action(async function (this: Command, options) {
349
+ const format = getFormat(this.opts());
350
+ const content = readFileSync(options.file);
351
+ await runAction(
352
+ () => getClient().attachments.uploadFile({
353
+ filename: options.file.split('/').pop() || 'upload.bin',
354
+ content,
355
+ contentType: options.contentType,
356
+ parentItem: options.parent,
357
+ attachmentKey: options.attachmentKey,
358
+ }),
359
+ format
360
+ );
361
+ });
362
+
363
+ program
364
+ .command('raw <path>')
365
+ .description('Make a raw API request')
366
+ .option('-X, --method <method>', 'HTTP method', 'GET')
367
+ .option('--json <path>', 'Path to JSON request body')
368
+ .option('--version <n>', 'If-Unmodified-Since-Version header', parseInt)
369
+ .action(async function (this: Command, path: string, options) {
370
+ const format = getFormat(this.opts());
371
+ let body: unknown;
372
+ if (options.json) {
373
+ body = JSON.parse(readFileSync(options.json, 'utf-8'));
374
+ }
375
+
376
+ await runAction(
377
+ () => getClient().rawRequest(path, {
378
+ method: options.method,
379
+ body,
380
+ version: options.version,
381
+ }),
382
+ format
383
+ );
384
+ });
385
+
386
+ program.parse();
@@ -0,0 +1,28 @@
1
+ export { Zotero, ZoteroClient, ItemsApi, CollectionsApi, AttachmentsApi } from './api';
2
+ export {
3
+ DEFAULT_BASE_URL,
4
+ ZOTERO_API_VERSION,
5
+ normalizeLibraryType,
6
+ buildLibraryPrefix,
7
+ buildZoteroUrl,
8
+ } from './api';
9
+
10
+ export type {
11
+ ZoteroConfig,
12
+ CliConfig,
13
+ LibraryType,
14
+ ZoteroItem,
15
+ ZoteroCollection,
16
+ ListItemsOptions,
17
+ CreateItemInput,
18
+ UpdateItemInput,
19
+ CreateCollectionInput,
20
+ CreateAttachmentInput,
21
+ UploadFileInput,
22
+ UploadAuthResponse,
23
+ CreateItemsResponse,
24
+ RequestOptions,
25
+ OutputFormat,
26
+ } from './types';
27
+
28
+ export { ZoteroApiError } from './types';
@@ -0,0 +1,129 @@
1
+ // Zotero Web API v3 types
2
+
3
+ export type OutputFormat = 'json' | 'table' | 'pretty';
4
+
5
+ export type LibraryType = 'users' | 'groups';
6
+
7
+ export interface ZoteroConfig {
8
+ apiKey: string;
9
+ libraryId: string;
10
+ libraryType?: LibraryType | 'group';
11
+ baseUrl?: string;
12
+ }
13
+
14
+ export interface CliConfig {
15
+ apiKey?: string;
16
+ libraryId?: string;
17
+ libraryType?: LibraryType | 'group';
18
+ baseUrl?: string;
19
+ }
20
+
21
+ export class ZoteroApiError extends Error {
22
+ constructor(
23
+ message: string,
24
+ public readonly code: string,
25
+ public readonly statusCode?: number
26
+ ) {
27
+ super(message);
28
+ this.name = 'ZoteroApiError';
29
+ }
30
+ }
31
+
32
+ export interface ZoteroItem {
33
+ key: string;
34
+ version: number;
35
+ itemType: string;
36
+ title?: string;
37
+ creators?: Array<{ creatorType: string; firstName?: string; lastName?: string; name?: string }>;
38
+ tags?: Array<{ tag: string; type?: number }>;
39
+ collections?: string[];
40
+ relations?: Record<string, string>;
41
+ date?: string;
42
+ url?: string;
43
+ [key: string]: unknown;
44
+ }
45
+
46
+ export interface ZoteroCollection {
47
+ key: string;
48
+ version: number;
49
+ name: string;
50
+ parentCollection?: string | false;
51
+ relations?: Record<string, string>;
52
+ }
53
+
54
+ export interface ListItemsOptions {
55
+ collectionKey?: string;
56
+ q?: string;
57
+ tag?: string;
58
+ since?: number;
59
+ limit?: number;
60
+ start?: number;
61
+ sort?: string;
62
+ direction?: 'asc' | 'desc';
63
+ includeTrashed?: 0 | 1;
64
+ }
65
+
66
+ export interface CreateItemInput {
67
+ itemType: string;
68
+ title?: string;
69
+ creators?: ZoteroItem['creators'];
70
+ tags?: ZoteroItem['tags'];
71
+ collections?: string[];
72
+ relations?: Record<string, string>;
73
+ [key: string]: unknown;
74
+ }
75
+
76
+ export interface UpdateItemInput extends Partial<CreateItemInput> {
77
+ key?: string;
78
+ }
79
+
80
+ export interface CreateCollectionInput {
81
+ name: string;
82
+ parentCollection?: string | false;
83
+ relations?: Record<string, string>;
84
+ }
85
+
86
+ export interface CreateAttachmentInput {
87
+ parentItem: string;
88
+ title?: string;
89
+ url?: string;
90
+ linkMode?: 'imported_url' | 'imported_file' | 'linked_url';
91
+ accessDate?: string;
92
+ contentType?: string;
93
+ filename?: string;
94
+ tags?: ZoteroItem['tags'];
95
+ collections?: string[];
96
+ relations?: Record<string, string>;
97
+ }
98
+
99
+ export interface UploadFileInput {
100
+ filename: string;
101
+ content: Buffer | Uint8Array;
102
+ contentType?: string;
103
+ parentItem?: string;
104
+ attachmentKey?: string;
105
+ mtime?: number;
106
+ }
107
+
108
+ export interface UploadAuthResponse {
109
+ exists?: number;
110
+ url?: string;
111
+ contentType?: string;
112
+ prefix?: string;
113
+ suffix?: string;
114
+ uploadKey?: string;
115
+ }
116
+
117
+ export interface CreateItemsResponse {
118
+ successful?: Record<string, string>;
119
+ success?: Record<string, string>;
120
+ failed?: Record<string, unknown>;
121
+ }
122
+
123
+ export interface RequestOptions {
124
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
125
+ params?: Record<string, string | number | boolean | undefined>;
126
+ body?: unknown;
127
+ headers?: Record<string, string>;
128
+ version?: number | string;
129
+ }