@hesed/conni 0.3.1 → 0.5.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.
- package/README.md +37 -28
- package/dist/commands/conni/content/create.d.ts +2 -0
- package/dist/commands/conni/content/create.js +28 -5
- package/dist/conni/conni-api.d.ts +13 -0
- package/dist/conni/conni-api.js +143 -27
- package/dist/conni/conni-client.d.ts +7 -0
- package/dist/conni/conni-client.js +10 -0
- package/oclif.manifest.json +100 -82
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ $ npm install -g @hesed/conni
|
|
|
26
26
|
$ conni COMMAND
|
|
27
27
|
running command...
|
|
28
28
|
$ conni (--version)
|
|
29
|
-
@hesed/conni/0.
|
|
29
|
+
@hesed/conni/0.5.0 linux-x64 node-v24.14.1
|
|
30
30
|
$ conni --help [COMMAND]
|
|
31
31
|
USAGE
|
|
32
32
|
$ conni COMMAND
|
|
@@ -59,12 +59,12 @@ Add Atlassian authentication
|
|
|
59
59
|
|
|
60
60
|
```
|
|
61
61
|
USAGE
|
|
62
|
-
$ conni conni auth add
|
|
62
|
+
$ conni conni auth add -e <value> -t <value> -u <value> [--json]
|
|
63
63
|
|
|
64
64
|
FLAGS
|
|
65
|
-
-e, --email=<value> Account email:
|
|
66
|
-
-t, --token=<value> API Token:
|
|
67
|
-
-u, --url=<value> Atlassian URL (start with https://):
|
|
65
|
+
-e, --email=<value> (required) Account email:
|
|
66
|
+
-t, --token=<value> (required) API Token:
|
|
67
|
+
-u, --url=<value> (required) Atlassian URL (start with https://):
|
|
68
68
|
|
|
69
69
|
GLOBAL FLAGS
|
|
70
70
|
--json Format output as json.
|
|
@@ -76,7 +76,7 @@ EXAMPLES
|
|
|
76
76
|
$ conni conni auth add
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
_See code: [src/commands/conni/auth/add.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
79
|
+
_See code: [src/commands/conni/auth/add.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/auth/add.ts)_
|
|
80
80
|
|
|
81
81
|
## `conni conni auth test`
|
|
82
82
|
|
|
@@ -96,7 +96,7 @@ EXAMPLES
|
|
|
96
96
|
$ conni conni auth test
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
_See code: [src/commands/conni/auth/test.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
99
|
+
_See code: [src/commands/conni/auth/test.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/auth/test.ts)_
|
|
100
100
|
|
|
101
101
|
## `conni conni auth update`
|
|
102
102
|
|
|
@@ -104,12 +104,12 @@ Update existing authentication
|
|
|
104
104
|
|
|
105
105
|
```
|
|
106
106
|
USAGE
|
|
107
|
-
$ conni conni auth update
|
|
107
|
+
$ conni conni auth update -e <value> -t <value> -u <value> [--json]
|
|
108
108
|
|
|
109
109
|
FLAGS
|
|
110
|
-
-e, --email=<value> Account email
|
|
111
|
-
-t, --token=<value> API Token
|
|
112
|
-
-u, --url=<value> Atlassian instance URL (start with https://)
|
|
110
|
+
-e, --email=<value> (required) Account email
|
|
111
|
+
-t, --token=<value> (required) API Token
|
|
112
|
+
-u, --url=<value> (required) Atlassian instance URL (start with https://)
|
|
113
113
|
|
|
114
114
|
GLOBAL FLAGS
|
|
115
115
|
--json Format output as json.
|
|
@@ -121,7 +121,7 @@ EXAMPLES
|
|
|
121
121
|
$ conni conni auth update
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
_See code: [src/commands/conni/auth/update.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
124
|
+
_See code: [src/commands/conni/auth/update.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/auth/update.ts)_
|
|
125
125
|
|
|
126
126
|
## `conni conni content attachment PAGEID FILE`
|
|
127
127
|
|
|
@@ -145,7 +145,7 @@ EXAMPLES
|
|
|
145
145
|
$ conni conni content attachment 123456 ./document.pdf
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
_See code: [src/commands/conni/content/attachment.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
148
|
+
_See code: [src/commands/conni/content/attachment.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/attachment.ts)_
|
|
149
149
|
|
|
150
150
|
## `conni conni content attachment-download ATTACHMENTID [OUTPUTPATH]`
|
|
151
151
|
|
|
@@ -171,7 +171,7 @@ EXAMPLES
|
|
|
171
171
|
$ conni conni content attachment-download att12345 ./document.pdf
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
_See code: [src/commands/conni/content/attachment-download.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
174
|
+
_See code: [src/commands/conni/content/attachment-download.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/attachment-download.ts)_
|
|
175
175
|
|
|
176
176
|
## `conni conni content comment PAGEID BODY`
|
|
177
177
|
|
|
@@ -204,7 +204,7 @@ EXAMPLES
|
|
|
204
204
|
$ conni conni content comment 123456 "$(cat content.md)"
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
_See code: [src/commands/conni/content/comment.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
207
|
+
_See code: [src/commands/conni/content/comment.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/comment.ts)_
|
|
208
208
|
|
|
209
209
|
## `conni conni content comment-delete ID`
|
|
210
210
|
|
|
@@ -227,7 +227,7 @@ EXAMPLES
|
|
|
227
227
|
$ conni conni content comment-delete 1544224770
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
-
_See code: [src/commands/conni/content/comment-delete.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
230
|
+
_See code: [src/commands/conni/content/comment-delete.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/comment-delete.ts)_
|
|
231
231
|
|
|
232
232
|
## `conni conni content comment-update ID BODY`
|
|
233
233
|
|
|
@@ -260,7 +260,7 @@ EXAMPLES
|
|
|
260
260
|
$ conni conni content comment-update 1544224770 "$(cat content.md)"
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
_See code: [src/commands/conni/content/comment-update.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
263
|
+
_See code: [src/commands/conni/content/comment-update.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/comment-update.ts)_
|
|
264
264
|
|
|
265
265
|
## `conni conni content create`
|
|
266
266
|
|
|
@@ -268,10 +268,12 @@ Create a new Confluence page
|
|
|
268
268
|
|
|
269
269
|
```
|
|
270
270
|
USAGE
|
|
271
|
-
$ conni conni content create --fields <value>... [--toon]
|
|
271
|
+
$ conni conni content create --fields <value>... [--attach <value>...] [--full-width] [--toon]
|
|
272
272
|
|
|
273
273
|
FLAGS
|
|
274
|
-
--
|
|
274
|
+
--attach=<value>... Path to a file to upload and embed inline (can be used multiple times)
|
|
275
|
+
--fields=<value>... (required) Minimum fields required: spaceKey, title & body
|
|
276
|
+
--full-width Set page appearance to full-width
|
|
275
277
|
--toon Format output as toon
|
|
276
278
|
|
|
277
279
|
DESCRIPTION
|
|
@@ -291,13 +293,20 @@ EXAMPLES
|
|
|
291
293
|
|
|
292
294
|
$ conni conni content create --fields spaceKey="DEV" title="Child page" body="Content" parentId="123456"
|
|
293
295
|
|
|
296
|
+
$ conni conni content create --fields spaceKey="DEV" title="Page with image" body="See the diagram:
|
|
297
|
+
" --attach ./diagram.png
|
|
298
|
+
|
|
299
|
+
$ conni conni content create --fields spaceKey="DEV" title="Page with files" body="Content" --attach ./image.png --attach ./report.pdf
|
|
300
|
+
|
|
301
|
+
$ conni conni content create --fields spaceKey="DEV" title="Storage page" body=@storage.xml representation=storage --full-width
|
|
302
|
+
|
|
294
303
|
FLAG DESCRIPTIONS
|
|
295
|
-
--fields=<value>...
|
|
304
|
+
--fields=<value>... Minimum fields required: spaceKey, title & body
|
|
296
305
|
|
|
297
|
-
|
|
306
|
+
Content fields in key=value format. Use @file to read value from a file (e.g. body=@content.xml)
|
|
298
307
|
```
|
|
299
308
|
|
|
300
|
-
_See code: [src/commands/conni/content/create.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
309
|
+
_See code: [src/commands/conni/content/create.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/create.ts)_
|
|
301
310
|
|
|
302
311
|
## `conni conni content delete PAGEID`
|
|
303
312
|
|
|
@@ -320,7 +329,7 @@ EXAMPLES
|
|
|
320
329
|
$ conni conni content delete 1543634992
|
|
321
330
|
```
|
|
322
331
|
|
|
323
|
-
_See code: [src/commands/conni/content/delete.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
332
|
+
_See code: [src/commands/conni/content/delete.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/delete.ts)_
|
|
324
333
|
|
|
325
334
|
## `conni conni content get PAGEID`
|
|
326
335
|
|
|
@@ -343,7 +352,7 @@ EXAMPLES
|
|
|
343
352
|
$ conni conni content get 1544060948
|
|
344
353
|
```
|
|
345
354
|
|
|
346
|
-
_See code: [src/commands/conni/content/get.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
355
|
+
_See code: [src/commands/conni/content/get.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/get.ts)_
|
|
347
356
|
|
|
348
357
|
## `conni conni content search CQL`
|
|
349
358
|
|
|
@@ -370,7 +379,7 @@ EXAMPLES
|
|
|
370
379
|
$ conni conni content search 'created > startOfMonth()' --limit=5 --expand=body,version
|
|
371
380
|
```
|
|
372
381
|
|
|
373
|
-
_See code: [src/commands/conni/content/search.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
382
|
+
_See code: [src/commands/conni/content/search.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/search.ts)_
|
|
374
383
|
|
|
375
384
|
## `conni conni content update PAGEID`
|
|
376
385
|
|
|
@@ -404,7 +413,7 @@ EXAMPLES
|
|
|
404
413
|
$ conni conni content update 1076199489 --fields body="$(cat content.md)"
|
|
405
414
|
```
|
|
406
415
|
|
|
407
|
-
_See code: [src/commands/conni/content/update.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
416
|
+
_See code: [src/commands/conni/content/update.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/content/update.ts)_
|
|
408
417
|
|
|
409
418
|
## `conni conni space get SPACEKEY`
|
|
410
419
|
|
|
@@ -427,7 +436,7 @@ EXAMPLES
|
|
|
427
436
|
$ conni conni space get DEV
|
|
428
437
|
```
|
|
429
438
|
|
|
430
|
-
_See code: [src/commands/conni/space/get.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
439
|
+
_See code: [src/commands/conni/space/get.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/space/get.ts)_
|
|
431
440
|
|
|
432
441
|
## `conni conni space list`
|
|
433
442
|
|
|
@@ -447,5 +456,5 @@ EXAMPLES
|
|
|
447
456
|
$ conni conni space list
|
|
448
457
|
```
|
|
449
458
|
|
|
450
|
-
_See code: [src/commands/conni/space/list.ts](https://github.com/hesedcasa/conni/blob/v0.
|
|
459
|
+
_See code: [src/commands/conni/space/list.ts](https://github.com/hesedcasa/conni/blob/v0.5.0/src/commands/conni/space/list.ts)_
|
|
451
460
|
<!-- commandsstop -->
|
|
@@ -4,7 +4,9 @@ export default class ContentCreate extends Command {
|
|
|
4
4
|
static description: string;
|
|
5
5
|
static examples: string[];
|
|
6
6
|
static flags: {
|
|
7
|
+
attach: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
fields: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'full-width': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
10
|
toon: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
11
|
};
|
|
10
12
|
run(): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import fs from 'fs-extra';
|
|
2
3
|
import { readConfig } from '../../../config.js';
|
|
3
|
-
import { clearClients, createPage } from '../../../conni/conni-client.js';
|
|
4
|
+
import { clearClients, createPage, createPageWithMedia } from '../../../conni/conni-client.js';
|
|
4
5
|
import { formatAsToon } from '../../../format.js';
|
|
5
6
|
export default class ContentCreate extends Command {
|
|
6
7
|
static args = {};
|
|
@@ -9,13 +10,25 @@ export default class ContentCreate extends Command {
|
|
|
9
10
|
'<%= config.bin %> <%= command.id %> --fields spaceKey="DEV" title="New title" body="New description" status="draft"',
|
|
10
11
|
'<%= config.bin %> <%= command.id %> --fields spaceKey="DEV" title="New title" body=\'\n# Header\n## Sub-header\n- Item 1\n- Item 2\n```bash\nls -a\n```\'',
|
|
11
12
|
'<%= config.bin %> <%= command.id %> --fields spaceKey="DEV" title="Child page" body="Content" parentId="123456"',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --fields spaceKey="DEV" title="Page with image" body="See the diagram:\n" --attach ./diagram.png',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --fields spaceKey="DEV" title="Page with files" body="Content" --attach ./image.png --attach ./report.pdf',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --fields spaceKey="DEV" title="Storage page" body=@storage.xml representation=storage --full-width',
|
|
12
16
|
];
|
|
13
17
|
static flags = {
|
|
18
|
+
attach: Flags.string({
|
|
19
|
+
description: 'Path to a file to upload and embed inline (can be used multiple times)',
|
|
20
|
+
multiple: true,
|
|
21
|
+
required: false,
|
|
22
|
+
}),
|
|
14
23
|
fields: Flags.string({
|
|
15
|
-
description: '
|
|
24
|
+
description: 'Content fields in key=value format. Use @file to read value from a file (e.g. body=@content.xml)',
|
|
16
25
|
multiple: true,
|
|
17
26
|
required: true,
|
|
18
|
-
summary: '
|
|
27
|
+
summary: 'Minimum fields required: spaceKey, title & body',
|
|
28
|
+
}),
|
|
29
|
+
'full-width': Flags.boolean({
|
|
30
|
+
description: 'Set page appearance to full-width',
|
|
31
|
+
required: false,
|
|
19
32
|
}),
|
|
20
33
|
toon: Flags.boolean({ description: 'Format output as toon', required: false }),
|
|
21
34
|
};
|
|
@@ -29,7 +42,12 @@ export default class ContentCreate extends Command {
|
|
|
29
42
|
if (flags.fields) {
|
|
30
43
|
for (const field of flags.fields) {
|
|
31
44
|
const [key, ...valueParts] = field.split('=');
|
|
32
|
-
|
|
45
|
+
let value = valueParts.join('=');
|
|
46
|
+
// Support @file syntax to read value from a file
|
|
47
|
+
if (value.startsWith('@')) {
|
|
48
|
+
const filePath = value.slice(1);
|
|
49
|
+
value = fs.readFileSync(filePath, 'utf8');
|
|
50
|
+
}
|
|
33
51
|
fields[key] = value;
|
|
34
52
|
}
|
|
35
53
|
}
|
|
@@ -39,7 +57,12 @@ export default class ContentCreate extends Command {
|
|
|
39
57
|
this.error(`Required field "${required}" is missing`);
|
|
40
58
|
}
|
|
41
59
|
}
|
|
42
|
-
|
|
60
|
+
if (flags['full-width']) {
|
|
61
|
+
fields.fullWidth = 'true';
|
|
62
|
+
}
|
|
63
|
+
const result = flags.attach
|
|
64
|
+
? await createPageWithMedia(config.auth, fields, flags.attach)
|
|
65
|
+
: await createPage(config.auth, fields);
|
|
43
66
|
clearClients();
|
|
44
67
|
if (flags.toon) {
|
|
45
68
|
this.log(formatAsToon(result));
|
|
@@ -36,6 +36,12 @@ export declare class ConniApi {
|
|
|
36
36
|
* Create a new page
|
|
37
37
|
*/
|
|
38
38
|
createPage(fields: Record<string, unknown>): Promise<ApiResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Create a new page with inline media attachments.
|
|
41
|
+
* Creates the page first to obtain a page ID, then uploads attachments and
|
|
42
|
+
* patches the ADF body to embed them by file ID before updating the page.
|
|
43
|
+
*/
|
|
44
|
+
createPageWithMedia(fields: Record<string, unknown>, filePaths: string[]): Promise<ApiResult>;
|
|
39
45
|
/**
|
|
40
46
|
* Delete a comment from a page
|
|
41
47
|
*/
|
|
@@ -68,6 +74,10 @@ export declare class ConniApi {
|
|
|
68
74
|
* Search pages using CQL
|
|
69
75
|
*/
|
|
70
76
|
searchContents(cql: string, limit?: number, expand?: string[]): Promise<ApiResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Set page appearance (full-width or fixed-width)
|
|
79
|
+
*/
|
|
80
|
+
setPageAppearance(pageId: string, appearance: string): Promise<ApiResult>;
|
|
71
81
|
/**
|
|
72
82
|
* Test Confluence API connection
|
|
73
83
|
*/
|
|
@@ -80,4 +90,7 @@ export declare class ConniApi {
|
|
|
80
90
|
* Update an existing page
|
|
81
91
|
*/
|
|
82
92
|
updateContent(pageId: string, fields: Record<string, unknown>): Promise<ApiResult>;
|
|
93
|
+
private buildPageBody;
|
|
94
|
+
private collectExternalMedia;
|
|
95
|
+
private patchMediaNodes;
|
|
83
96
|
}
|
package/dist/conni/conni-api.js
CHANGED
|
@@ -106,38 +106,73 @@ export class ConniApi {
|
|
|
106
106
|
async createPage(fields) {
|
|
107
107
|
try {
|
|
108
108
|
const client = this.getClient();
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
109
|
+
const { contentPayload } = this.buildPageBody(fields);
|
|
110
|
+
const response = await client.content.createContent(contentPayload);
|
|
111
|
+
if (fields.fullWidth && response.id) {
|
|
112
|
+
await this.setPageAppearance(response.id, 'full-width');
|
|
113
|
+
}
|
|
114
|
+
return { data: response, success: true };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
|
|
118
|
+
return { error: errorMessage, success: false };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Create a new page with inline media attachments.
|
|
123
|
+
* Creates the page first to obtain a page ID, then uploads attachments and
|
|
124
|
+
* patches the ADF body to embed them by file ID before updating the page.
|
|
125
|
+
*/
|
|
126
|
+
async createPageWithMedia(fields, filePaths) {
|
|
127
|
+
try {
|
|
128
|
+
const client = this.getClient();
|
|
129
|
+
const { bodyContent, contentPayload } = this.buildPageBody(fields);
|
|
130
|
+
const { title } = contentPayload;
|
|
131
|
+
const externalMediaByBasename = new Map();
|
|
132
|
+
this.collectExternalMedia(bodyContent.content, externalMediaByBasename);
|
|
133
|
+
const inlinePaths = [];
|
|
134
|
+
const trailingPaths = [];
|
|
135
|
+
for (const f of filePaths) {
|
|
136
|
+
if (externalMediaByBasename.has(path.basename(f))) {
|
|
137
|
+
inlinePaths.push(f);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
trailingPaths.push(f);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Create the page first to get a page ID for attachment uploads.
|
|
144
|
+
const page = await client.content.createContent(contentPayload);
|
|
145
|
+
const pageId = page.id;
|
|
146
|
+
if (!pageId) {
|
|
147
|
+
return { error: 'Failed to get page ID from creation response', success: false };
|
|
148
|
+
}
|
|
149
|
+
const uploadResults = await Promise.all(filePaths.map((filePath) => this.addAttachment(pageId, filePath)));
|
|
150
|
+
const firstFailure = uploadResults.find((r) => !r.success);
|
|
151
|
+
if (firstFailure)
|
|
152
|
+
return firstFailure;
|
|
153
|
+
const fileInfoByPath = new Map();
|
|
154
|
+
for (const [i, filePath] of filePaths.entries()) {
|
|
155
|
+
const uploadData = uploadResults[i].data;
|
|
156
|
+
const att = uploadData?.results?.[0];
|
|
157
|
+
const fileId = att?.extensions?.fileId;
|
|
158
|
+
const collectionName = att?.extensions?.collectionName ?? '';
|
|
159
|
+
if (fileId) {
|
|
160
|
+
fileInfoByPath.set(filePath, { collection: collectionName, id: fileId });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
this.patchMediaNodes(bodyContent.content, inlinePaths, trailingPaths, fileInfoByPath, externalMediaByBasename);
|
|
164
|
+
const updatedPage = await client.content.updateContent({
|
|
165
|
+
body: { storage: { representation: 'atlas_doc_format', value: JSON.stringify(bodyContent) } },
|
|
166
|
+
id: pageId,
|
|
126
167
|
title,
|
|
127
168
|
type: 'page',
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
data: response,
|
|
132
|
-
success: true,
|
|
133
|
-
};
|
|
169
|
+
version: { number: 2 },
|
|
170
|
+
});
|
|
171
|
+
return { data: updatedPage, success: true };
|
|
134
172
|
}
|
|
135
173
|
catch (error) {
|
|
136
174
|
const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
|
|
137
|
-
return {
|
|
138
|
-
error: errorMessage,
|
|
139
|
-
success: false,
|
|
140
|
-
};
|
|
175
|
+
return { error: errorMessage, success: false };
|
|
141
176
|
}
|
|
142
177
|
}
|
|
143
178
|
/**
|
|
@@ -337,6 +372,24 @@ export class ConniApi {
|
|
|
337
372
|
};
|
|
338
373
|
}
|
|
339
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Set page appearance (full-width or fixed-width)
|
|
377
|
+
*/
|
|
378
|
+
async setPageAppearance(pageId, appearance) {
|
|
379
|
+
try {
|
|
380
|
+
const client = this.getClient();
|
|
381
|
+
await Promise.all(['content-appearance-published', 'content-appearance-draft'].map((key) => client.contentProperties.createContentProperty({
|
|
382
|
+
id: pageId,
|
|
383
|
+
key,
|
|
384
|
+
value: appearance,
|
|
385
|
+
})));
|
|
386
|
+
return { success: true };
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
const errorMessage = typeof error === 'object' ? String(error.message) : String(error);
|
|
390
|
+
return { error: errorMessage, success: false };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
340
393
|
/**
|
|
341
394
|
* Test Confluence API connection
|
|
342
395
|
*/
|
|
@@ -444,4 +497,67 @@ export class ConniApi {
|
|
|
444
497
|
};
|
|
445
498
|
}
|
|
446
499
|
}
|
|
500
|
+
buildPageBody(fields) {
|
|
501
|
+
const representation = fields.representation ?? 'atlas_doc_format';
|
|
502
|
+
const isStorage = representation === 'storage';
|
|
503
|
+
// eslint-disable-next-line unicorn/prefer-string-replace-all
|
|
504
|
+
const rawBody = fields.body.replace(/\\n/g, '\n');
|
|
505
|
+
const bodyContent = isStorage ? rawBody : markdownToAdf(rawBody);
|
|
506
|
+
const spaceKey = fields.spaceKey;
|
|
507
|
+
const title = fields.title;
|
|
508
|
+
const parentId = fields.parentId;
|
|
509
|
+
const status = fields.status;
|
|
510
|
+
return {
|
|
511
|
+
bodyContent,
|
|
512
|
+
contentPayload: {
|
|
513
|
+
ancestors: parentId ? [{ id: parentId }] : undefined,
|
|
514
|
+
body: { storage: { representation, value: isStorage ? rawBody : JSON.stringify(bodyContent) } },
|
|
515
|
+
space: { key: spaceKey },
|
|
516
|
+
status,
|
|
517
|
+
title,
|
|
518
|
+
type: 'page',
|
|
519
|
+
},
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
collectExternalMedia(nodes, map) {
|
|
523
|
+
for (const node of nodes) {
|
|
524
|
+
const content = node.content;
|
|
525
|
+
const media = node.type === 'mediaSingle' ? content?.[0] : undefined;
|
|
526
|
+
const attrs = media?.type === 'media' ? media.attrs : undefined;
|
|
527
|
+
if (attrs?.type === 'external' && typeof attrs.url === 'string') {
|
|
528
|
+
const base = path.basename(attrs.url);
|
|
529
|
+
if (!map.has(base))
|
|
530
|
+
map.set(base, []);
|
|
531
|
+
map.get(base).push(attrs);
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
if (content)
|
|
535
|
+
this.collectExternalMedia(content, map);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/* eslint-disable max-params */
|
|
539
|
+
patchMediaNodes(bodyNodes, inlinePaths, trailingPaths, fileInfoByPath, externalMediaByBasename) {
|
|
540
|
+
for (const filePath of inlinePaths) {
|
|
541
|
+
const info = fileInfoByPath.get(filePath);
|
|
542
|
+
if (!info)
|
|
543
|
+
continue;
|
|
544
|
+
for (const attrs of externalMediaByBasename.get(path.basename(filePath)) ?? []) {
|
|
545
|
+
delete attrs.url;
|
|
546
|
+
delete attrs.alt;
|
|
547
|
+
attrs.collection = info.collection;
|
|
548
|
+
attrs.id = info.id;
|
|
549
|
+
attrs.type = 'file';
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
for (const filePath of trailingPaths) {
|
|
553
|
+
const info = fileInfoByPath.get(filePath);
|
|
554
|
+
if (!info)
|
|
555
|
+
continue;
|
|
556
|
+
bodyNodes.push({
|
|
557
|
+
attrs: { layout: 'center' },
|
|
558
|
+
content: [{ attrs: { collection: info.collection, id: info.id, type: 'file' }, type: 'media' }],
|
|
559
|
+
type: 'mediaSingle',
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
447
563
|
}
|
|
@@ -30,6 +30,13 @@ export declare function getContent(config: Config, pageId: string): Promise<ApiR
|
|
|
30
30
|
* @param fields - Page fields (spaceKey, title, body, parentId)
|
|
31
31
|
*/
|
|
32
32
|
export declare function createPage(config: Config, fields: Record<string, unknown>): Promise<ApiResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Create a new page with inline media attachments
|
|
35
|
+
* @param config - Confluence configuration
|
|
36
|
+
* @param fields - Page fields (spaceKey, title, body, parentId)
|
|
37
|
+
* @param filePaths - Local file paths to upload and embed inline
|
|
38
|
+
*/
|
|
39
|
+
export declare function createPageWithMedia(config: Config, fields: Record<string, unknown>, filePaths: string[]): Promise<ApiResult>;
|
|
33
40
|
/**
|
|
34
41
|
* Update an existing page
|
|
35
42
|
* @param config - Confluence configuration
|
|
@@ -61,6 +61,16 @@ export async function createPage(config, fields) {
|
|
|
61
61
|
const conni = await initConni(config);
|
|
62
62
|
return conni.createPage(fields);
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a new page with inline media attachments
|
|
66
|
+
* @param config - Confluence configuration
|
|
67
|
+
* @param fields - Page fields (spaceKey, title, body, parentId)
|
|
68
|
+
* @param filePaths - Local file paths to upload and embed inline
|
|
69
|
+
*/
|
|
70
|
+
export async function createPageWithMedia(config, fields, filePaths) {
|
|
71
|
+
const conni = await initConni(config);
|
|
72
|
+
return conni.createPageWithMedia(fields, filePaths);
|
|
73
|
+
}
|
|
64
74
|
/**
|
|
65
75
|
* Update an existing page
|
|
66
76
|
* @param config - Confluence configuration
|
package/oclif.manifest.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"char": "e",
|
|
20
20
|
"description": "Account email:",
|
|
21
21
|
"name": "email",
|
|
22
|
-
"required":
|
|
22
|
+
"required": true,
|
|
23
23
|
"hasDynamicHelp": false,
|
|
24
24
|
"multiple": false,
|
|
25
25
|
"type": "option"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"char": "t",
|
|
29
29
|
"description": "API Token:",
|
|
30
30
|
"name": "token",
|
|
31
|
-
"required":
|
|
31
|
+
"required": true,
|
|
32
32
|
"hasDynamicHelp": false,
|
|
33
33
|
"multiple": false,
|
|
34
34
|
"type": "option"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"char": "u",
|
|
38
38
|
"description": "Atlassian URL (start with https://):",
|
|
39
39
|
"name": "url",
|
|
40
|
-
"required":
|
|
40
|
+
"required": true,
|
|
41
41
|
"hasDynamicHelp": false,
|
|
42
42
|
"multiple": false,
|
|
43
43
|
"type": "option"
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"char": "e",
|
|
113
113
|
"description": "Account email",
|
|
114
114
|
"name": "email",
|
|
115
|
-
"required":
|
|
115
|
+
"required": true,
|
|
116
116
|
"hasDynamicHelp": false,
|
|
117
117
|
"multiple": false,
|
|
118
118
|
"type": "option"
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"char": "t",
|
|
122
122
|
"description": "API Token",
|
|
123
123
|
"name": "token",
|
|
124
|
-
"required":
|
|
124
|
+
"required": true,
|
|
125
125
|
"hasDynamicHelp": false,
|
|
126
126
|
"multiple": false,
|
|
127
127
|
"type": "option"
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"char": "u",
|
|
131
131
|
"description": "Atlassian instance URL (start with https://)",
|
|
132
132
|
"name": "url",
|
|
133
|
-
"required":
|
|
133
|
+
"required": true,
|
|
134
134
|
"hasDynamicHelp": false,
|
|
135
135
|
"multiple": false,
|
|
136
136
|
"type": "option"
|
|
@@ -153,6 +153,78 @@
|
|
|
153
153
|
"update.js"
|
|
154
154
|
]
|
|
155
155
|
},
|
|
156
|
+
"conni:space:get": {
|
|
157
|
+
"aliases": [],
|
|
158
|
+
"args": {
|
|
159
|
+
"spaceKey": {
|
|
160
|
+
"description": "Space key",
|
|
161
|
+
"name": "spaceKey",
|
|
162
|
+
"required": true
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"description": "Get details of a Confluence space",
|
|
166
|
+
"examples": [
|
|
167
|
+
"<%= config.bin %> <%= command.id %> DEV"
|
|
168
|
+
],
|
|
169
|
+
"flags": {
|
|
170
|
+
"toon": {
|
|
171
|
+
"description": "Format output as toon",
|
|
172
|
+
"name": "toon",
|
|
173
|
+
"required": false,
|
|
174
|
+
"allowNo": false,
|
|
175
|
+
"type": "boolean"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"hasDynamicHelp": false,
|
|
179
|
+
"hiddenAliases": [],
|
|
180
|
+
"id": "conni:space:get",
|
|
181
|
+
"pluginAlias": "@hesed/conni",
|
|
182
|
+
"pluginName": "@hesed/conni",
|
|
183
|
+
"pluginType": "core",
|
|
184
|
+
"strict": true,
|
|
185
|
+
"enableJsonFlag": false,
|
|
186
|
+
"isESM": true,
|
|
187
|
+
"relativePath": [
|
|
188
|
+
"dist",
|
|
189
|
+
"commands",
|
|
190
|
+
"conni",
|
|
191
|
+
"space",
|
|
192
|
+
"get.js"
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
"conni:space:list": {
|
|
196
|
+
"aliases": [],
|
|
197
|
+
"args": {},
|
|
198
|
+
"description": "List all Confluence spaces",
|
|
199
|
+
"examples": [
|
|
200
|
+
"<%= config.bin %> <%= command.id %>"
|
|
201
|
+
],
|
|
202
|
+
"flags": {
|
|
203
|
+
"toon": {
|
|
204
|
+
"description": "Format output as toon",
|
|
205
|
+
"name": "toon",
|
|
206
|
+
"required": false,
|
|
207
|
+
"allowNo": false,
|
|
208
|
+
"type": "boolean"
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"hasDynamicHelp": false,
|
|
212
|
+
"hiddenAliases": [],
|
|
213
|
+
"id": "conni:space:list",
|
|
214
|
+
"pluginAlias": "@hesed/conni",
|
|
215
|
+
"pluginName": "@hesed/conni",
|
|
216
|
+
"pluginType": "core",
|
|
217
|
+
"strict": true,
|
|
218
|
+
"enableJsonFlag": false,
|
|
219
|
+
"isESM": true,
|
|
220
|
+
"relativePath": [
|
|
221
|
+
"dist",
|
|
222
|
+
"commands",
|
|
223
|
+
"conni",
|
|
224
|
+
"space",
|
|
225
|
+
"list.js"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
156
228
|
"conni:content:attachment-download": {
|
|
157
229
|
"aliases": [],
|
|
158
230
|
"args": {
|
|
@@ -378,18 +450,36 @@
|
|
|
378
450
|
"examples": [
|
|
379
451
|
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"New title\" body=\"New description\" status=\"draft\"",
|
|
380
452
|
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"New title\" body='\n# Header\n## Sub-header\n- Item 1\n- Item 2\n```bash\nls -a\n```'",
|
|
381
|
-
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"Child page\" body=\"Content\" parentId=\"123456\""
|
|
453
|
+
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"Child page\" body=\"Content\" parentId=\"123456\"",
|
|
454
|
+
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"Page with image\" body=\"See the diagram:\n\" --attach ./diagram.png",
|
|
455
|
+
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"Page with files\" body=\"Content\" --attach ./image.png --attach ./report.pdf",
|
|
456
|
+
"<%= config.bin %> <%= command.id %> --fields spaceKey=\"DEV\" title=\"Storage page\" body=@storage.xml representation=storage --full-width"
|
|
382
457
|
],
|
|
383
458
|
"flags": {
|
|
459
|
+
"attach": {
|
|
460
|
+
"description": "Path to a file to upload and embed inline (can be used multiple times)",
|
|
461
|
+
"name": "attach",
|
|
462
|
+
"required": false,
|
|
463
|
+
"hasDynamicHelp": false,
|
|
464
|
+
"multiple": true,
|
|
465
|
+
"type": "option"
|
|
466
|
+
},
|
|
384
467
|
"fields": {
|
|
385
|
-
"description": "
|
|
468
|
+
"description": "Content fields in key=value format. Use @file to read value from a file (e.g. body=@content.xml)",
|
|
386
469
|
"name": "fields",
|
|
387
470
|
"required": true,
|
|
388
|
-
"summary": "
|
|
471
|
+
"summary": "Minimum fields required: spaceKey, title & body",
|
|
389
472
|
"hasDynamicHelp": false,
|
|
390
473
|
"multiple": true,
|
|
391
474
|
"type": "option"
|
|
392
475
|
},
|
|
476
|
+
"full-width": {
|
|
477
|
+
"description": "Set page appearance to full-width",
|
|
478
|
+
"name": "full-width",
|
|
479
|
+
"required": false,
|
|
480
|
+
"allowNo": false,
|
|
481
|
+
"type": "boolean"
|
|
482
|
+
},
|
|
393
483
|
"toon": {
|
|
394
484
|
"description": "Format output as toon",
|
|
395
485
|
"name": "toon",
|
|
@@ -590,79 +680,7 @@
|
|
|
590
680
|
"content",
|
|
591
681
|
"update.js"
|
|
592
682
|
]
|
|
593
|
-
},
|
|
594
|
-
"conni:space:get": {
|
|
595
|
-
"aliases": [],
|
|
596
|
-
"args": {
|
|
597
|
-
"spaceKey": {
|
|
598
|
-
"description": "Space key",
|
|
599
|
-
"name": "spaceKey",
|
|
600
|
-
"required": true
|
|
601
|
-
}
|
|
602
|
-
},
|
|
603
|
-
"description": "Get details of a Confluence space",
|
|
604
|
-
"examples": [
|
|
605
|
-
"<%= config.bin %> <%= command.id %> DEV"
|
|
606
|
-
],
|
|
607
|
-
"flags": {
|
|
608
|
-
"toon": {
|
|
609
|
-
"description": "Format output as toon",
|
|
610
|
-
"name": "toon",
|
|
611
|
-
"required": false,
|
|
612
|
-
"allowNo": false,
|
|
613
|
-
"type": "boolean"
|
|
614
|
-
}
|
|
615
|
-
},
|
|
616
|
-
"hasDynamicHelp": false,
|
|
617
|
-
"hiddenAliases": [],
|
|
618
|
-
"id": "conni:space:get",
|
|
619
|
-
"pluginAlias": "@hesed/conni",
|
|
620
|
-
"pluginName": "@hesed/conni",
|
|
621
|
-
"pluginType": "core",
|
|
622
|
-
"strict": true,
|
|
623
|
-
"enableJsonFlag": false,
|
|
624
|
-
"isESM": true,
|
|
625
|
-
"relativePath": [
|
|
626
|
-
"dist",
|
|
627
|
-
"commands",
|
|
628
|
-
"conni",
|
|
629
|
-
"space",
|
|
630
|
-
"get.js"
|
|
631
|
-
]
|
|
632
|
-
},
|
|
633
|
-
"conni:space:list": {
|
|
634
|
-
"aliases": [],
|
|
635
|
-
"args": {},
|
|
636
|
-
"description": "List all Confluence spaces",
|
|
637
|
-
"examples": [
|
|
638
|
-
"<%= config.bin %> <%= command.id %>"
|
|
639
|
-
],
|
|
640
|
-
"flags": {
|
|
641
|
-
"toon": {
|
|
642
|
-
"description": "Format output as toon",
|
|
643
|
-
"name": "toon",
|
|
644
|
-
"required": false,
|
|
645
|
-
"allowNo": false,
|
|
646
|
-
"type": "boolean"
|
|
647
|
-
}
|
|
648
|
-
},
|
|
649
|
-
"hasDynamicHelp": false,
|
|
650
|
-
"hiddenAliases": [],
|
|
651
|
-
"id": "conni:space:list",
|
|
652
|
-
"pluginAlias": "@hesed/conni",
|
|
653
|
-
"pluginName": "@hesed/conni",
|
|
654
|
-
"pluginType": "core",
|
|
655
|
-
"strict": true,
|
|
656
|
-
"enableJsonFlag": false,
|
|
657
|
-
"isESM": true,
|
|
658
|
-
"relativePath": [
|
|
659
|
-
"dist",
|
|
660
|
-
"commands",
|
|
661
|
-
"conni",
|
|
662
|
-
"space",
|
|
663
|
-
"list.js"
|
|
664
|
-
]
|
|
665
683
|
}
|
|
666
684
|
},
|
|
667
|
-
"version": "0.
|
|
685
|
+
"version": "0.5.0"
|
|
668
686
|
}
|