@hesed/conni 0.1.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 (49) hide show
  1. package/README.md +449 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +5 -0
  6. package/dist/commands/conni/auth/add.d.ts +14 -0
  7. package/dist/commands/conni/auth/add.js +55 -0
  8. package/dist/commands/conni/auth/test.d.ts +10 -0
  9. package/dist/commands/conni/auth/test.js +32 -0
  10. package/dist/commands/conni/auth/update.d.ts +14 -0
  11. package/dist/commands/conni/auth/update.js +77 -0
  12. package/dist/commands/conni/content/attachment-download.d.ts +13 -0
  13. package/dist/commands/conni/content/attachment-download.js +44 -0
  14. package/dist/commands/conni/content/attachment.d.ts +13 -0
  15. package/dist/commands/conni/content/attachment.js +40 -0
  16. package/dist/commands/conni/content/comment-delete.d.ts +12 -0
  17. package/dist/commands/conni/content/comment-delete.js +29 -0
  18. package/dist/commands/conni/content/comment-update.d.ts +13 -0
  19. package/dist/commands/conni/content/comment-update.js +35 -0
  20. package/dist/commands/conni/content/comment.d.ts +13 -0
  21. package/dist/commands/conni/content/comment.js +35 -0
  22. package/dist/commands/conni/content/create.d.ts +11 -0
  23. package/dist/commands/conni/content/create.js +50 -0
  24. package/dist/commands/conni/content/delete.d.ts +12 -0
  25. package/dist/commands/conni/content/delete.js +29 -0
  26. package/dist/commands/conni/content/get.d.ts +12 -0
  27. package/dist/commands/conni/content/get.js +29 -0
  28. package/dist/commands/conni/content/search.d.ts +14 -0
  29. package/dist/commands/conni/content/search.js +34 -0
  30. package/dist/commands/conni/content/update.d.ts +12 -0
  31. package/dist/commands/conni/content/update.js +35 -0
  32. package/dist/commands/conni/space/get.d.ts +12 -0
  33. package/dist/commands/conni/space/get.js +29 -0
  34. package/dist/commands/conni/space/list.d.ts +9 -0
  35. package/dist/commands/conni/space/list.js +26 -0
  36. package/dist/config.d.ts +10 -0
  37. package/dist/config.js +18 -0
  38. package/dist/conni/conni-api.d.ts +88 -0
  39. package/dist/conni/conni-api.js +447 -0
  40. package/dist/conni/conni-client.d.ts +88 -0
  41. package/dist/conni/conni-client.js +148 -0
  42. package/dist/format.d.ts +4 -0
  43. package/dist/format.js +10 -0
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.js +1 -0
  46. package/dist/utils.d.ts +1 -0
  47. package/dist/utils.js +1 -0
  48. package/oclif.manifest.json +667 -0
  49. package/package.json +107 -0
@@ -0,0 +1,88 @@
1
+ import { ConfluenceClient } from 'confluence.js';
2
+ /**
3
+ * Generic API result
4
+ */
5
+ export interface ApiResult {
6
+ data?: unknown;
7
+ error?: unknown;
8
+ success: boolean;
9
+ }
10
+ export interface Config {
11
+ apiToken: string;
12
+ email: string;
13
+ host: string;
14
+ }
15
+ export interface ConniError {
16
+ data: unknown;
17
+ message: string;
18
+ statusCode: string;
19
+ }
20
+ /**
21
+ * Confluence API Utility
22
+ * Provides core Confluence API operations
23
+ */
24
+ export declare class ConniApi {
25
+ private client?;
26
+ private config;
27
+ constructor(config: Config);
28
+ /**
29
+ * Add an attachment to a page
30
+ */
31
+ addAttachment(pageId: string, filePath: string): Promise<ApiResult>;
32
+ /**
33
+ * Add a comment to a page
34
+ */
35
+ addComment(pageId: string, body: string): Promise<ApiResult>;
36
+ /**
37
+ * Clear client (for cleanup)
38
+ */
39
+ clearClients(): void;
40
+ /**
41
+ * Create a new page
42
+ */
43
+ createPage(fields: Record<string, unknown>): Promise<ApiResult>;
44
+ /**
45
+ * Delete a comment from a page
46
+ */
47
+ deleteComment(id: string): Promise<ApiResult>;
48
+ /**
49
+ * Delete a page
50
+ */
51
+ deleteContent(pageId: string): Promise<ApiResult>;
52
+ /**
53
+ * Download attachment from a page
54
+ */
55
+ downloadAttachment(attachmentId: string, outputPath?: string): Promise<ApiResult>;
56
+ /**
57
+ * Get or create Confluence client
58
+ */
59
+ getClient(): ConfluenceClient;
60
+ /**
61
+ * Get page details
62
+ */
63
+ getContent(pageId: string): Promise<ApiResult>;
64
+ /**
65
+ * Get space details
66
+ */
67
+ getSpace(spaceKey: string): Promise<ApiResult>;
68
+ /**
69
+ * List all spaces
70
+ */
71
+ listSpaces(): Promise<ApiResult>;
72
+ /**
73
+ * Search pages using CQL
74
+ */
75
+ searchContents(cql: string, limit?: number, expand?: string[]): Promise<ApiResult>;
76
+ /**
77
+ * Test Confluence API connection
78
+ */
79
+ testConnection(): Promise<ApiResult>;
80
+ /**
81
+ * Update a comment on a page
82
+ */
83
+ updateComment(commentId: string, body: string): Promise<ApiResult>;
84
+ /**
85
+ * Update an existing page
86
+ */
87
+ updateContent(pageId: string, fields: Record<string, unknown>): Promise<ApiResult>;
88
+ }
@@ -0,0 +1,447 @@
1
+ import { ConfluenceClient } from 'confluence.js';
2
+ import fs from 'fs-extra';
3
+ import { markdownToAdf } from 'marklassian';
4
+ import path from 'node:path';
5
+ /**
6
+ * Confluence API Utility
7
+ * Provides core Confluence API operations
8
+ */
9
+ export class ConniApi {
10
+ client;
11
+ config;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ /**
16
+ * Add an attachment to a page
17
+ */
18
+ async addAttachment(pageId, filePath) {
19
+ try {
20
+ if (!fs.existsSync(filePath)) {
21
+ return {
22
+ error: `File not found: ${filePath}`,
23
+ success: false,
24
+ };
25
+ }
26
+ const stats = fs.statSync(filePath);
27
+ const maxFileSizeBytes = 10 * 1024 * 1024; // 10MB
28
+ if (stats.size > maxFileSizeBytes) {
29
+ return {
30
+ error: `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds the 10MB limit`,
31
+ success: false,
32
+ };
33
+ }
34
+ const client = this.getClient();
35
+ const fileContent = fs.readFileSync(filePath);
36
+ const fileName = path.basename(filePath);
37
+ const response = await client.contentAttachments.createAttachments({
38
+ attachments: [
39
+ {
40
+ file: fileContent,
41
+ filename: fileName,
42
+ minorEdit: false,
43
+ },
44
+ ],
45
+ id: pageId,
46
+ });
47
+ return {
48
+ data: response,
49
+ success: true,
50
+ };
51
+ }
52
+ catch (error) {
53
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
54
+ return {
55
+ error: errorMessage,
56
+ success: false,
57
+ };
58
+ }
59
+ }
60
+ /**
61
+ * Add a comment to a page
62
+ */
63
+ async addComment(pageId, body) {
64
+ try {
65
+ const client = this.getClient();
66
+ // Convert Markdown body to Confluence ADF
67
+ // eslint-disable-next-line unicorn/prefer-string-replace-all
68
+ const bodyContent = markdownToAdf(body.replace(/\\n/g, '\n'));
69
+ const response = await client.content.createContent({
70
+ body: {
71
+ storage: {
72
+ representation: 'atlas_doc_format',
73
+ value: JSON.stringify(bodyContent),
74
+ },
75
+ },
76
+ container: {
77
+ id: pageId,
78
+ type: 'page',
79
+ },
80
+ space: { key: '' },
81
+ title: '',
82
+ type: 'comment',
83
+ });
84
+ return {
85
+ data: response,
86
+ success: true,
87
+ };
88
+ }
89
+ catch (error) {
90
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
91
+ return {
92
+ error: errorMessage,
93
+ success: false,
94
+ };
95
+ }
96
+ }
97
+ /**
98
+ * Clear client (for cleanup)
99
+ */
100
+ clearClients() {
101
+ this.client = undefined;
102
+ }
103
+ /**
104
+ * Create a new page
105
+ */
106
+ async createPage(fields) {
107
+ try {
108
+ const client = this.getClient();
109
+ // Convert Markdown body to Confluence ADF
110
+ // eslint-disable-next-line unicorn/prefer-string-replace-all
111
+ const bodyContent = markdownToAdf(fields.body.replace(/\\n/g, '\n'));
112
+ const spaceKey = fields.spaceKey;
113
+ const title = fields.title;
114
+ const parentId = fields.parentId;
115
+ const status = fields.status;
116
+ const contentBody = {
117
+ body: {
118
+ storage: {
119
+ representation: 'atlas_doc_format',
120
+ value: JSON.stringify(bodyContent),
121
+ },
122
+ },
123
+ parentId,
124
+ space: { key: spaceKey },
125
+ status,
126
+ title,
127
+ type: 'page',
128
+ };
129
+ const response = await client.content.createContent(contentBody);
130
+ return {
131
+ data: response,
132
+ success: true,
133
+ };
134
+ }
135
+ catch (error) {
136
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
137
+ return {
138
+ error: errorMessage,
139
+ success: false,
140
+ };
141
+ }
142
+ }
143
+ /**
144
+ * Delete a comment from a page
145
+ */
146
+ async deleteComment(id) {
147
+ try {
148
+ const client = this.getClient();
149
+ await client.content.deleteContent({ id });
150
+ return {
151
+ data: true,
152
+ success: true,
153
+ };
154
+ }
155
+ catch (error) {
156
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
157
+ return {
158
+ error: errorMessage,
159
+ success: false,
160
+ };
161
+ }
162
+ }
163
+ /**
164
+ * Delete a page
165
+ */
166
+ async deleteContent(pageId) {
167
+ try {
168
+ const client = this.getClient();
169
+ await client.content.deleteContent({ id: pageId });
170
+ return {
171
+ data: true,
172
+ success: true,
173
+ };
174
+ }
175
+ catch (error) {
176
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
177
+ return {
178
+ error: errorMessage,
179
+ success: false,
180
+ };
181
+ }
182
+ }
183
+ /**
184
+ * Download attachment from a page
185
+ */
186
+ async downloadAttachment(attachmentId, outputPath) {
187
+ try {
188
+ const client = this.getClient();
189
+ // Get attachment metadata
190
+ const attachment = await client.content.getContentById({
191
+ expand: ['container', 'metadata.mediaType', 'version'],
192
+ id: attachmentId,
193
+ });
194
+ const fileName = attachment.title || 'download';
195
+ const mediaType = attachment.metadata?.mediaType || 'application/octet-stream';
196
+ const containerId = attachment.container?.id;
197
+ if (!containerId) {
198
+ return {
199
+ error: `Attachment ${attachmentId} has no parent content`,
200
+ success: false,
201
+ };
202
+ }
203
+ const buffer = await client.contentAttachments.downloadAttachment({
204
+ attachmentId,
205
+ id: containerId,
206
+ });
207
+ const finalPath = outputPath || path.join(process.cwd(), fileName);
208
+ fs.writeFileSync(finalPath, buffer);
209
+ return {
210
+ data: {
211
+ attachmentId,
212
+ filename: fileName,
213
+ mimeType: mediaType,
214
+ savedTo: finalPath,
215
+ size: buffer.length,
216
+ },
217
+ success: true,
218
+ };
219
+ }
220
+ catch (error) {
221
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
222
+ return {
223
+ error: errorMessage,
224
+ success: false,
225
+ };
226
+ }
227
+ }
228
+ /**
229
+ * Get or create Confluence client
230
+ */
231
+ getClient() {
232
+ if (this.client) {
233
+ return this.client;
234
+ }
235
+ this.client = new ConfluenceClient({
236
+ authentication: {
237
+ basic: {
238
+ apiToken: this.config.apiToken,
239
+ email: this.config.email,
240
+ },
241
+ },
242
+ host: this.config.host,
243
+ });
244
+ return this.client;
245
+ }
246
+ /**
247
+ * Get page details
248
+ */
249
+ async getContent(pageId) {
250
+ try {
251
+ const client = this.getClient();
252
+ const page = await client.content.getContentById({
253
+ expand: ['body.storage', 'children.attachment', 'children.comment', 'space', 'version'],
254
+ id: pageId,
255
+ });
256
+ return {
257
+ data: page,
258
+ success: true,
259
+ };
260
+ }
261
+ catch (error) {
262
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
263
+ return {
264
+ error: errorMessage,
265
+ success: false,
266
+ };
267
+ }
268
+ }
269
+ /**
270
+ * Get space details
271
+ */
272
+ async getSpace(spaceKey) {
273
+ try {
274
+ const client = this.getClient();
275
+ const space = await client.space.getSpace({ spaceKey });
276
+ return {
277
+ data: space,
278
+ success: true,
279
+ };
280
+ }
281
+ catch (error) {
282
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
283
+ return {
284
+ error: errorMessage,
285
+ success: false,
286
+ };
287
+ }
288
+ }
289
+ /**
290
+ * List all spaces
291
+ */
292
+ async listSpaces() {
293
+ try {
294
+ const client = this.getClient();
295
+ const response = await client.space.getSpaces();
296
+ const spaces = response.results || [];
297
+ const simplifiedSpaces = spaces.map((s) => ({
298
+ id: String(s.id),
299
+ key: s.key,
300
+ name: s.name,
301
+ type: s.type,
302
+ }));
303
+ return {
304
+ data: simplifiedSpaces,
305
+ success: true,
306
+ };
307
+ }
308
+ catch (error) {
309
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
310
+ return {
311
+ error: errorMessage,
312
+ success: false,
313
+ };
314
+ }
315
+ }
316
+ /**
317
+ * Search pages using CQL
318
+ */
319
+ async searchContents(cql, limit = 10, expand) {
320
+ try {
321
+ const client = this.getClient();
322
+ const response = await client.content.searchContentByCQL({
323
+ cql,
324
+ expand,
325
+ limit,
326
+ });
327
+ return {
328
+ data: response,
329
+ success: true,
330
+ };
331
+ }
332
+ catch (error) {
333
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
334
+ return {
335
+ error: errorMessage,
336
+ success: false,
337
+ };
338
+ }
339
+ }
340
+ /**
341
+ * Test Confluence API connection
342
+ */
343
+ async testConnection() {
344
+ try {
345
+ const client = this.getClient();
346
+ const currentUser = await client.users.getCurrentUser();
347
+ return {
348
+ data: { currentUser, serverInfo: {} },
349
+ success: true,
350
+ };
351
+ }
352
+ catch (error) {
353
+ return {
354
+ error: typeof error === 'object' ? String(error.message) : String(error),
355
+ success: false,
356
+ };
357
+ }
358
+ }
359
+ /**
360
+ * Update a comment on a page
361
+ */
362
+ async updateComment(commentId, body) {
363
+ try {
364
+ const client = this.getClient();
365
+ // Convert Markdown body to Confluence ADF
366
+ // eslint-disable-next-line unicorn/prefer-string-replace-all
367
+ const bodyContent = markdownToAdf(body.replace(/\\n/g, '\n'));
368
+ // Get current comment to find its version
369
+ const comment = await client.content.getContentById({
370
+ expand: ['version'],
371
+ id: commentId,
372
+ });
373
+ const currentVersion = (comment.version?.number ?? 0) + 1;
374
+ const response = await client.content.updateContent({
375
+ body: {
376
+ storage: {
377
+ representation: 'atlas_doc_format',
378
+ value: JSON.stringify(bodyContent),
379
+ },
380
+ },
381
+ id: commentId,
382
+ title: '',
383
+ type: 'comment',
384
+ version: {
385
+ number: currentVersion,
386
+ },
387
+ });
388
+ return {
389
+ data: response,
390
+ success: true,
391
+ };
392
+ }
393
+ catch (error) {
394
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
395
+ return {
396
+ error: errorMessage,
397
+ success: false,
398
+ };
399
+ }
400
+ }
401
+ /**
402
+ * Update an existing page
403
+ */
404
+ async updateContent(pageId, fields) {
405
+ try {
406
+ const client = this.getClient();
407
+ // Get current page to find its version
408
+ const page = await client.content.getContentById({
409
+ expand: ['version'],
410
+ id: pageId,
411
+ });
412
+ const currentVersion = (page.version?.number ?? 0) + 1;
413
+ const title = fields.title ?? page.title ?? '';
414
+ const body = fields.body;
415
+ const response = await client.content.updateContent({
416
+ id: pageId,
417
+ type: 'page',
418
+ ...(body === undefined
419
+ ? {}
420
+ : {
421
+ body: {
422
+ storage: {
423
+ representation: 'atlas_doc_format',
424
+ // eslint-disable-next-line unicorn/prefer-string-replace-all
425
+ value: JSON.stringify(markdownToAdf(body.replace(/\\n/g, '\n'))),
426
+ },
427
+ },
428
+ }),
429
+ title,
430
+ version: {
431
+ number: currentVersion,
432
+ },
433
+ });
434
+ return {
435
+ data: response,
436
+ success: true,
437
+ };
438
+ }
439
+ catch (error) {
440
+ const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
441
+ return {
442
+ error: errorMessage,
443
+ success: false,
444
+ };
445
+ }
446
+ }
447
+ }
@@ -0,0 +1,88 @@
1
+ import type { ApiResult, Config } from './conni-api.js';
2
+ /**
3
+ * List all spaces
4
+ * @param config - Confluence configuration
5
+ */
6
+ export declare function listSpaces(config: Config): Promise<ApiResult>;
7
+ /**
8
+ * Get space details
9
+ * @param config - Confluence configuration
10
+ * @param spaceKey - Space key
11
+ */
12
+ export declare function getSpace(config: Config, spaceKey: string): Promise<ApiResult>;
13
+ /**
14
+ * Search pages using CQL
15
+ * @param config - Confluence configuration
16
+ * @param cql - CQL query string
17
+ * @param limit - Maximum number of contents per page
18
+ * @param expand - Properties of the content to expand
19
+ */
20
+ export declare function searchContents(config: Config, cql: string, limit?: number, expand?: string[]): Promise<ApiResult>;
21
+ /**
22
+ * Get page details
23
+ * @param config - Confluence configuration
24
+ * @param pageId - Page ID
25
+ */
26
+ export declare function getContent(config: Config, pageId: string): Promise<ApiResult>;
27
+ /**
28
+ * Create a new page
29
+ * @param config - Confluence configuration
30
+ * @param fields - Page fields (spaceKey, title, body, parentId)
31
+ */
32
+ export declare function createPage(config: Config, fields: Record<string, unknown>): Promise<ApiResult>;
33
+ /**
34
+ * Update an existing page
35
+ * @param config - Confluence configuration
36
+ * @param pageId - Page ID
37
+ * @param fields - Page fields to update (title, body)
38
+ */
39
+ export declare function updateContent(config: Config, pageId: string, fields: Record<string, unknown>): Promise<ApiResult>;
40
+ /**
41
+ * Add an attachment to a page
42
+ * @param config - Confluence configuration
43
+ * @param pageId - Page ID
44
+ * @param filePath - Path to the file to upload
45
+ */
46
+ export declare function addAttachment(config: Config, pageId: string, filePath: string): Promise<ApiResult>;
47
+ /**
48
+ * Add a comment to a page
49
+ * @param config - Confluence configuration
50
+ * @param pageId - Page ID
51
+ * @param body - Comment body
52
+ */
53
+ export declare function addComment(config: Config, pageId: string, body: string): Promise<ApiResult>;
54
+ /**
55
+ * Delete a comment from a page
56
+ * @param config - Confluence configuration
57
+ * @param id - Comment ID
58
+ */
59
+ export declare function deleteComment(config: Config, id: string): Promise<ApiResult>;
60
+ /**
61
+ * Update a comment on a page
62
+ * @param config - Confluence configuration
63
+ * @param id - Comment ID
64
+ * @param body - Comment body
65
+ */
66
+ export declare function updateComment(config: Config, id: string, body: string): Promise<ApiResult>;
67
+ /**
68
+ * Delete a page
69
+ * @param config - Confluence configuration
70
+ * @param pageId - Page ID
71
+ */
72
+ export declare function deleteContent(config: Config, pageId: string): Promise<ApiResult>;
73
+ /**
74
+ * Test Confluence API connection
75
+ * @param config - Confluence configuration
76
+ */
77
+ export declare function testConnection(config: Config): Promise<ApiResult>;
78
+ /**
79
+ * Clear clients (for cleanup)
80
+ */
81
+ export declare function clearClients(): void;
82
+ /**
83
+ * Download attachment from a page
84
+ * @param config - Confluence configuration
85
+ * @param attachmentId - Attachment ID
86
+ * @param outputPath - Output file path (optional)
87
+ */
88
+ export declare function downloadAttachment(config: Config, attachmentId: string, outputPath?: string): Promise<ApiResult>;