@moxn/kb-migrate 0.4.41 → 0.6.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/dist/api-error.d.ts +7 -0
- package/dist/api-error.js +21 -0
- package/dist/blocks-to-grammar.d.ts +51 -0
- package/dist/blocks-to-grammar.js +133 -0
- package/dist/client-http.test.d.ts +1 -0
- package/dist/client-http.test.js +89 -0
- package/dist/client.d.ts +76 -3
- package/dist/client.js +180 -154
- package/dist/export.js +94 -4
- package/dist/export.test.js +121 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.js +16 -0
- package/dist/import-local.js +1 -0
- package/dist/import-local.test.js +96 -0
- package/dist/index.js +39 -12
- package/dist/migrate-document.test.js +100 -20
- package/dist/output.d.ts +17 -0
- package/dist/output.js +65 -0
- package/dist/output.test.d.ts +1 -0
- package/dist/output.test.js +59 -0
- package/dist/sources/onenote/__tests__/onenote-tree.test.d.ts +1 -0
- package/dist/sources/onenote/__tests__/onenote-tree.test.js +43 -0
- package/dist/targets/notion.js +3 -2
- package/dist/types.d.ts +6 -1
- package/package.json +3 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
2
|
import { MoxnClient } from './client.js';
|
|
3
|
+
import { sectionsToGrammarMarkdown, buildImportFrontMatter, blockToGrammar, } from './blocks-to-grammar.js';
|
|
3
4
|
/** Minimal fetch Response stand-in (client reads .ok/.status/.json()). */
|
|
4
5
|
function mockResponse(status, body) {
|
|
5
6
|
return {
|
|
@@ -25,22 +26,59 @@ function client() {
|
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
afterEach(() => vi.restoreAllMocks());
|
|
28
|
-
describe('migrateDocument —
|
|
29
|
-
it(
|
|
30
|
-
|
|
29
|
+
describe('migrateDocument — grammar-markdown import (write-surface Phase B)', () => {
|
|
30
|
+
it('serializes sections to grammar markdown and UPSERTs via import_markdown', async () => {
|
|
31
|
+
let importBody;
|
|
31
32
|
vi.spyOn(globalThis, 'fetch').mockImplementation((async (url, init) => {
|
|
32
33
|
const u = String(url);
|
|
33
34
|
const method = (init?.method ?? 'GET').toUpperCase();
|
|
34
|
-
if (method === 'POST' && u.endsWith('/api/v1/kb/
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
if (method === 'POST' && u.endsWith('/api/v1/kb/import')) {
|
|
36
|
+
importBody = JSON.parse(String(init?.body));
|
|
37
|
+
return mockResponse(200, {
|
|
38
|
+
result: {
|
|
39
|
+
id: 'doc-1',
|
|
40
|
+
path: '/runbook',
|
|
41
|
+
outcome: 'created',
|
|
42
|
+
existed: false,
|
|
43
|
+
name: 'Runbook',
|
|
44
|
+
frontMatterIgnored: false,
|
|
45
|
+
sectionIds: ['s1'],
|
|
46
|
+
branchId: 'br-1',
|
|
47
|
+
},
|
|
39
48
|
});
|
|
40
49
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
return mockResponse(200, {});
|
|
51
|
+
}));
|
|
52
|
+
const res = await client().migrateDocument(doc, '/', 'update', false);
|
|
53
|
+
expect(res.status).toBe('created');
|
|
54
|
+
expect(res.documentId).toBe('doc-1');
|
|
55
|
+
expect(res.branchId).toBe('br-1');
|
|
56
|
+
expect(res.sectionIds).toEqual(['s1']);
|
|
57
|
+
// POSITIVE wire assertion: the retired blocks payload is GONE; the body is
|
|
58
|
+
// grammar markdown with the name front-matter + H2 sections.
|
|
59
|
+
expect(importBody?.action).toBe('import_markdown');
|
|
60
|
+
const md = String(importBody?.markdown);
|
|
61
|
+
expect(md).toContain('name: "Runbook"');
|
|
62
|
+
expect(md).toContain('## Steps');
|
|
63
|
+
expect(md).toContain('body');
|
|
64
|
+
expect(importBody).not.toHaveProperty('sections');
|
|
65
|
+
});
|
|
66
|
+
it("maps the server's no-op re-import (outcome 'updated') to an updated result", async () => {
|
|
67
|
+
// The old client-side "No changes to commit" special-case moved server-side:
|
|
68
|
+
// import_markdown swallows the empty-commit rejection and reports 'updated'.
|
|
69
|
+
vi.spyOn(globalThis, 'fetch').mockImplementation((async (url, init) => {
|
|
70
|
+
const u = String(url);
|
|
71
|
+
const method = (init?.method ?? 'GET').toUpperCase();
|
|
72
|
+
if (method === 'POST' && u.endsWith('/api/v1/kb/import')) {
|
|
73
|
+
return mockResponse(200, {
|
|
74
|
+
result: {
|
|
75
|
+
id: 'doc-1',
|
|
76
|
+
path: '/runbook',
|
|
77
|
+
outcome: 'updated',
|
|
78
|
+
existed: true,
|
|
79
|
+
name: 'Runbook',
|
|
80
|
+
frontMatterIgnored: false,
|
|
81
|
+
},
|
|
44
82
|
});
|
|
45
83
|
}
|
|
46
84
|
return mockResponse(200, {});
|
|
@@ -49,22 +87,64 @@ describe('migrateDocument — finding B: unchanged re-import is a no-op, not a f
|
|
|
49
87
|
expect(res.status).toBe('updated'); // NOT 'failed'
|
|
50
88
|
expect(res.documentId).toBe('doc-1');
|
|
51
89
|
});
|
|
52
|
-
it('still reports a genuine
|
|
90
|
+
it('still reports a genuine import error as failed', async () => {
|
|
53
91
|
vi.spyOn(globalThis, 'fetch').mockImplementation((async (url, init) => {
|
|
54
92
|
const u = String(url);
|
|
55
93
|
const method = (init?.method ?? 'GET').toUpperCase();
|
|
56
|
-
if (method === 'POST' && u.endsWith('/api/v1/kb/
|
|
57
|
-
return mockResponse(409, {
|
|
58
|
-
error: 'exists',
|
|
59
|
-
documentId: 'doc-1',
|
|
60
|
-
branchId: 'br-1',
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
if (method === 'PUT')
|
|
94
|
+
if (method === 'POST' && u.endsWith('/api/v1/kb/import')) {
|
|
64
95
|
return mockResponse(500, { error: 'boom' });
|
|
96
|
+
}
|
|
65
97
|
return mockResponse(200, {});
|
|
66
98
|
}));
|
|
67
99
|
const res = await client().migrateDocument(doc, '/', 'update', false);
|
|
68
100
|
expect(res.status).toBe('failed');
|
|
69
101
|
});
|
|
70
102
|
});
|
|
103
|
+
describe('blocks-to-grammar serializer', () => {
|
|
104
|
+
it('serializes media blocks to ::: directives (storage key first, url fallback)', () => {
|
|
105
|
+
expect(blockToGrammar({
|
|
106
|
+
blockType: 'image',
|
|
107
|
+
type: 'storage',
|
|
108
|
+
key: 'tenant_1/img.png',
|
|
109
|
+
mediaType: 'image/png',
|
|
110
|
+
alt: 'diagram',
|
|
111
|
+
})).toBe(':::image{ref="tenant_1/img.png" alt="diagram" mime="image/png"}');
|
|
112
|
+
expect(blockToGrammar({
|
|
113
|
+
blockType: 'image',
|
|
114
|
+
type: 'url',
|
|
115
|
+
url: 'https://example.test/pic.png',
|
|
116
|
+
mediaType: 'image/png',
|
|
117
|
+
})).toBe(':::image{ref="https://example.test/pic.png" mime="image/png"}');
|
|
118
|
+
expect(blockToGrammar({ blockType: 'database_embed', databaseId: 'db-1' })).toBe(':::db{ref="db-1"}');
|
|
119
|
+
expect(blockToGrammar({
|
|
120
|
+
blockType: 'csv',
|
|
121
|
+
type: 'storage',
|
|
122
|
+
key: 'tenant_1/data.csv',
|
|
123
|
+
mediaType: 'text/csv',
|
|
124
|
+
filename: 'data.csv',
|
|
125
|
+
headers: ['a', 'b'],
|
|
126
|
+
rowCount: 3,
|
|
127
|
+
})).toBe(':::csv{ref="tenant_1/data.csv" filename="data.csv" mime="text/csv" headers=[a,b] rowCount=3}');
|
|
128
|
+
});
|
|
129
|
+
it('drops media with no expressible ref and counts it', () => {
|
|
130
|
+
const { markdown, dropped } = sectionsToGrammarMarkdown([
|
|
131
|
+
{
|
|
132
|
+
name: 'S',
|
|
133
|
+
content: [
|
|
134
|
+
{ blockType: 'text', text: 'kept' },
|
|
135
|
+
{
|
|
136
|
+
blockType: 'image',
|
|
137
|
+
type: 'base64',
|
|
138
|
+
base64: 'xxxx',
|
|
139
|
+
mediaType: 'image/png',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
]);
|
|
144
|
+
expect(dropped).toBe(1);
|
|
145
|
+
expect(markdown).toBe('## S\n\nkept');
|
|
146
|
+
});
|
|
147
|
+
it('front-matter escapes names safely (JSON-quoted scalars)', () => {
|
|
148
|
+
expect(buildImportFrontMatter('He said "hi": ok')).toBe('---\nname: "He said \\"hi\\": ok"\n---\n\n');
|
|
149
|
+
});
|
|
150
|
+
});
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package's version, read from its package.json at runtime (src/ and
|
|
3
|
+
* dist/ both sit one level below it). Reported by `--version`, on stderr at
|
|
4
|
+
* the start of every command, and on every JSON log — so a stale npx
|
|
5
|
+
* resolution of an old kb-migrate is visible instead of silent.
|
|
6
|
+
*/
|
|
7
|
+
export declare function packageVersion(): string;
|
|
8
|
+
/**
|
|
9
|
+
* Route console.log to stderr until {@link exitJsonMode}. The CLI enters it
|
|
10
|
+
* from a preAction hook for any command run with `--json`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function enterJsonMode(): void;
|
|
13
|
+
export declare function exitJsonMode(): void;
|
|
14
|
+
/** Run `fn` with console.log routed to stderr when `json` is set. */
|
|
15
|
+
export declare function withJsonStdout<T>(json: boolean, fn: () => Promise<T>): Promise<T>;
|
|
16
|
+
/** Write a command's JSON log to stdout, stamped with the kb-migrate version. */
|
|
17
|
+
export declare function emitJson(log: object): void;
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-output helpers for the kb-migrate CLI.
|
|
3
|
+
*
|
|
4
|
+
* `--json` promises stdout is ONE JSON document — `context import-local
|
|
5
|
+
* --json` and friends parse it. Progress lines are printed with console.log
|
|
6
|
+
* all through the runners, so JSON mode routes console.log to stderr for the
|
|
7
|
+
* duration of the run and writes the log itself straight to stdout.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import { format } from 'util';
|
|
11
|
+
let cachedVersion;
|
|
12
|
+
/**
|
|
13
|
+
* This package's version, read from its package.json at runtime (src/ and
|
|
14
|
+
* dist/ both sit one level below it). Reported by `--version`, on stderr at
|
|
15
|
+
* the start of every command, and on every JSON log — so a stale npx
|
|
16
|
+
* resolution of an old kb-migrate is visible instead of silent.
|
|
17
|
+
*/
|
|
18
|
+
export function packageVersion() {
|
|
19
|
+
if (cachedVersion === undefined) {
|
|
20
|
+
try {
|
|
21
|
+
const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
|
|
22
|
+
cachedVersion = pkg.version ?? 'unknown';
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
cachedVersion = 'unknown';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return cachedVersion;
|
|
29
|
+
}
|
|
30
|
+
let restoreLog;
|
|
31
|
+
/**
|
|
32
|
+
* Route console.log to stderr until {@link exitJsonMode}. The CLI enters it
|
|
33
|
+
* from a preAction hook for any command run with `--json`.
|
|
34
|
+
*/
|
|
35
|
+
export function enterJsonMode() {
|
|
36
|
+
if (restoreLog)
|
|
37
|
+
return;
|
|
38
|
+
const original = console.log;
|
|
39
|
+
console.log = (...args) => {
|
|
40
|
+
process.stderr.write(`${format(...args)}\n`);
|
|
41
|
+
};
|
|
42
|
+
restoreLog = () => {
|
|
43
|
+
console.log = original;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function exitJsonMode() {
|
|
47
|
+
restoreLog?.();
|
|
48
|
+
restoreLog = undefined;
|
|
49
|
+
}
|
|
50
|
+
/** Run `fn` with console.log routed to stderr when `json` is set. */
|
|
51
|
+
export async function withJsonStdout(json, fn) {
|
|
52
|
+
if (!json)
|
|
53
|
+
return fn();
|
|
54
|
+
enterJsonMode();
|
|
55
|
+
try {
|
|
56
|
+
return await fn();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
exitJsonMode();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Write a command's JSON log to stdout, stamped with the kb-migrate version. */
|
|
63
|
+
export function emitJson(log) {
|
|
64
|
+
process.stdout.write(`${JSON.stringify({ kbMigrateVersion: packageVersion(), ...log }, null, 2)}\n`);
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--json` output contract + version reporting.
|
|
3
|
+
*
|
|
4
|
+
* - `kb-migrate local --json` printed `Processing: …` progress on STDOUT ahead
|
|
5
|
+
* of the JSON log, so `context import-local --json` was not parseable. In
|
|
6
|
+
* JSON mode stdout carries the log and nothing else; progress goes to stderr.
|
|
7
|
+
* - `--version` was hardcoded `0.1.0`, so a stale npx resolution (a cached
|
|
8
|
+
* 0.4.x exporter, prod 2026-09-25) was undiagnosable. The real package
|
|
9
|
+
* version is reported, and stamped on every JSON log.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import { emitJson, packageVersion, withJsonStdout } from './output.js';
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
vi.restoreAllMocks();
|
|
16
|
+
});
|
|
17
|
+
describe('packageVersion', () => {
|
|
18
|
+
it('is the version in package.json, not a hardcoded placeholder', () => {
|
|
19
|
+
const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
|
|
20
|
+
expect(packageVersion()).toBe(pkg.version);
|
|
21
|
+
expect(packageVersion()).not.toBe('0.1.0');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('JSON mode stdout', () => {
|
|
25
|
+
function capture() {
|
|
26
|
+
const stdout = [];
|
|
27
|
+
const stderr = [];
|
|
28
|
+
vi.spyOn(process.stdout, 'write').mockImplementation(((c) => {
|
|
29
|
+
stdout.push(String(c));
|
|
30
|
+
return true;
|
|
31
|
+
}));
|
|
32
|
+
vi.spyOn(process.stderr, 'write').mockImplementation(((c) => {
|
|
33
|
+
stderr.push(String(c));
|
|
34
|
+
return true;
|
|
35
|
+
}));
|
|
36
|
+
return { stdout, stderr };
|
|
37
|
+
}
|
|
38
|
+
it('routes progress (console.log) to stderr while the run is in JSON mode', async () => {
|
|
39
|
+
const { stdout, stderr } = capture();
|
|
40
|
+
await withJsonStdout(true, async () => {
|
|
41
|
+
console.log('Processing: a.md (1/1)');
|
|
42
|
+
});
|
|
43
|
+
emitJson({ summary: { total: 1 } });
|
|
44
|
+
const out = stdout.join('');
|
|
45
|
+
const parsed = JSON.parse(out);
|
|
46
|
+
expect(parsed.summary.total).toBe(1);
|
|
47
|
+
expect(parsed.kbMigrateVersion).toBe(packageVersion());
|
|
48
|
+
expect(out).not.toContain('Processing');
|
|
49
|
+
expect(stderr.join('')).toContain('Processing: a.md');
|
|
50
|
+
});
|
|
51
|
+
it('restores console.log afterwards, and leaves it alone outside JSON mode', async () => {
|
|
52
|
+
const original = console.log;
|
|
53
|
+
await withJsonStdout(true, async () => { });
|
|
54
|
+
expect(console.log).toBe(original);
|
|
55
|
+
await withJsonStdout(false, async () => {
|
|
56
|
+
expect(console.log).toBe(original);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { discoverOneNotePages, slugifyPathSegment } from '../onenote-tree.js';
|
|
3
|
+
/** Minimal OneNoteApiClient: one notebook, no groups, pages routed by section. */
|
|
4
|
+
function mockClient(sectionPages) {
|
|
5
|
+
const sections = Object.keys(sectionPages).map((id) => ({ id, displayName: id }));
|
|
6
|
+
return {
|
|
7
|
+
listNotebooks: async () => [{ id: 'nb1', displayName: 'Notebook' }],
|
|
8
|
+
listSectionGroups: async () => [],
|
|
9
|
+
listSectionsInNotebook: async () => sections,
|
|
10
|
+
listSectionsInGroup: async () => [],
|
|
11
|
+
listPages: async (sectionId) => sectionPages[sectionId] ?? [],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
describe('discoverOneNotePages — dedup same-titled sibling pages (finding D, #203)', () => {
|
|
15
|
+
it('two same-titled pages in ONE section get distinct paths + disambiguated titles', async () => {
|
|
16
|
+
const out = await discoverOneNotePages(mockClient({
|
|
17
|
+
sec1: [
|
|
18
|
+
{ id: 'p1', title: 'Notes' },
|
|
19
|
+
{ id: 'p2', title: 'Notes' },
|
|
20
|
+
],
|
|
21
|
+
}));
|
|
22
|
+
expect(out).toHaveLength(2);
|
|
23
|
+
// Distinct paths — the collision (data loss) is gone.
|
|
24
|
+
expect(new Set(out.map((p) => p.kbPath)).size).toBe(2);
|
|
25
|
+
// Second sibling disambiguated.
|
|
26
|
+
expect(out.map((p) => p.title).sort()).toEqual(['Notes', 'Notes 2']);
|
|
27
|
+
// The server's bijection invariant: pathTail === slug(name).
|
|
28
|
+
for (const p of out) {
|
|
29
|
+
expect(p.kbPath.split('/').pop()).toBe(slugifyPathSegment(p.title));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
it('same title in DIFFERENT sections is NOT deduped (counter is per-section)', async () => {
|
|
33
|
+
const out = await discoverOneNotePages(mockClient({
|
|
34
|
+
secA: [{ id: 'p1', title: 'Notes' }],
|
|
35
|
+
secB: [{ id: 'p2', title: 'Notes' }],
|
|
36
|
+
}));
|
|
37
|
+
expect(out).toHaveLength(2);
|
|
38
|
+
// Both keep the plain title (no cross-section suffixing)...
|
|
39
|
+
expect(out.map((p) => p.title)).toEqual(['Notes', 'Notes']);
|
|
40
|
+
// ...and the section segment already makes the paths distinct.
|
|
41
|
+
expect(new Set(out.map((p) => p.kbPath)).size).toBe(2);
|
|
42
|
+
});
|
|
43
|
+
});
|
package/dist/targets/notion.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* Conflict detection uses the MoxnClient's notion-mapping API endpoints
|
|
12
12
|
* (when available) to find existing Notion pages for a KB document.
|
|
13
13
|
*/
|
|
14
|
+
import { moxnFetch } from '../http.js';
|
|
14
15
|
import { Client } from '@notionhq/client';
|
|
15
16
|
import { markdownToBlocks } from '@tryfabric/martian';
|
|
16
17
|
import { ExportTarget, } from './base.js';
|
|
@@ -744,7 +745,7 @@ export class NotionExportTarget extends ExportTarget {
|
|
|
744
745
|
return cached;
|
|
745
746
|
// Try notion-mapping API
|
|
746
747
|
try {
|
|
747
|
-
const response = await
|
|
748
|
+
const response = await moxnFetch(`${this.config.apiUrl}/api/v1/kb/notion-mappings/by-document/${kbDocumentId}`, {
|
|
748
749
|
headers: { 'x-api-key': this.config.apiKey },
|
|
749
750
|
});
|
|
750
751
|
if (response.ok) {
|
|
@@ -764,7 +765,7 @@ export class NotionExportTarget extends ExportTarget {
|
|
|
764
765
|
this.mappingCache.set(kbDocumentId, notionPageId);
|
|
765
766
|
// Try to save mapping via API (best-effort)
|
|
766
767
|
try {
|
|
767
|
-
await
|
|
768
|
+
await moxnFetch(`${this.config.apiUrl}/api/v1/kb/notion-mappings`, {
|
|
768
769
|
method: 'POST',
|
|
769
770
|
headers: {
|
|
770
771
|
'Content-Type': 'application/json',
|
package/dist/types.d.ts
CHANGED
|
@@ -146,6 +146,8 @@ export interface MigrationResult {
|
|
|
146
146
|
/** Source page ID (e.g. Notion page ID) for building cross-ref mappings */
|
|
147
147
|
sourcePageId?: string;
|
|
148
148
|
error?: string;
|
|
149
|
+
/** Non-fatal: the document landed, but not everything asked for applied. */
|
|
150
|
+
warning?: string;
|
|
149
151
|
duration?: number;
|
|
150
152
|
}
|
|
151
153
|
/**
|
|
@@ -276,8 +278,10 @@ export interface ListResponse {
|
|
|
276
278
|
export interface ExportResult {
|
|
277
279
|
documentId: string;
|
|
278
280
|
documentPath: string;
|
|
281
|
+
/** Directory-relative output file; empty when nothing was written. */
|
|
279
282
|
outputFile: string;
|
|
280
|
-
|
|
283
|
+
/** 'skipped': a kind with no local export format (nothing written). */
|
|
284
|
+
status: 'exported' | 'failed' | 'skipped';
|
|
281
285
|
sectionsCount: number;
|
|
282
286
|
mediaFiles: string[];
|
|
283
287
|
error?: string;
|
|
@@ -302,6 +306,7 @@ export interface ExportLog {
|
|
|
302
306
|
total: number;
|
|
303
307
|
exported: number;
|
|
304
308
|
failed: number;
|
|
309
|
+
skipped: number;
|
|
305
310
|
mediaDownloaded: number;
|
|
306
311
|
duration: number;
|
|
307
312
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moxn/kb-migrate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Migration tool for importing documents into Moxn Knowledge Base from local files, Notion, Google Docs, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -112,6 +112,7 @@
|
|
|
112
112
|
"dependencies": {
|
|
113
113
|
"@azure/msal-node": "^3.8.10",
|
|
114
114
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
115
|
+
"@moxn/auth": "^0.1.0",
|
|
115
116
|
"@moxn/kb-migrate": "^0.4.14",
|
|
116
117
|
"@notionhq/client": "^5.9.0",
|
|
117
118
|
"@tryfabric/martian": "^1.2.4",
|
|
@@ -155,4 +156,4 @@
|
|
|
155
156
|
"publishConfig": {
|
|
156
157
|
"access": "public"
|
|
157
158
|
}
|
|
158
|
-
}
|
|
159
|
+
}
|