@moxn/kb-migrate 0.4.22 → 0.4.23
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/dist/sources/notion.d.ts +3 -1
- package/dist/sources/notion.js +59 -5
- package/package.json +1 -1
package/dist/sources/notion.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ExtractedDocument } from '../types.js';
|
|
11
11
|
import { MigrationSource, type SourceConfig } from './base.js';
|
|
12
|
-
import type { NotionPage } from './notion-api.js';
|
|
12
|
+
import type { NotionPage, NotionDatabase } from './notion-api.js';
|
|
13
13
|
import { type PagePathMap } from './notion-blocks.js';
|
|
14
14
|
import { type ParsedDatabaseSchema } from './notion-databases.js';
|
|
15
15
|
export interface NotionSourceConfig extends SourceConfig {
|
|
@@ -26,6 +26,7 @@ export interface PageTreeNode {
|
|
|
26
26
|
children: PageTreeNode[];
|
|
27
27
|
kbPath: string;
|
|
28
28
|
isDatabaseEntry: boolean;
|
|
29
|
+
isDatabaseNode?: boolean;
|
|
29
30
|
parentDatabaseId?: string;
|
|
30
31
|
}
|
|
31
32
|
/** Info yielded to the migration runner for database import (post-document pass). */
|
|
@@ -83,6 +84,7 @@ export declare class NotionSource extends MigrationSource<NotionSourceConfig> {
|
|
|
83
84
|
export interface BuildPageTreeOptions {
|
|
84
85
|
rootPageId?: string;
|
|
85
86
|
maxDepth?: number;
|
|
87
|
+
databases?: NotionDatabase[];
|
|
86
88
|
}
|
|
87
89
|
/** Result of building the page tree. */
|
|
88
90
|
export interface PageTreeResult {
|
package/dist/sources/notion.js
CHANGED
|
@@ -84,12 +84,12 @@ export class NotionSource extends MigrationSource {
|
|
|
84
84
|
console.log('Discovering databases...');
|
|
85
85
|
const allNotionDatabases = await this.client.searchDatabases();
|
|
86
86
|
console.log(` Found ${allNotionDatabases.length} databases.`);
|
|
87
|
-
// 4. Build page tree
|
|
88
|
-
this.buildPageTreeInternal(allNotionPages);
|
|
87
|
+
// 4. Build page tree (pass databases so they become tree nodes for nesting entries)
|
|
88
|
+
this.buildPageTreeInternal(allNotionPages, allNotionDatabases);
|
|
89
89
|
// 5. Process databases — identify entries and build schemas
|
|
90
90
|
await this.processDatabases(allNotionDatabases);
|
|
91
|
-
// 6. Count and validate
|
|
92
|
-
this._documentCount = this.allPages.length;
|
|
91
|
+
// 6. Count and validate (exclude synthetic database container nodes)
|
|
92
|
+
this._documentCount = this.allPages.filter((n) => !n.isDatabaseNode).length;
|
|
93
93
|
// Add database-only entries (pages that are in databases but not in page tree)
|
|
94
94
|
for (const dbInfo of this.databases) {
|
|
95
95
|
for (const entry of dbInfo.entries) {
|
|
@@ -141,6 +141,9 @@ export class NotionSource extends MigrationSource {
|
|
|
141
141
|
// unless they also appear in the page tree (child_page)
|
|
142
142
|
if (node.isDatabaseEntry)
|
|
143
143
|
continue;
|
|
144
|
+
// Skip synthetic database container nodes — they're for nesting, not documents
|
|
145
|
+
if (node.isDatabaseNode)
|
|
146
|
+
continue;
|
|
144
147
|
const doc = await this.extractPage(node);
|
|
145
148
|
if (doc)
|
|
146
149
|
yield doc;
|
|
@@ -171,10 +174,11 @@ export class NotionSource extends MigrationSource {
|
|
|
171
174
|
// ============================================
|
|
172
175
|
// Tree building (delegates to standalone function)
|
|
173
176
|
// ============================================
|
|
174
|
-
buildPageTreeInternal(pages) {
|
|
177
|
+
buildPageTreeInternal(pages, databases) {
|
|
175
178
|
const result = buildPageTree(pages, {
|
|
176
179
|
rootPageId: this.config.rootPageId,
|
|
177
180
|
maxDepth: this.config.maxDepth,
|
|
181
|
+
databases,
|
|
178
182
|
});
|
|
179
183
|
this.pageTree = result.tree;
|
|
180
184
|
this.allPages = result.allPages;
|
|
@@ -332,6 +336,7 @@ export function buildPageTree(pages, options) {
|
|
|
332
336
|
// Build lookup maps
|
|
333
337
|
const pageById = new Map();
|
|
334
338
|
const childrenByParent = new Map();
|
|
339
|
+
const syntheticDatabaseIds = new Set();
|
|
335
340
|
for (const page of pages) {
|
|
336
341
|
const nid = normalizeId(page.id);
|
|
337
342
|
pageById.set(nid, page);
|
|
@@ -344,6 +349,39 @@ export function buildPageTree(pages, options) {
|
|
|
344
349
|
childrenByParent.get(npid).push(page);
|
|
345
350
|
}
|
|
346
351
|
}
|
|
352
|
+
// Inject synthetic page nodes for databases so entries nest under them
|
|
353
|
+
if (options?.databases?.length) {
|
|
354
|
+
for (const db of options.databases) {
|
|
355
|
+
const dbNid = normalizeId(db.id);
|
|
356
|
+
// Skip if a real page already has this ID
|
|
357
|
+
if (pageById.has(dbNid))
|
|
358
|
+
continue;
|
|
359
|
+
// Create synthetic NotionPage wrapper
|
|
360
|
+
const syntheticPage = {
|
|
361
|
+
id: db.id,
|
|
362
|
+
object: 'page',
|
|
363
|
+
parent: db.parent,
|
|
364
|
+
created_time: db.created_time,
|
|
365
|
+
last_edited_time: db.last_edited_time,
|
|
366
|
+
created_by: { id: '', object: 'user' },
|
|
367
|
+
last_edited_by: { id: '', object: 'user' },
|
|
368
|
+
url: '',
|
|
369
|
+
properties: {
|
|
370
|
+
title: { id: 'title', type: 'title', title: db.title },
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
pageById.set(dbNid, syntheticPage);
|
|
374
|
+
// Add to childrenByParent
|
|
375
|
+
const parentId = getParentPageId(syntheticPage);
|
|
376
|
+
if (parentId) {
|
|
377
|
+
const npid = normalizeId(parentId);
|
|
378
|
+
if (!childrenByParent.has(npid))
|
|
379
|
+
childrenByParent.set(npid, []);
|
|
380
|
+
childrenByParent.get(npid).push(syntheticPage);
|
|
381
|
+
}
|
|
382
|
+
syntheticDatabaseIds.add(dbNid);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
347
385
|
// Identify database entries
|
|
348
386
|
for (const page of pages) {
|
|
349
387
|
if (page.parent.type === 'database_id' && page.parent.database_id) {
|
|
@@ -377,6 +415,19 @@ export function buildPageTree(pages, options) {
|
|
|
377
415
|
}
|
|
378
416
|
}
|
|
379
417
|
}
|
|
418
|
+
// Also add synthetic database nodes whose parent is workspace or not in the tree
|
|
419
|
+
for (const dbNid of syntheticDatabaseIds) {
|
|
420
|
+
const synth = pageById.get(dbNid);
|
|
421
|
+
if (synth.parent.type === 'workspace') {
|
|
422
|
+
rootPages.push(synth);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
const parentId = getParentPageId(synth);
|
|
426
|
+
if (parentId && !pageById.has(normalizeId(parentId))) {
|
|
427
|
+
rootPages.push(synth);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
380
431
|
}
|
|
381
432
|
// Build tree recursively
|
|
382
433
|
const buildNode = (page, parentPath, depth, siblingSlugCounts) => {
|
|
@@ -400,6 +451,7 @@ export function buildPageTree(pages, options) {
|
|
|
400
451
|
slug,
|
|
401
452
|
kbPath,
|
|
402
453
|
isDatabaseEntry,
|
|
454
|
+
isDatabaseNode: syntheticDatabaseIds.has(nid) || undefined,
|
|
403
455
|
parentDatabaseId: page.parent.type === 'database_id' ? page.parent.database_id : undefined,
|
|
404
456
|
children: [],
|
|
405
457
|
};
|
|
@@ -438,6 +490,8 @@ export function buildPageTree(pages, options) {
|
|
|
438
490
|
function getParentPageId(page) {
|
|
439
491
|
if (page.parent.type === 'page_id')
|
|
440
492
|
return page.parent.page_id ?? null;
|
|
493
|
+
if (page.parent.type === 'database_id')
|
|
494
|
+
return page.parent.database_id ?? null;
|
|
441
495
|
if (page.parent.type === 'block_id')
|
|
442
496
|
return page.parent.block_id ?? null;
|
|
443
497
|
return null;
|
package/package.json
CHANGED