@hasna/connectors 1.3.44 → 1.3.46
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.
- package/README.md +25 -0
- package/bin/index.js +792 -130
- package/bin/mcp.js +438 -52
- package/bin/serve.js +438 -52
- package/connectors/cloudflare-workers/.env.example +5 -0
- package/connectors/cloudflare-workers/AGENTS.md +11 -0
- package/connectors/cloudflare-workers/CLAUDE.md +11 -0
- package/connectors/cloudflare-workers/README.md +45 -0
- package/connectors/cloudflare-workers/package.json +47 -0
- package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
- package/connectors/cloudflare-workers/src/api/client.ts +386 -0
- package/connectors/cloudflare-workers/src/api/index.ts +1 -0
- package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
- package/connectors/cloudflare-workers/src/index.ts +16 -0
- package/connectors/cloudflare-workers/src/types/index.ts +53 -0
- package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
- package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
- package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
- package/connectors/cloudflare-workers/tsconfig.json +14 -0
- package/connectors/tidio/.env.example +3 -2
- package/connectors/tidio/CLAUDE.md +21 -96
- package/connectors/tidio/README.md +22 -18
- package/connectors/tidio/package.json +4 -2
- package/connectors/tidio/src/api/client.ts +26 -15
- package/connectors/tidio/src/api/index.ts +185 -128
- package/connectors/tidio/src/api/tidio.test.ts +175 -44
- package/connectors/tidio/src/cli/index.ts +154 -388
- package/connectors/tidio/src/index.ts +5 -3
- package/connectors/tidio/src/types/index.ts +135 -82
- package/connectors/tidio/src/utils/config.ts +90 -44
- package/connectors/wandb/.env.example +7 -0
- package/connectors/wandb/AGENTS.md +43 -0
- package/connectors/wandb/CLAUDE.md +67 -0
- package/connectors/wandb/README.md +65 -0
- package/connectors/wandb/package.json +52 -0
- package/connectors/wandb/src/api/client.test.ts +116 -0
- package/connectors/wandb/src/api/client.ts +83 -0
- package/connectors/wandb/src/api/graphql.ts +9 -0
- package/connectors/wandb/src/api/index.ts +36 -0
- package/connectors/wandb/src/api/projects.ts +36 -0
- package/connectors/wandb/src/api/viewer.ts +20 -0
- package/connectors/wandb/src/cli/index.ts +265 -0
- package/connectors/wandb/src/index.ts +22 -0
- package/connectors/wandb/src/types/index.ts +75 -0
- package/connectors/wandb/src/utils/config.ts +164 -0
- package/connectors/wandb/src/utils/output.ts +119 -0
- package/connectors/wandb/tsconfig.json +16 -0
- package/connectors/weights-biases/.env.example +7 -0
- package/connectors/weights-biases/CLAUDE.md +65 -0
- package/connectors/weights-biases/README.md +62 -0
- package/connectors/weights-biases/package.json +53 -0
- package/connectors/weights-biases/src/api/client.test.ts +46 -0
- package/connectors/weights-biases/src/api/client.ts +119 -0
- package/connectors/weights-biases/src/api/events.ts +18 -0
- package/connectors/weights-biases/src/api/index.ts +56 -0
- package/connectors/weights-biases/src/api/runs.ts +28 -0
- package/connectors/weights-biases/src/api/search.ts +10 -0
- package/connectors/weights-biases/src/cli/index.ts +289 -0
- package/connectors/weights-biases/src/index.ts +19 -0
- package/connectors/weights-biases/src/types/index.ts +92 -0
- package/connectors/weights-biases/src/utils/config.ts +168 -0
- package/connectors/weights-biases/src/utils/output.ts +116 -0
- package/connectors/weights-biases/tsconfig.json +16 -0
- package/connectors/zoominfo/.env.example +4 -0
- package/connectors/zoominfo/AGENTS.md +26 -0
- package/connectors/zoominfo/CLAUDE.md +20 -0
- package/connectors/zoominfo/README.md +69 -0
- package/connectors/zoominfo/package.json +52 -0
- package/connectors/zoominfo/src/api/client.test.ts +140 -0
- package/connectors/zoominfo/src/api/client.ts +228 -0
- package/connectors/zoominfo/src/api/index.ts +1 -0
- package/connectors/zoominfo/src/cli/index.ts +179 -0
- package/connectors/zoominfo/src/index.ts +3 -0
- package/connectors/zoominfo/src/types/index.ts +39 -0
- package/connectors/zoominfo/src/utils/config.ts +61 -0
- package/connectors/zoominfo/src/utils/output.ts +27 -0
- package/connectors/zoominfo/tsconfig.json +20 -0
- package/connectors/zotero/.env.example +7 -0
- package/connectors/zotero/.npmrc.example +2 -0
- package/connectors/zotero/AGENTS.md +40 -0
- package/connectors/zotero/CLAUDE.md +69 -0
- package/connectors/zotero/README.md +91 -0
- package/connectors/zotero/package.json +43 -0
- package/connectors/zotero/src/api/attachments.ts +130 -0
- package/connectors/zotero/src/api/client.test.ts +166 -0
- package/connectors/zotero/src/api/client.ts +169 -0
- package/connectors/zotero/src/api/collections.ts +26 -0
- package/connectors/zotero/src/api/index.ts +45 -0
- package/connectors/zotero/src/api/items.ts +64 -0
- package/connectors/zotero/src/cli/index.ts +386 -0
- package/connectors/zotero/src/index.ts +28 -0
- package/connectors/zotero/src/types/index.ts +129 -0
- package/connectors/zotero/src/utils/config.ts +245 -0
- package/connectors/zotero/src/utils/output.ts +119 -0
- package/connectors/zotero/tsconfig.json +16 -0
- package/connectors/zymbly/.env.example +2 -0
- package/connectors/zymbly/AGENTS.md +11 -0
- package/connectors/zymbly/CLAUDE.md +5 -0
- package/connectors/zymbly/README.md +35 -0
- package/connectors/zymbly/package.json +52 -0
- package/connectors/zymbly/src/api/client.test.ts +110 -0
- package/connectors/zymbly/src/api/client.ts +166 -0
- package/connectors/zymbly/src/api/index.ts +1 -0
- package/connectors/zymbly/src/cli/index.ts +156 -0
- package/connectors/zymbly/src/index.ts +12 -0
- package/connectors/zymbly/src/types/index.ts +34 -0
- package/connectors/zymbly/src/utils/config.ts +52 -0
- package/connectors/zymbly/src/utils/output.ts +17 -0
- package/connectors/zymbly/tsconfig.json +13 -0
- package/dist/index.js +45 -2
- package/dist/lib/compact-output.d.ts +40 -0
- package/dist/mcp/tools/jobs.d.ts +32 -0
- package/dist/mcp/tools/jobs.test.d.ts +1 -0
- package/package.json +3 -2
|
@@ -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
|
+
}
|