confluence-exporter 1.0.4 → 1.0.5
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.
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<p>
|
|
2
|
+
<ac:structured-macro ac:name="children" ac:schema-version="2" ac:macro-id="7aaf9114-616b-461d-8da7-3ea099b1b543" />
|
|
3
|
+
</p>
|
|
4
|
+
<p><a href="https://confluence.fmr.com/pages/viewpage.action?pageId=560875531">Secondary Reach DevOps On Call</a></p>
|
|
5
|
+
<p><a href="https://confluence.fmr.com/display/AP001330/Batch+job+contacts">Batch Contacts</a></p>
|
package/agents.md
CHANGED
|
@@ -287,6 +287,9 @@ Displays usage information, options, and examples.
|
|
|
287
287
|
```bash
|
|
288
288
|
npm run dev -- index -u URL -n USER -p TOKEN -s SPACE -o ./output
|
|
289
289
|
|
|
290
|
+
# Index specific page and all children
|
|
291
|
+
npm run dev -- index -i PAGE_ID -u URL -n USER -p TOKEN -s SPACE -o ./output
|
|
292
|
+
|
|
290
293
|
# With limit (index only first 10 pages)
|
|
291
294
|
npm run dev -- index -u URL -n USER -p TOKEN -s SPACE -o ./output -l 10
|
|
292
295
|
```
|
|
@@ -294,13 +297,17 @@ npm run dev -- index -u URL -n USER -p TOKEN -s SPACE -o ./output -l 10
|
|
|
294
297
|
|
|
295
298
|
**Behavior:**
|
|
296
299
|
- Creates output directory if missing
|
|
297
|
-
- Streams all pages via `api.getAllPages()` (memory-efficient)
|
|
298
|
-
- Appends each page to `_index.yaml` as YAML array entry
|
|
299
|
-
- **Resume:** Automatically resumes from where it left off by calculating the start position from existing pages (does NOT re-fetch already-indexed pages)
|
|
300
|
+
- **Mode A (No pageId):** Streams all pages via `api.getAllPages()` (memory-efficient)
|
|
301
|
+
- Appends each page to `_index.yaml` as YAML array entry
|
|
302
|
+
- **Resume:** Automatically resumes from where it left off by calculating the start position from existing pages (does NOT re-fetch already-indexed pages)
|
|
303
|
+
- **Logging:** `[N] Indexed: Title (ID) [API Page N]`
|
|
304
|
+
- **Mode B (With pageId):** Fetches specific page and recursively fetches all children
|
|
305
|
+
- Creates fresh `_index.yaml` (no resume for specific page indexing)
|
|
306
|
+
- Uses `api.getPage()` and `api.getChildPages()` recursively
|
|
307
|
+
- **Logging:** `[N] Indexed: Title (ID)` (indented for hierarchy depth)
|
|
300
308
|
- **Limit:** If `--limit` is specified, stops after indexing that many pages
|
|
301
|
-
- **Logging:** `[N] Indexed: Title (ID) [API Page N]`
|
|
302
309
|
|
|
303
|
-
**Output:** `_index.yaml` with metadata for all pages in space
|
|
310
|
+
**Output:** `_index.yaml` with metadata for all pages in space or page tree
|
|
304
311
|
|
|
305
312
|
#### PlanCommand (`plan.command.ts`)
|
|
306
313
|
```bash
|
|
@@ -11,4 +11,9 @@ export declare class IndexCommand implements CommandHandler {
|
|
|
11
11
|
* Create _index.yaml file with all pages to download
|
|
12
12
|
*/
|
|
13
13
|
private createIndex;
|
|
14
|
+
/**
|
|
15
|
+
* Create _index.yaml from a specific page and all its children (recursive)
|
|
16
|
+
* Uses parallel fetching for better performance
|
|
17
|
+
*/
|
|
18
|
+
private createIndexFromPage;
|
|
14
19
|
}
|
|
@@ -14,11 +14,20 @@ export class IndexCommand {
|
|
|
14
14
|
const api = new ConfluenceApi(this.config);
|
|
15
15
|
// Create output directory if it doesn't exist
|
|
16
16
|
await fs.mkdir(this.config.outputDir, { recursive: true });
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
// Check if pageId is specified for specific page + children indexing
|
|
18
|
+
if (this.config.pageId) {
|
|
19
|
+
console.log(`Starting indexing of page: ${this.config.pageId} and its children`);
|
|
20
|
+
console.log(`Output directory: ${this.config.outputDir}\n`);
|
|
21
|
+
console.log('Creating _index.yaml for specific page tree...');
|
|
22
|
+
await this.createIndexFromPage(api, this.config);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(`Starting indexing of space: ${this.config.spaceKey}`);
|
|
26
|
+
console.log(`Output directory: ${this.config.outputDir}\n`);
|
|
27
|
+
// Phase 1: Create _index.yaml
|
|
28
|
+
console.log('Phase 1: Creating _index.yaml...');
|
|
29
|
+
await this.createIndex(api, this.config);
|
|
30
|
+
}
|
|
22
31
|
console.log(`\nIndexing complete!`);
|
|
23
32
|
console.log(`Index saved to: ${this.config.outputDir}/_index.yaml`);
|
|
24
33
|
}
|
|
@@ -91,5 +100,106 @@ export class IndexCommand {
|
|
|
91
100
|
console.log(`\n✓ Index created: ${indexPath}`);
|
|
92
101
|
console.log(` Total pages indexed: ${pageCount}`);
|
|
93
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Create _index.yaml from a specific page and all its children (recursive)
|
|
105
|
+
* Uses parallel fetching for better performance
|
|
106
|
+
*/
|
|
107
|
+
async createIndexFromPage(api, config) {
|
|
108
|
+
const indexPath = path.join(config.outputDir, '_index.yaml');
|
|
109
|
+
const parallelLimit = config.parallel || 5;
|
|
110
|
+
// Start fresh for specific page indexing
|
|
111
|
+
const header = `# Confluence Export Index
|
|
112
|
+
# Space: ${config.spaceKey}
|
|
113
|
+
# Root Page: ${config.pageId}
|
|
114
|
+
# Export Date: ${new Date().toISOString()}
|
|
115
|
+
|
|
116
|
+
`;
|
|
117
|
+
await fs.writeFile(indexPath, header, 'utf-8');
|
|
118
|
+
console.log(`Creating new index for page tree: ${config.pageId}...`);
|
|
119
|
+
console.log(`Using parallel fetching with concurrency: ${parallelLimit}\n`);
|
|
120
|
+
// Collect all pages first, then write to file
|
|
121
|
+
const allPages = [];
|
|
122
|
+
let limitReached = false;
|
|
123
|
+
// BFS approach with parallel fetching for better performance
|
|
124
|
+
const processLevel = async (pageIds, parentDepth) => {
|
|
125
|
+
if (pageIds.length === 0 || limitReached)
|
|
126
|
+
return [];
|
|
127
|
+
const depth = parentDepth + 1;
|
|
128
|
+
const nextLevelIds = [];
|
|
129
|
+
// Process pages in batches for parallel fetching
|
|
130
|
+
for (let i = 0; i < pageIds.length; i += parallelLimit) {
|
|
131
|
+
if (limitReached)
|
|
132
|
+
break;
|
|
133
|
+
const batch = pageIds.slice(i, i + parallelLimit);
|
|
134
|
+
// Fetch page details and children in parallel
|
|
135
|
+
const results = await Promise.all(batch.map(async (pageId) => {
|
|
136
|
+
const [page, children] = await Promise.all([
|
|
137
|
+
api.getPage(pageId),
|
|
138
|
+
api.getChildPages(pageId)
|
|
139
|
+
]);
|
|
140
|
+
return { page, children };
|
|
141
|
+
}));
|
|
142
|
+
// Process results
|
|
143
|
+
for (const { page, children } of results) {
|
|
144
|
+
if (limitReached)
|
|
145
|
+
break;
|
|
146
|
+
allPages.push({ page, depth });
|
|
147
|
+
console.log(`[${allPages.length}] Indexed: ${page.title} (${page.id})`);
|
|
148
|
+
// Check limit
|
|
149
|
+
if (config.limit && allPages.length >= config.limit) {
|
|
150
|
+
console.log(`\n⚠ Limit reached: ${config.limit} pages indexed`);
|
|
151
|
+
limitReached = true;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
// Collect child IDs for next level
|
|
155
|
+
nextLevelIds.push(...children.map(c => c.id));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return nextLevelIds;
|
|
159
|
+
};
|
|
160
|
+
// Start with the root page
|
|
161
|
+
const rootPage = await api.getPage(config.pageId);
|
|
162
|
+
allPages.push({ page: rootPage, depth: 0 });
|
|
163
|
+
console.log(`[${allPages.length}] Indexed: ${rootPage.title} (${rootPage.id})`);
|
|
164
|
+
if (config.limit && allPages.length >= config.limit) {
|
|
165
|
+
console.log(`\n⚠ Limit reached: ${config.limit} pages indexed`);
|
|
166
|
+
limitReached = true;
|
|
167
|
+
}
|
|
168
|
+
if (!limitReached) {
|
|
169
|
+
// Get children of root and process level by level
|
|
170
|
+
const rootChildren = await api.getChildPages(config.pageId);
|
|
171
|
+
let currentLevelIds = rootChildren.map(c => c.id);
|
|
172
|
+
let currentDepth = 0;
|
|
173
|
+
while (currentLevelIds.length > 0 && !limitReached) {
|
|
174
|
+
currentLevelIds = await processLevel(currentLevelIds, currentDepth);
|
|
175
|
+
currentDepth++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Write all pages to index file
|
|
179
|
+
console.log(`\nWriting ${allPages.length} pages to index...`);
|
|
180
|
+
for (const { page } of allPages) {
|
|
181
|
+
const pageEntry = {
|
|
182
|
+
id: page.id,
|
|
183
|
+
title: page.title,
|
|
184
|
+
version: page.version,
|
|
185
|
+
parentId: page.parentId,
|
|
186
|
+
modifiedDate: page.modifiedDate,
|
|
187
|
+
indexedDate: new Date().toISOString(),
|
|
188
|
+
pageNumber: 0 // Not applicable for specific page indexing
|
|
189
|
+
};
|
|
190
|
+
// Convert to YAML and format as array item
|
|
191
|
+
const yamlDoc = yaml.stringify(pageEntry).trim();
|
|
192
|
+
const lines = yamlDoc.split('\n');
|
|
193
|
+
const arrayItem = lines.map((line, index) => {
|
|
194
|
+
if (index === 0) {
|
|
195
|
+
return `- ${line}`;
|
|
196
|
+
}
|
|
197
|
+
return ` ${line}`;
|
|
198
|
+
}).join('\n');
|
|
199
|
+
await fs.appendFile(indexPath, arrayItem + '\n', 'utf-8');
|
|
200
|
+
}
|
|
201
|
+
console.log(`\n✓ Index created: ${indexPath}`);
|
|
202
|
+
console.log(` Total pages indexed: ${allPages.length}`);
|
|
203
|
+
}
|
|
94
204
|
}
|
|
95
205
|
//# sourceMappingURL=index.command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.command.js","sourceRoot":"","sources":["../../src/commands/index.command.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAI1C,MAAM,OAAO,YAAY;IACH;IAApB,YAAoB,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEhD,KAAK,CAAC,OAAO,CAAC,OAAuB;QACnC,MAAM,GAAG,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE3C,8CAA8C;QAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.command.js","sourceRoot":"","sources":["../../src/commands/index.command.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@ import { promises as fs } from 'fs';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import yaml from 'yaml';
|
|
8
8
|
import { ConfluenceApi } from '../api.js';
|
|
9
|
-
import type { ConfluenceConfig, PageIndexEntry } from '../types.js';
|
|
9
|
+
import type { ConfluenceConfig, PageIndexEntry, Page } from '../types.js';
|
|
10
10
|
import type { CommandContext, CommandHandler } from './types.js';
|
|
11
11
|
|
|
12
12
|
export class IndexCommand implements CommandHandler {
|
|
@@ -18,12 +18,21 @@ export class IndexCommand implements CommandHandler {
|
|
|
18
18
|
// Create output directory if it doesn't exist
|
|
19
19
|
await fs.mkdir(this.config.outputDir, { recursive: true });
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// Check if pageId is specified for specific page + children indexing
|
|
22
|
+
if (this.config.pageId) {
|
|
23
|
+
console.log(`Starting indexing of page: ${this.config.pageId} and its children`);
|
|
24
|
+
console.log(`Output directory: ${this.config.outputDir}\n`);
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
console.log('Creating _index.yaml for specific page tree...');
|
|
27
|
+
await this.createIndexFromPage(api, this.config);
|
|
28
|
+
} else {
|
|
29
|
+
console.log(`Starting indexing of space: ${this.config.spaceKey}`);
|
|
30
|
+
console.log(`Output directory: ${this.config.outputDir}\n`);
|
|
31
|
+
|
|
32
|
+
// Phase 1: Create _index.yaml
|
|
33
|
+
console.log('Phase 1: Creating _index.yaml...');
|
|
34
|
+
await this.createIndex(api, this.config);
|
|
35
|
+
}
|
|
27
36
|
|
|
28
37
|
console.log(`\nIndexing complete!`);
|
|
29
38
|
console.log(`Index saved to: ${this.config.outputDir}/_index.yaml`);
|
|
@@ -108,4 +117,125 @@ export class IndexCommand implements CommandHandler {
|
|
|
108
117
|
console.log(`\n✓ Index created: ${indexPath}`);
|
|
109
118
|
console.log(` Total pages indexed: ${pageCount}`);
|
|
110
119
|
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Create _index.yaml from a specific page and all its children (recursive)
|
|
123
|
+
* Uses parallel fetching for better performance
|
|
124
|
+
*/
|
|
125
|
+
private async createIndexFromPage(api: ConfluenceApi, config: CommandContext['config']): Promise<void> {
|
|
126
|
+
const indexPath = path.join(config.outputDir, '_index.yaml');
|
|
127
|
+
const parallelLimit = config.parallel || 5;
|
|
128
|
+
|
|
129
|
+
// Start fresh for specific page indexing
|
|
130
|
+
const header = `# Confluence Export Index
|
|
131
|
+
# Space: ${config.spaceKey}
|
|
132
|
+
# Root Page: ${config.pageId}
|
|
133
|
+
# Export Date: ${new Date().toISOString()}
|
|
134
|
+
|
|
135
|
+
`;
|
|
136
|
+
await fs.writeFile(indexPath, header, 'utf-8');
|
|
137
|
+
console.log(`Creating new index for page tree: ${config.pageId}...`);
|
|
138
|
+
console.log(`Using parallel fetching with concurrency: ${parallelLimit}\n`);
|
|
139
|
+
|
|
140
|
+
// Collect all pages first, then write to file
|
|
141
|
+
const allPages: Array<{ page: Page; depth: number }> = [];
|
|
142
|
+
let limitReached = false;
|
|
143
|
+
|
|
144
|
+
// BFS approach with parallel fetching for better performance
|
|
145
|
+
const processLevel = async (pageIds: string[], parentDepth: number): Promise<string[]> => {
|
|
146
|
+
if (pageIds.length === 0 || limitReached) return [];
|
|
147
|
+
|
|
148
|
+
const depth = parentDepth + 1;
|
|
149
|
+
const nextLevelIds: string[] = [];
|
|
150
|
+
|
|
151
|
+
// Process pages in batches for parallel fetching
|
|
152
|
+
for (let i = 0; i < pageIds.length; i += parallelLimit) {
|
|
153
|
+
if (limitReached) break;
|
|
154
|
+
|
|
155
|
+
const batch = pageIds.slice(i, i + parallelLimit);
|
|
156
|
+
|
|
157
|
+
// Fetch page details and children in parallel
|
|
158
|
+
const results = await Promise.all(
|
|
159
|
+
batch.map(async (pageId) => {
|
|
160
|
+
const [page, children] = await Promise.all([
|
|
161
|
+
api.getPage(pageId),
|
|
162
|
+
api.getChildPages(pageId)
|
|
163
|
+
]);
|
|
164
|
+
return { page, children };
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Process results
|
|
169
|
+
for (const { page, children } of results) {
|
|
170
|
+
if (limitReached) break;
|
|
171
|
+
|
|
172
|
+
allPages.push({ page, depth });
|
|
173
|
+
console.log(`[${allPages.length}] Indexed: ${page.title} (${page.id})`);
|
|
174
|
+
|
|
175
|
+
// Check limit
|
|
176
|
+
if (config.limit && allPages.length >= config.limit) {
|
|
177
|
+
console.log(`\n⚠ Limit reached: ${config.limit} pages indexed`);
|
|
178
|
+
limitReached = true;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Collect child IDs for next level
|
|
183
|
+
nextLevelIds.push(...children.map(c => c.id));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return nextLevelIds;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Start with the root page
|
|
191
|
+
const rootPage = await api.getPage(config.pageId!);
|
|
192
|
+
allPages.push({ page: rootPage, depth: 0 });
|
|
193
|
+
console.log(`[${allPages.length}] Indexed: ${rootPage.title} (${rootPage.id})`);
|
|
194
|
+
|
|
195
|
+
if (config.limit && allPages.length >= config.limit) {
|
|
196
|
+
console.log(`\n⚠ Limit reached: ${config.limit} pages indexed`);
|
|
197
|
+
limitReached = true;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!limitReached) {
|
|
201
|
+
// Get children of root and process level by level
|
|
202
|
+
const rootChildren = await api.getChildPages(config.pageId!);
|
|
203
|
+
let currentLevelIds = rootChildren.map(c => c.id);
|
|
204
|
+
let currentDepth = 0;
|
|
205
|
+
|
|
206
|
+
while (currentLevelIds.length > 0 && !limitReached) {
|
|
207
|
+
currentLevelIds = await processLevel(currentLevelIds, currentDepth);
|
|
208
|
+
currentDepth++;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Write all pages to index file
|
|
213
|
+
console.log(`\nWriting ${allPages.length} pages to index...`);
|
|
214
|
+
for (const { page } of allPages) {
|
|
215
|
+
const pageEntry: PageIndexEntry = {
|
|
216
|
+
id: page.id,
|
|
217
|
+
title: page.title,
|
|
218
|
+
version: page.version,
|
|
219
|
+
parentId: page.parentId,
|
|
220
|
+
modifiedDate: page.modifiedDate,
|
|
221
|
+
indexedDate: new Date().toISOString(),
|
|
222
|
+
pageNumber: 0 // Not applicable for specific page indexing
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Convert to YAML and format as array item
|
|
226
|
+
const yamlDoc = yaml.stringify(pageEntry).trim();
|
|
227
|
+
const lines = yamlDoc.split('\n');
|
|
228
|
+
const arrayItem = lines.map((line, index) => {
|
|
229
|
+
if (index === 0) {
|
|
230
|
+
return `- ${line}`;
|
|
231
|
+
}
|
|
232
|
+
return ` ${line}`;
|
|
233
|
+
}).join('\n');
|
|
234
|
+
|
|
235
|
+
await fs.appendFile(indexPath, arrayItem + '\n', 'utf-8');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
console.log(`\n✓ Index created: ${indexPath}`);
|
|
239
|
+
console.log(` Total pages indexed: ${allPages.length}`);
|
|
240
|
+
}
|
|
111
241
|
}
|