@iwonz/ywtc 3.6.0 → 4.0.1
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/CHANGELOG.md +30 -0
- package/README.md +17 -14
- package/dist/adapters/confluence.d.ts +0 -2
- package/dist/adapters/confluence.js +61 -27
- package/dist/adapters/confluence.js.map +1 -1
- package/dist/adapters/yandex.d.ts +7 -9
- package/dist/adapters/yandex.js +68 -27
- package/dist/adapters/yandex.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/clients/confluence-cloud.d.ts +1 -0
- package/dist/clients/confluence-cloud.js +2 -2
- package/dist/clients/confluence-cloud.js.map +1 -1
- package/dist/clients/confluence.d.ts +1 -0
- package/dist/clients/confluence.js +4 -3
- package/dist/clients/confluence.js.map +1 -1
- package/dist/clients/yandex-wiki.js +2 -6
- package/dist/clients/yandex-wiki.js.map +1 -1
- package/dist/consistency.d.ts +1 -1
- package/dist/consistency.js +6 -1
- package/dist/consistency.js.map +1 -1
- package/dist/content-model.d.ts +1 -0
- package/dist/content-model.js +118 -37
- package/dist/content-model.js.map +1 -1
- package/dist/conversion.d.ts +2 -0
- package/dist/conversion.js +42 -17
- package/dist/conversion.js.map +1 -1
- package/dist/domain.d.ts +27 -4
- package/dist/domain.js +20 -0
- package/dist/domain.js.map +1 -1
- package/dist/exclusive-lease.d.ts +14 -0
- package/dist/exclusive-lease.js +87 -0
- package/dist/exclusive-lease.js.map +1 -0
- package/dist/filesystem-export.d.ts +2 -0
- package/dist/filesystem-export.js +188 -167
- package/dist/filesystem-export.js.map +1 -1
- package/dist/graph.js +4 -4
- package/dist/graph.js.map +1 -1
- package/dist/http.js +1 -1
- package/dist/http.js.map +1 -1
- package/dist/interactive-config.js +55 -3
- package/dist/interactive-config.js.map +1 -1
- package/dist/issues.d.ts +1 -1
- package/dist/migrator.js +604 -366
- package/dist/migrator.js.map +1 -1
- package/dist/report-catalog.d.ts +4 -0
- package/dist/report-catalog.js +4 -0
- package/dist/report-catalog.js.map +1 -1
- package/dist/report-contract.d.ts +6 -0
- package/dist/report-contract.js.map +1 -1
- package/dist/report-ui/index.html +6 -6
- package/dist/report.js +34 -23
- package/dist/report.js.map +1 -1
- package/dist/state.d.ts +18 -0
- package/dist/state.js +60 -32
- package/dist/state.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/domain.d.ts
CHANGED
|
@@ -77,6 +77,17 @@ export declare class DestinationTitleConflictError extends Error {
|
|
|
77
77
|
readonly status: number;
|
|
78
78
|
constructor(title: string, status: number, options?: ErrorOptions);
|
|
79
79
|
}
|
|
80
|
+
export declare class DestinationRevisionConflictError extends Error {
|
|
81
|
+
readonly objectType: 'page' | 'comment';
|
|
82
|
+
readonly objectId: string;
|
|
83
|
+
constructor(objectType: 'page' | 'comment', objectId: string, options?: ErrorOptions);
|
|
84
|
+
}
|
|
85
|
+
export type OwnershipConflictReason = 'duplicate-source-mapping' | 'immutable-id-mismatch' | 'ambiguous-ownership-candidates';
|
|
86
|
+
export declare class DestinationOwnershipConflictError extends Error {
|
|
87
|
+
readonly reason: OwnershipConflictReason;
|
|
88
|
+
readonly candidateIds: string[];
|
|
89
|
+
constructor(reason: OwnershipConflictReason, candidateIds: string[], message: string, options?: ErrorOptions);
|
|
90
|
+
}
|
|
80
91
|
export interface UploadedResource {
|
|
81
92
|
id: string;
|
|
82
93
|
name: string;
|
|
@@ -170,7 +181,7 @@ export interface SourceStatusExclusion {
|
|
|
170
181
|
depth?: number;
|
|
171
182
|
discoveredFromId?: string;
|
|
172
183
|
metadataComplete?: boolean;
|
|
173
|
-
reason: 'source-status';
|
|
184
|
+
reason: 'source-status' | 'inventory-drift';
|
|
174
185
|
status?: string;
|
|
175
186
|
}
|
|
176
187
|
export interface DescendantDiscovery {
|
|
@@ -227,12 +238,10 @@ export interface DestinationAdapter {
|
|
|
227
238
|
page: DestinationPage;
|
|
228
239
|
title: string;
|
|
229
240
|
body: string;
|
|
230
|
-
expectedFingerprint?: string;
|
|
231
241
|
}): Promise<DestinationPage>;
|
|
232
242
|
reparentPage?(input: {
|
|
233
243
|
page: DestinationPage;
|
|
234
244
|
parent: DestinationContainer | DestinationPage;
|
|
235
|
-
expectedFingerprint?: string;
|
|
236
245
|
}): Promise<DestinationPage>;
|
|
237
246
|
uploadResource(input: {
|
|
238
247
|
page: DestinationPage;
|
|
@@ -286,7 +295,7 @@ export interface HierarchyGap {
|
|
|
286
295
|
pageId: string;
|
|
287
296
|
missingParentId?: string;
|
|
288
297
|
selectedParentId: string;
|
|
289
|
-
reason: 'unavailable' | 'source-status';
|
|
298
|
+
reason: 'unavailable' | 'source-status' | 'inventory-drift';
|
|
290
299
|
}
|
|
291
300
|
export interface SourceSelection {
|
|
292
301
|
requestedStatus: SourceStatus;
|
|
@@ -332,6 +341,14 @@ export interface NormalizedNode {
|
|
|
332
341
|
sectionType?: 'single' | 'two_equal' | 'two_left_sidebar' | 'two_right_sidebar' | 'three_equal' | 'three_with_sidebars' | 'unsupported';
|
|
333
342
|
};
|
|
334
343
|
}
|
|
344
|
+
export type TransformationNoticeKind = 'normalization' | 'adaptation' | 'degradation';
|
|
345
|
+
export interface TransformationNotice {
|
|
346
|
+
code: string;
|
|
347
|
+
kind: TransformationNoticeKind;
|
|
348
|
+
message: string;
|
|
349
|
+
objectId?: string;
|
|
350
|
+
verification?: string;
|
|
351
|
+
}
|
|
335
352
|
export interface NormalizedDocument {
|
|
336
353
|
root: NormalizedNode;
|
|
337
354
|
raw: string;
|
|
@@ -339,6 +356,8 @@ export interface NormalizedDocument {
|
|
|
339
356
|
references: NormalizedReference[];
|
|
340
357
|
warnings: string[];
|
|
341
358
|
normalizations: string[];
|
|
359
|
+
adaptations: string[];
|
|
360
|
+
notices: TransformationNotice[];
|
|
342
361
|
degraded: boolean;
|
|
343
362
|
semanticallyEmpty: boolean;
|
|
344
363
|
metrics: {
|
|
@@ -346,6 +365,7 @@ export interface NormalizedDocument {
|
|
|
346
365
|
images: number;
|
|
347
366
|
tables: number;
|
|
348
367
|
codeBlocks: number;
|
|
368
|
+
preservedExternalReferences: number;
|
|
349
369
|
};
|
|
350
370
|
}
|
|
351
371
|
export interface RenderContext {
|
|
@@ -362,7 +382,10 @@ export interface RenderedDocument {
|
|
|
362
382
|
body: string;
|
|
363
383
|
warnings: string[];
|
|
364
384
|
normalizations: string[];
|
|
385
|
+
adaptations: string[];
|
|
386
|
+
notices: TransformationNotice[];
|
|
365
387
|
degraded: boolean;
|
|
366
388
|
representedReferences: number;
|
|
389
|
+
preservedExternalReferences: number;
|
|
367
390
|
}
|
|
368
391
|
export declare function assertTransferCapabilities(source: SourceAdapter, destination: DestinationAdapter | undefined, scope: TransferScope, sourceStatus?: SourceStatus, comments?: boolean): void;
|
package/dist/domain.js
CHANGED
|
@@ -8,6 +8,26 @@ export class DestinationTitleConflictError extends Error {
|
|
|
8
8
|
this.name = 'DestinationTitleConflictError';
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
+
export class DestinationRevisionConflictError extends Error {
|
|
12
|
+
objectType;
|
|
13
|
+
objectId;
|
|
14
|
+
constructor(objectType, objectId, options) {
|
|
15
|
+
super(`Destination ${objectType} ${objectId} changed concurrently`, options);
|
|
16
|
+
this.objectType = objectType;
|
|
17
|
+
this.objectId = objectId;
|
|
18
|
+
this.name = 'DestinationRevisionConflictError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class DestinationOwnershipConflictError extends Error {
|
|
22
|
+
reason;
|
|
23
|
+
candidateIds;
|
|
24
|
+
constructor(reason, candidateIds, message, options) {
|
|
25
|
+
super(message, options);
|
|
26
|
+
this.reason = reason;
|
|
27
|
+
this.candidateIds = candidateIds;
|
|
28
|
+
this.name = 'DestinationOwnershipConflictError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
11
31
|
export function assertTransferCapabilities(source, destination, scope, sourceStatus = 'all', comments = true) {
|
|
12
32
|
const missing = [];
|
|
13
33
|
if (!source.capabilities.readPages)
|
package/dist/domain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain.js","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"AAiFA,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAE3C;IACA;IAFX,YACW,KAAa,EACb,MAAc,EACvB,OAAsB;QAEtB,KAAK,CAAC,+CAA+C,KAAK,GAAG,EAAE,OAAO,CAAC,CAAC;QAJ/D,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAQ;QAIvB,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"domain.js","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface LeaseMetadata {
|
|
2
|
+
pid: number;
|
|
3
|
+
hostname: string;
|
|
4
|
+
startedAt: string;
|
|
5
|
+
purpose: string;
|
|
6
|
+
target: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ExclusiveLease {
|
|
9
|
+
filename: string;
|
|
10
|
+
metadata: LeaseMetadata;
|
|
11
|
+
release(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare function acquireExclusiveLease(filename: string, purpose: string, target: string): Promise<ExclusiveLease>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { hostname } from 'node:os';
|
|
2
|
+
import { mkdir, open, readFile, unlink } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
function localProcessIsAlive(pid) {
|
|
5
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
6
|
+
return false;
|
|
7
|
+
try {
|
|
8
|
+
process.kill(pid, 0);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return error.code === 'EPERM';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function existingLease(filename) {
|
|
16
|
+
try {
|
|
17
|
+
const value = JSON.parse(await readFile(filename, 'utf8'));
|
|
18
|
+
if (typeof value.pid !== 'number'
|
|
19
|
+
|| typeof value.hostname !== 'string'
|
|
20
|
+
|| typeof value.startedAt !== 'string'
|
|
21
|
+
|| typeof value.purpose !== 'string'
|
|
22
|
+
|| typeof value.target !== 'string')
|
|
23
|
+
return undefined;
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function isProvablyStale(metadata) {
|
|
31
|
+
return metadata?.hostname === hostname() && !localProcessIsAlive(metadata.pid);
|
|
32
|
+
}
|
|
33
|
+
export async function acquireExclusiveLease(filename, purpose, target) {
|
|
34
|
+
await mkdir(path.dirname(filename), { recursive: true, mode: 0o700 });
|
|
35
|
+
const metadata = { pid: process.pid, hostname: hostname(), startedAt: new Date().toISOString(), purpose, target };
|
|
36
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
37
|
+
let created = false;
|
|
38
|
+
try {
|
|
39
|
+
const handle = await open(filename, 'wx', 0o600);
|
|
40
|
+
created = true;
|
|
41
|
+
try {
|
|
42
|
+
await handle.writeFile(`${JSON.stringify(metadata, null, 2)}\n`);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await handle.close();
|
|
46
|
+
}
|
|
47
|
+
let released = false;
|
|
48
|
+
return {
|
|
49
|
+
filename,
|
|
50
|
+
metadata,
|
|
51
|
+
async release() {
|
|
52
|
+
if (released)
|
|
53
|
+
return;
|
|
54
|
+
released = true;
|
|
55
|
+
const current = await existingLease(filename);
|
|
56
|
+
if (current?.pid === metadata.pid && current.hostname === metadata.hostname && current.startedAt === metadata.startedAt) {
|
|
57
|
+
await unlink(filename).catch((error) => {
|
|
58
|
+
if (error.code !== 'ENOENT')
|
|
59
|
+
throw error;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error.code !== 'EEXIST') {
|
|
67
|
+
if (created)
|
|
68
|
+
await unlink(filename).catch(() => undefined);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
const current = await existingLease(filename);
|
|
72
|
+
if (attempt === 0 && isProvablyStale(current)) {
|
|
73
|
+
await unlink(filename).catch((unlinkError) => {
|
|
74
|
+
if (unlinkError.code !== 'ENOENT')
|
|
75
|
+
throw unlinkError;
|
|
76
|
+
});
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const detail = current
|
|
80
|
+
? `PID ${current.pid} on ${current.hostname}, started ${current.startedAt}`
|
|
81
|
+
: 'the lock metadata is unreadable and cannot be proven active';
|
|
82
|
+
throw new Error(`Another ${purpose} is active for "${target}" (${detail}). Wait for it to finish or remove the lock only after proving that process is no longer running.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Could not acquire ${purpose} lock for "${target}"`);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=exclusive-lease.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclusive-lease.js","sourceRoot":"","sources":["../src/exclusive-lease.ts"],"names":[],"mappings":"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"}
|