@knpkv/confluence-to-markdown 0.5.0 → 0.7.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/CHANGELOG.md +61 -0
- package/README.md +58 -14
- package/dist/AdfPlaceholders.d.ts +42 -0
- package/dist/AdfPlaceholders.d.ts.map +1 -0
- package/dist/AdfPlaceholders.js +547 -0
- package/dist/AdfPlaceholders.js.map +1 -0
- package/dist/AdfSchemaValidator.d.ts +37 -0
- package/dist/AdfSchemaValidator.d.ts.map +1 -0
- package/dist/AdfSchemaValidator.js +37 -0
- package/dist/AdfSchemaValidator.js.map +1 -0
- package/dist/AdfWalker.d.ts +39 -0
- package/dist/AdfWalker.d.ts.map +1 -0
- package/dist/AdfWalker.js +527 -0
- package/dist/AdfWalker.js.map +1 -0
- package/dist/AtlaskitTransformers.d.ts +35 -0
- package/dist/AtlaskitTransformers.d.ts.map +1 -0
- package/dist/AtlaskitTransformers.js +48 -0
- package/dist/AtlaskitTransformers.js.map +1 -0
- package/dist/Brand.d.ts +6 -6
- package/dist/Brand.d.ts.map +1 -1
- package/dist/Brand.js +8 -6
- package/dist/Brand.js.map +1 -1
- package/dist/ConfluenceAuth.d.ts +4 -4
- package/dist/ConfluenceAuth.d.ts.map +1 -1
- package/dist/ConfluenceAuth.js +15 -27
- package/dist/ConfluenceAuth.js.map +1 -1
- package/dist/ConfluenceClient.d.ts +4 -4
- package/dist/ConfluenceClient.d.ts.map +1 -1
- package/dist/ConfluenceClient.js +21 -14
- package/dist/ConfluenceClient.js.map +1 -1
- package/dist/ConfluenceConfig.d.ts +3 -3
- package/dist/ConfluenceConfig.d.ts.map +1 -1
- package/dist/ConfluenceConfig.js +13 -11
- package/dist/ConfluenceConfig.js.map +1 -1
- package/dist/ConfluenceError.d.ts +56 -4
- package/dist/ConfluenceError.d.ts.map +1 -1
- package/dist/ConfluenceError.js +30 -1
- package/dist/ConfluenceError.js.map +1 -1
- package/dist/GitService.d.ts +11 -3
- package/dist/GitService.d.ts.map +1 -1
- package/dist/GitService.js +19 -27
- package/dist/GitService.js.map +1 -1
- package/dist/LocalFileSystem.d.ts +3 -3
- package/dist/LocalFileSystem.d.ts.map +1 -1
- package/dist/LocalFileSystem.js +6 -6
- package/dist/LocalFileSystem.js.map +1 -1
- package/dist/MarkdownConverter.d.ts +16 -65
- package/dist/MarkdownConverter.d.ts.map +1 -1
- package/dist/MarkdownConverter.js +64 -85
- package/dist/MarkdownConverter.js.map +1 -1
- package/dist/Schemas.d.ts +128 -141
- package/dist/Schemas.d.ts.map +1 -1
- package/dist/Schemas.js +21 -23
- package/dist/Schemas.js.map +1 -1
- package/dist/SyncEngine.d.ts +8 -5
- package/dist/SyncEngine.d.ts.map +1 -1
- package/dist/SyncEngine.js +189 -113
- package/dist/SyncEngine.js.map +1 -1
- package/dist/bin.js +23 -35
- package/dist/bin.js.map +1 -1
- package/dist/commands/auth.d.ts +2 -14
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +11 -16
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/clone.d.ts +4 -6
- package/dist/commands/clone.d.ts.map +1 -1
- package/dist/commands/clone.js +34 -32
- package/dist/commands/clone.js.map +1 -1
- package/dist/commands/delete.d.ts +2 -10
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +5 -4
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/errorHandler.d.ts +2 -1
- package/dist/commands/errorHandler.d.ts.map +1 -1
- package/dist/commands/errorHandler.js +22 -15
- package/dist/commands/errorHandler.js.map +1 -1
- package/dist/commands/fetch.d.ts +27 -0
- package/dist/commands/fetch.d.ts.map +1 -0
- package/dist/commands/fetch.js +48 -0
- package/dist/commands/fetch.js.map +1 -0
- package/dist/commands/git.d.ts +7 -10
- package/dist/commands/git.d.ts.map +1 -1
- package/dist/commands/git.js +6 -6
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/layers.d.ts +10 -9
- package/dist/commands/layers.d.ts.map +1 -1
- package/dist/commands/layers.js +41 -30
- package/dist/commands/layers.js.map +1 -1
- package/dist/commands/new.d.ts +2 -6
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +5 -4
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/pageInput.d.ts +19 -0
- package/dist/commands/pageInput.d.ts.map +1 -0
- package/dist/commands/pageInput.js +68 -0
- package/dist/commands/pageInput.js.map +1 -0
- package/dist/commands/root.d.ts +8 -0
- package/dist/commands/root.d.ts.map +1 -0
- package/dist/commands/root.js +29 -0
- package/dist/commands/root.js.map +1 -0
- package/dist/commands/sync.d.ts +6 -9
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +5 -6
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.d.ts +3 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -13
- package/dist/index.js.map +1 -1
- package/dist/internal/NodeLayers.d.ts.map +1 -1
- package/dist/internal/NodeLayers.js +1 -2
- package/dist/internal/NodeLayers.js.map +1 -1
- package/dist/internal/adfMetadata.d.ts +30 -0
- package/dist/internal/adfMetadata.d.ts.map +1 -0
- package/dist/internal/adfMetadata.js +126 -0
- package/dist/internal/adfMetadata.js.map +1 -0
- package/dist/internal/cleanMarkdown.d.ts +5 -0
- package/dist/internal/cleanMarkdown.d.ts.map +1 -0
- package/dist/internal/cleanMarkdown.js +13 -0
- package/dist/internal/cleanMarkdown.js.map +1 -0
- package/dist/internal/frontmatter.d.ts.map +1 -1
- package/dist/internal/frontmatter.js +41 -8
- package/dist/internal/frontmatter.js.map +1 -1
- package/dist/internal/gitCommands.d.ts +9 -3
- package/dist/internal/gitCommands.d.ts.map +1 -1
- package/dist/internal/gitCommands.js +18 -9
- package/dist/internal/gitCommands.js.map +1 -1
- package/dist/internal/hashUtils.d.ts +1 -1
- package/dist/internal/hashUtils.d.ts.map +1 -1
- package/dist/internal/hashUtils.js +1 -1
- package/dist/internal/hashUtils.js.map +1 -1
- package/dist/internal/oauthServer.d.ts +10 -5
- package/dist/internal/oauthServer.d.ts.map +1 -1
- package/dist/internal/oauthServer.js +19 -40
- package/dist/internal/oauthServer.js.map +1 -1
- package/dist/internal/pathUtils.d.ts +1 -1
- package/dist/internal/pathUtils.d.ts.map +1 -1
- package/dist/internal/pathUtils.js +1 -1
- package/dist/internal/pathUtils.js.map +1 -1
- package/dist/internal/process.d.ts +15 -0
- package/dist/internal/process.d.ts.map +1 -0
- package/dist/internal/process.js +10 -0
- package/dist/internal/process.js.map +1 -0
- package/dist/internal/stdio.d.ts +6 -0
- package/dist/internal/stdio.d.ts.map +1 -0
- package/dist/internal/stdio.js +15 -0
- package/dist/internal/stdio.js.map +1 -0
- package/dist/internal/tokenStorage.d.ts +3 -13
- package/dist/internal/tokenStorage.d.ts.map +1 -1
- package/dist/internal/tokenStorage.js +26 -24
- package/dist/internal/tokenStorage.js.map +1 -1
- package/dist/internal/userCache.d.ts +1 -1
- package/dist/internal/userCache.d.ts.map +1 -1
- package/dist/internal/userCache.js +1 -1
- package/dist/internal/userCache.js.map +1 -1
- package/package.json +29 -20
- package/skills/confluence/SKILL.md +143 -0
- package/skills/confluence/agents/openai.yaml +4 -0
- package/src/AdfPlaceholders.ts +563 -0
- package/src/AdfSchemaValidator.ts +65 -0
- package/src/AdfWalker.ts +591 -0
- package/src/AtlaskitTransformers.ts +70 -0
- package/src/Brand.ts +11 -16
- package/src/ConfluenceAuth.ts +22 -30
- package/src/ConfluenceClient.ts +28 -24
- package/src/ConfluenceConfig.ts +14 -14
- package/src/ConfluenceError.ts +65 -3
- package/src/GitService.ts +39 -49
- package/src/LocalFileSystem.ts +7 -9
- package/src/MarkdownConverter.ts +108 -143
- package/src/Schemas.ts +17 -16
- package/src/SyncEngine.ts +272 -127
- package/src/atlaskit-adf-schema.d.ts +3 -0
- package/src/bin.ts +30 -56
- package/src/commands/auth.ts +21 -18
- package/src/commands/clone.ts +46 -38
- package/src/commands/delete.ts +5 -4
- package/src/commands/errorHandler.ts +25 -18
- package/src/commands/fetch.ts +90 -0
- package/src/commands/git.ts +6 -6
- package/src/commands/index.ts +1 -0
- package/src/commands/layers.ts +64 -37
- package/src/commands/new.ts +5 -4
- package/src/commands/pageInput.ts +103 -0
- package/src/commands/root.ts +59 -0
- package/src/commands/sync.ts +7 -6
- package/src/index.ts +3 -18
- package/src/internal/NodeLayers.ts +1 -2
- package/src/internal/adfMetadata.ts +145 -0
- package/src/internal/cleanMarkdown.ts +15 -0
- package/src/internal/frontmatter.ts +45 -8
- package/src/internal/gitCommands.ts +23 -17
- package/src/internal/hashUtils.ts +2 -2
- package/src/internal/oauthServer.ts +84 -105
- package/src/internal/pathUtils.ts +1 -1
- package/src/internal/process.ts +15 -0
- package/src/internal/stdio.ts +22 -0
- package/src/internal/tokenStorage.ts +39 -29
- package/src/internal/userCache.ts +2 -2
- package/test/AdfPlaceholders.test.ts +508 -0
- package/test/AdfSchemaValidator.test.ts +34 -0
- package/test/AdfWalker.test.ts +676 -0
- package/test/AtlaskitTransformers.test.ts +25 -0
- package/test/Brand.test.ts +11 -11
- package/test/GitService.test.ts +6 -2
- package/test/MarkdownConverter.test.ts +121 -105
- package/test/RoundTrip.test.ts +521 -0
- package/test/Schemas.test.ts +40 -40
- package/test/adfMetadata.test.ts +110 -0
- package/test/cleanMarkdown.test.ts +36 -0
- package/test/commandHarness.test.ts +79 -0
- package/test/commandHarness.ts +147 -0
- package/test/fetch.test.ts +61 -0
- package/test/frontmatter.test.ts +41 -0
- package/test/integration.test.ts +569 -156
- package/test/layers.test.ts +12 -0
- package/test/oauthServer.test.ts +4 -5
- package/test/pageInput.test.ts +83 -0
- package/test/tokenStorage.test.ts +17 -17
- package/dist/SchemaConverterError.d.ts +0 -108
- package/dist/SchemaConverterError.d.ts.map +0 -1
- package/dist/SchemaConverterError.js +0 -84
- package/dist/SchemaConverterError.js.map +0 -1
- package/dist/ast/BlockNode.d.ts +0 -453
- package/dist/ast/BlockNode.d.ts.map +0 -1
- package/dist/ast/BlockNode.js +0 -310
- package/dist/ast/BlockNode.js.map +0 -1
- package/dist/ast/Document.d.ts +0 -216
- package/dist/ast/Document.d.ts.map +0 -1
- package/dist/ast/Document.js +0 -69
- package/dist/ast/Document.js.map +0 -1
- package/dist/ast/InlineNode.d.ts +0 -477
- package/dist/ast/InlineNode.d.ts.map +0 -1
- package/dist/ast/InlineNode.js +0 -263
- package/dist/ast/InlineNode.js.map +0 -1
- package/dist/ast/MacroNode.d.ts +0 -267
- package/dist/ast/MacroNode.d.ts.map +0 -1
- package/dist/ast/MacroNode.js +0 -164
- package/dist/ast/MacroNode.js.map +0 -1
- package/dist/ast/index.d.ts +0 -10
- package/dist/ast/index.d.ts.map +0 -1
- package/dist/ast/index.js +0 -14
- package/dist/ast/index.js.map +0 -1
- package/dist/parsers/ConfluenceParser.d.ts +0 -26
- package/dist/parsers/ConfluenceParser.d.ts.map +0 -1
- package/dist/parsers/ConfluenceParser.js +0 -797
- package/dist/parsers/ConfluenceParser.js.map +0 -1
- package/dist/parsers/MarkdownParser.d.ts +0 -26
- package/dist/parsers/MarkdownParser.d.ts.map +0 -1
- package/dist/parsers/MarkdownParser.js +0 -982
- package/dist/parsers/MarkdownParser.js.map +0 -1
- package/dist/parsers/index.d.ts +0 -8
- package/dist/parsers/index.d.ts.map +0 -1
- package/dist/parsers/index.js +0 -8
- package/dist/parsers/index.js.map +0 -1
- package/dist/schemas/ConfluenceSchema.d.ts +0 -21
- package/dist/schemas/ConfluenceSchema.d.ts.map +0 -1
- package/dist/schemas/ConfluenceSchema.js +0 -38
- package/dist/schemas/ConfluenceSchema.js.map +0 -1
- package/dist/schemas/ConversionSchema.d.ts +0 -35
- package/dist/schemas/ConversionSchema.d.ts.map +0 -1
- package/dist/schemas/ConversionSchema.js +0 -208
- package/dist/schemas/ConversionSchema.js.map +0 -1
- package/dist/schemas/MarkdownSchema.d.ts +0 -21
- package/dist/schemas/MarkdownSchema.d.ts.map +0 -1
- package/dist/schemas/MarkdownSchema.js +0 -38
- package/dist/schemas/MarkdownSchema.js.map +0 -1
- package/dist/schemas/hast/HastFromHtml.d.ts +0 -27
- package/dist/schemas/hast/HastFromHtml.d.ts.map +0 -1
- package/dist/schemas/hast/HastFromHtml.js +0 -107
- package/dist/schemas/hast/HastFromHtml.js.map +0 -1
- package/dist/schemas/hast/HastSchema.d.ts +0 -195
- package/dist/schemas/hast/HastSchema.d.ts.map +0 -1
- package/dist/schemas/hast/HastSchema.js +0 -183
- package/dist/schemas/hast/HastSchema.js.map +0 -1
- package/dist/schemas/hast/index.d.ts +0 -9
- package/dist/schemas/hast/index.d.ts.map +0 -1
- package/dist/schemas/hast/index.js +0 -3
- package/dist/schemas/hast/index.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -14
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -16
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/mdast/MdastFromMarkdown.d.ts +0 -30
- package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +0 -1
- package/dist/schemas/mdast/MdastFromMarkdown.js +0 -79
- package/dist/schemas/mdast/MdastFromMarkdown.js.map +0 -1
- package/dist/schemas/mdast/MdastSchema.d.ts +0 -385
- package/dist/schemas/mdast/MdastSchema.d.ts.map +0 -1
- package/dist/schemas/mdast/MdastSchema.js +0 -266
- package/dist/schemas/mdast/MdastSchema.js.map +0 -1
- package/dist/schemas/mdast/index.d.ts +0 -10
- package/dist/schemas/mdast/index.d.ts.map +0 -1
- package/dist/schemas/mdast/index.js +0 -4
- package/dist/schemas/mdast/index.js.map +0 -1
- package/dist/schemas/mdast/mdastToString.d.ts +0 -13
- package/dist/schemas/mdast/mdastToString.d.ts.map +0 -1
- package/dist/schemas/mdast/mdastToString.js +0 -85
- package/dist/schemas/mdast/mdastToString.js.map +0 -1
- package/dist/schemas/nodes/block/BlockSchema.d.ts +0 -43
- package/dist/schemas/nodes/block/BlockSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/block/BlockSchema.js +0 -634
- package/dist/schemas/nodes/block/BlockSchema.js.map +0 -1
- package/dist/schemas/nodes/block/index.d.ts +0 -7
- package/dist/schemas/nodes/block/index.d.ts.map +0 -1
- package/dist/schemas/nodes/block/index.js +0 -7
- package/dist/schemas/nodes/block/index.js.map +0 -1
- package/dist/schemas/nodes/index.d.ts +0 -9
- package/dist/schemas/nodes/index.d.ts.map +0 -1
- package/dist/schemas/nodes/index.js +0 -12
- package/dist/schemas/nodes/index.js.map +0 -1
- package/dist/schemas/nodes/inline/InlineSchema.d.ts +0 -48
- package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/inline/InlineSchema.js +0 -436
- package/dist/schemas/nodes/inline/InlineSchema.js.map +0 -1
- package/dist/schemas/nodes/inline/index.d.ts +0 -7
- package/dist/schemas/nodes/inline/index.d.ts.map +0 -1
- package/dist/schemas/nodes/inline/index.js +0 -7
- package/dist/schemas/nodes/inline/index.js.map +0 -1
- package/dist/schemas/nodes/macro/MacroSchema.d.ts +0 -27
- package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/macro/MacroSchema.js +0 -162
- package/dist/schemas/nodes/macro/MacroSchema.js.map +0 -1
- package/dist/schemas/nodes/macro/index.d.ts +0 -7
- package/dist/schemas/nodes/macro/index.d.ts.map +0 -1
- package/dist/schemas/nodes/macro/index.js +0 -7
- package/dist/schemas/nodes/macro/index.js.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +0 -24
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -359
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +0 -1
- package/dist/schemas/preprocessing/index.d.ts +0 -8
- package/dist/schemas/preprocessing/index.d.ts.map +0 -1
- package/dist/schemas/preprocessing/index.js +0 -2
- package/dist/schemas/preprocessing/index.js.map +0 -1
- package/dist/serializers/ConfluenceSerializer.d.ts +0 -30
- package/dist/serializers/ConfluenceSerializer.d.ts.map +0 -1
- package/dist/serializers/ConfluenceSerializer.js +0 -560
- package/dist/serializers/ConfluenceSerializer.js.map +0 -1
- package/dist/serializers/MarkdownSerializer.d.ts +0 -34
- package/dist/serializers/MarkdownSerializer.d.ts.map +0 -1
- package/dist/serializers/MarkdownSerializer.js +0 -395
- package/dist/serializers/MarkdownSerializer.js.map +0 -1
- package/dist/serializers/index.d.ts +0 -8
- package/dist/serializers/index.d.ts.map +0 -1
- package/dist/serializers/index.js +0 -8
- package/dist/serializers/index.js.map +0 -1
- package/src/SchemaConverterError.ts +0 -108
- package/src/ast/BlockNode.ts +0 -469
- package/src/ast/Document.ts +0 -90
- package/src/ast/InlineNode.ts +0 -323
- package/src/ast/MacroNode.ts +0 -245
- package/src/ast/index.ts +0 -83
- package/src/parsers/ConfluenceParser.ts +0 -956
- package/src/parsers/MarkdownParser.ts +0 -1338
- package/src/parsers/index.ts +0 -8
- package/src/schemas/ConfluenceSchema.ts +0 -56
- package/src/schemas/ConversionSchema.ts +0 -318
- package/src/schemas/MarkdownSchema.ts +0 -56
- package/src/schemas/hast/HastFromHtml.ts +0 -153
- package/src/schemas/hast/HastSchema.ts +0 -274
- package/src/schemas/hast/index.ts +0 -35
- package/src/schemas/index.ts +0 -20
- package/src/schemas/mdast/MdastFromMarkdown.ts +0 -118
- package/src/schemas/mdast/MdastSchema.ts +0 -566
- package/src/schemas/mdast/index.ts +0 -59
- package/src/schemas/mdast/mdastToString.ts +0 -102
- package/src/schemas/nodes/block/BlockSchema.ts +0 -773
- package/src/schemas/nodes/block/index.ts +0 -13
- package/src/schemas/nodes/index.ts +0 -20
- package/src/schemas/nodes/inline/InlineSchema.ts +0 -523
- package/src/schemas/nodes/inline/index.ts +0 -14
- package/src/schemas/nodes/macro/MacroSchema.ts +0 -226
- package/src/schemas/nodes/macro/index.ts +0 -6
- package/src/schemas/preprocessing/ConfluencePreprocessor.ts +0 -455
- package/src/schemas/preprocessing/index.ts +0 -8
- package/src/serializers/ConfluenceSerializer.ts +0 -737
- package/src/serializers/MarkdownSerializer.ts +0 -543
- package/src/serializers/index.ts +0 -8
- package/test/ast/BlockNode.test.ts +0 -265
- package/test/ast/Document.test.ts +0 -126
- package/test/ast/InlineNode.test.ts +0 -161
- package/test/fixtures/integration-test.html.fixture +0 -103
- package/test/fixtures/integration-test.md.expected +0 -257
- package/test/parsers/ConfluenceParser.test.ts +0 -452
- package/test/schemas/ConfluencePreprocessor.test.ts +0 -180
- package/test/schemas/ConversionSchema.test.ts +0 -159
- package/test/schemas/HastSchema.test.ts +0 -138
- package/test/schemas/MdastSchema.test.ts +0 -145
- package/test/schemas/nodes/block/BlockSchema.test.ts +0 -173
- package/test/schemas/nodes/inline/InlineSchema.test.ts +0 -198
- package/test/schemas/nodes/macro/MacroSchema.test.ts +0 -142
package/src/Brand.ts
CHANGED
|
@@ -26,9 +26,8 @@ export type PageId = string & Brand.Brand<"PageId">
|
|
|
26
26
|
*
|
|
27
27
|
* @category Brand
|
|
28
28
|
*/
|
|
29
|
-
export const PageId = Brand.
|
|
30
|
-
|
|
31
|
-
(s) => Brand.error(`Invalid page ID: "${s}" (must be non-empty string)`)
|
|
29
|
+
export const PageId = Brand.make<PageId>((s) =>
|
|
30
|
+
typeof s === "string" && s.length > 0 || `Invalid page ID: "${s}" (must be non-empty string)`
|
|
32
31
|
)
|
|
33
32
|
|
|
34
33
|
/**
|
|
@@ -36,10 +35,7 @@ export const PageId = Brand.refined<PageId>(
|
|
|
36
35
|
*
|
|
37
36
|
* @category Schema
|
|
38
37
|
*/
|
|
39
|
-
export const PageIdSchema = Schema.
|
|
40
|
-
Schema.nonEmptyString(),
|
|
41
|
-
Schema.brand("PageId")
|
|
42
|
-
)
|
|
38
|
+
export const PageIdSchema = Schema.NonEmptyString.pipe(Schema.brand("PageId"))
|
|
43
39
|
|
|
44
40
|
/**
|
|
45
41
|
* Branded type for Confluence space keys.
|
|
@@ -60,9 +56,9 @@ export type SpaceKey = string & Brand.Brand<"SpaceKey">
|
|
|
60
56
|
*
|
|
61
57
|
* @category Brand
|
|
62
58
|
*/
|
|
63
|
-
export const SpaceKey = Brand.
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
export const SpaceKey = Brand.make<SpaceKey>((s) =>
|
|
60
|
+
typeof s === "string" && s.length > 0 && /^[A-Z0-9]+$/.test(s)
|
|
61
|
+
|| `Invalid space key: "${s}" (must be uppercase alphanumeric)`
|
|
66
62
|
)
|
|
67
63
|
|
|
68
64
|
/**
|
|
@@ -71,8 +67,7 @@ export const SpaceKey = Brand.refined<SpaceKey>(
|
|
|
71
67
|
* @category Schema
|
|
72
68
|
*/
|
|
73
69
|
export const SpaceKeySchema = Schema.String.pipe(
|
|
74
|
-
Schema.
|
|
75
|
-
Schema.pattern(/^[A-Z0-9]+$/),
|
|
70
|
+
Schema.check(Schema.isNonEmpty(), Schema.isPattern(/^[A-Z0-9]+$/)),
|
|
76
71
|
Schema.brand("SpaceKey")
|
|
77
72
|
)
|
|
78
73
|
|
|
@@ -88,9 +83,9 @@ export type ContentHash = string & Brand.Brand<"ContentHash">
|
|
|
88
83
|
*
|
|
89
84
|
* @category Brand
|
|
90
85
|
*/
|
|
91
|
-
export const ContentHash = Brand.
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
export const ContentHash = Brand.make<ContentHash>((s) =>
|
|
87
|
+
typeof s === "string" && /^[a-f0-9]{64}$/.test(s)
|
|
88
|
+
|| `Invalid content hash: "${s}" (must be 64-char hex string)`
|
|
94
89
|
)
|
|
95
90
|
|
|
96
91
|
/**
|
|
@@ -99,6 +94,6 @@ export const ContentHash = Brand.refined<ContentHash>(
|
|
|
99
94
|
* @category Schema
|
|
100
95
|
*/
|
|
101
96
|
export const ContentHashSchema = Schema.String.pipe(
|
|
102
|
-
Schema.
|
|
97
|
+
Schema.check(Schema.isPattern(/^[a-f0-9]{64}$/)),
|
|
103
98
|
Schema.brand("ContentHash")
|
|
104
99
|
)
|
package/src/ConfluenceAuth.ts
CHANGED
|
@@ -11,12 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
|
-
import * as
|
|
15
|
-
import * as NodePath from "@effect/platform-node/NodePath"
|
|
16
|
-
import * as Command from "@effect/platform/Command"
|
|
17
|
-
import * as CommandExecutor from "@effect/platform/CommandExecutor"
|
|
18
|
-
import * as HttpClient from "@effect/platform/HttpClient"
|
|
19
|
-
import * as HttpClientRequest from "@effect/platform/HttpClientRequest"
|
|
14
|
+
import * as NodeServices from "@effect/platform-node/NodeServices"
|
|
20
15
|
import * as Console from "effect/Console"
|
|
21
16
|
import * as Context from "effect/Context"
|
|
22
17
|
import * as Deferred from "effect/Deferred"
|
|
@@ -25,6 +20,9 @@ import * as Layer from "effect/Layer"
|
|
|
25
20
|
import * as Option from "effect/Option"
|
|
26
21
|
import * as Ref from "effect/Ref"
|
|
27
22
|
import * as Schema from "effect/Schema"
|
|
23
|
+
import { HttpClient, HttpClientRequest } from "effect/unstable/http"
|
|
24
|
+
import { ChildProcessSpawner } from "effect/unstable/process"
|
|
25
|
+
import * as ChildProcess from "effect/unstable/process/ChildProcess"
|
|
28
26
|
import type { FileSystemError } from "./ConfluenceError.js"
|
|
29
27
|
import { AuthMissingError, OAuthError } from "./ConfluenceError.js"
|
|
30
28
|
import { HttpServerFactoryLive } from "./internal/NodeLayers.js"
|
|
@@ -41,8 +39,7 @@ import type { OAuthConfig, OAuthToken, OAuthUser } from "./Schemas.js"
|
|
|
41
39
|
|
|
42
40
|
// Layer for token storage operations (FileSystem + Path + HomeDirectory)
|
|
43
41
|
const TokenStorageLive = Layer.mergeAll(
|
|
44
|
-
|
|
45
|
-
NodePath.layer,
|
|
42
|
+
NodeServices.layer,
|
|
46
43
|
HomeDirectoryLive
|
|
47
44
|
)
|
|
48
45
|
|
|
@@ -168,10 +165,10 @@ export interface ConfluenceAuthService {
|
|
|
168
165
|
*
|
|
169
166
|
* @category Services
|
|
170
167
|
*/
|
|
171
|
-
export class ConfluenceAuth extends Context.
|
|
168
|
+
export class ConfluenceAuth extends Context.Service<
|
|
172
169
|
ConfluenceAuth,
|
|
173
170
|
ConfluenceAuthService
|
|
174
|
-
>() {}
|
|
171
|
+
>()("@knpkv/confluence-to-markdown/ConfluenceAuth") {}
|
|
175
172
|
|
|
176
173
|
const buildAuthUrl = (clientId: string, state: string, port: number): string => {
|
|
177
174
|
const params = new URLSearchParams({
|
|
@@ -195,7 +192,7 @@ const saveOAuthConfigOp = (config: OAuthConfig) => saveOAuthConfig(config).pipe(
|
|
|
195
192
|
|
|
196
193
|
const make = Effect.gen(function*() {
|
|
197
194
|
const httpClient = yield* HttpClient.HttpClient
|
|
198
|
-
const
|
|
195
|
+
const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
199
196
|
|
|
200
197
|
// Ref to track ongoing refresh operation to prevent concurrent refreshes
|
|
201
198
|
const refreshLock = yield* Ref.make<Option.Option<Deferred.Deferred<OAuthToken, OAuthError | FileSystemError>>>(
|
|
@@ -204,19 +201,14 @@ const make = Effect.gen(function*() {
|
|
|
204
201
|
|
|
205
202
|
const openBrowserImpl = (url: string): Effect.Effect<void, OAuthError> =>
|
|
206
203
|
Effect.gen(function*() {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
command = Command.make("open", url)
|
|
212
|
-
} else if (platform === "win32") {
|
|
213
|
-
command = Command.make("cmd", "/c", "start", "", url)
|
|
214
|
-
} else {
|
|
215
|
-
command = Command.make("xdg-open", url)
|
|
216
|
-
}
|
|
204
|
+
const run = (command: ChildProcess.Command) =>
|
|
205
|
+
childProcessSpawner.exitCode(command).pipe(
|
|
206
|
+
Effect.flatMap((code) => code === 0 ? Effect.void : Effect.fail(code))
|
|
207
|
+
)
|
|
217
208
|
|
|
218
|
-
yield*
|
|
219
|
-
Effect.
|
|
209
|
+
yield* run(ChildProcess.make("open", [url])).pipe(
|
|
210
|
+
Effect.catchIf(() => true, () => run(ChildProcess.make("xdg-open", [url]))),
|
|
211
|
+
Effect.catchIf(() => true, () => run(ChildProcess.make("rundll32.exe", ["url.dll,FileProtocolHandler", url])))
|
|
220
212
|
)
|
|
221
213
|
}).pipe(
|
|
222
214
|
Effect.mapError((cause) => new OAuthError({ step: "authorize", cause }))
|
|
@@ -256,7 +248,7 @@ const make = Effect.gen(function*() {
|
|
|
256
248
|
const response = yield* httpClient.execute(request)
|
|
257
249
|
const body = yield* response.json
|
|
258
250
|
|
|
259
|
-
return yield* Schema.
|
|
251
|
+
return yield* Schema.decodeUnknownEffect(TokenResponseSchema)(body)
|
|
260
252
|
}).pipe(
|
|
261
253
|
Effect.mapError((cause) => new OAuthError({ step: "token", cause }))
|
|
262
254
|
)
|
|
@@ -273,7 +265,7 @@ const make = Effect.gen(function*() {
|
|
|
273
265
|
const response = yield* httpClient.execute(request)
|
|
274
266
|
const body = yield* response.json
|
|
275
267
|
|
|
276
|
-
return yield* Schema.
|
|
268
|
+
return yield* Schema.decodeUnknownEffect(Schema.Array(AccessibleResourceSchema))(body)
|
|
277
269
|
}).pipe(
|
|
278
270
|
Effect.mapError((cause) => new OAuthError({ step: "authorize", cause }))
|
|
279
271
|
)
|
|
@@ -290,7 +282,7 @@ const make = Effect.gen(function*() {
|
|
|
290
282
|
const response = yield* httpClient.execute(request)
|
|
291
283
|
const body = yield* response.json
|
|
292
284
|
|
|
293
|
-
return yield* Schema.
|
|
285
|
+
return yield* Schema.decodeUnknownEffect(UserInfoSchema)(body)
|
|
294
286
|
}).pipe(
|
|
295
287
|
Effect.mapError((cause) => new OAuthError({ step: "authorize", cause }))
|
|
296
288
|
)
|
|
@@ -317,7 +309,7 @@ const make = Effect.gen(function*() {
|
|
|
317
309
|
const body = yield* response.json.pipe(
|
|
318
310
|
Effect.mapError((cause) => new OAuthError({ step: "refresh", cause }))
|
|
319
311
|
)
|
|
320
|
-
const tokenResponse = yield* Schema.
|
|
312
|
+
const tokenResponse = yield* Schema.decodeUnknownEffect(TokenResponseSchema)(body).pipe(
|
|
321
313
|
Effect.mapError((cause) => new OAuthError({ step: "refresh", cause }))
|
|
322
314
|
)
|
|
323
315
|
|
|
@@ -389,7 +381,7 @@ const make = Effect.gen(function*() {
|
|
|
389
381
|
|
|
390
382
|
const code = yield* codePromise.pipe(
|
|
391
383
|
Effect.timeout("5 minutes"),
|
|
392
|
-
Effect.catchTag("
|
|
384
|
+
Effect.catchTag("TimeoutError", () =>
|
|
393
385
|
Effect.fail(new OAuthError({ step: "authorize", cause: "Authorization timed out" })))
|
|
394
386
|
)
|
|
395
387
|
|
|
@@ -476,7 +468,7 @@ const make = Effect.gen(function*() {
|
|
|
476
468
|
if (config !== null) {
|
|
477
469
|
yield* revokeToken(token, config).pipe(
|
|
478
470
|
Effect.tap(() => Effect.log("Token revoked with Atlassian")),
|
|
479
|
-
Effect.
|
|
471
|
+
Effect.catchIf(() => true, (error) => Effect.log(`Warning: Failed to revoke token: ${error.message}`))
|
|
480
472
|
)
|
|
481
473
|
}
|
|
482
474
|
|
|
@@ -577,5 +569,5 @@ const make = Effect.gen(function*() {
|
|
|
577
569
|
export const layer: Layer.Layer<
|
|
578
570
|
ConfluenceAuth,
|
|
579
571
|
never,
|
|
580
|
-
HttpClient.HttpClient |
|
|
572
|
+
HttpClient.HttpClient | ChildProcessSpawner.ChildProcessSpawner
|
|
581
573
|
> = Layer.effect(ConfluenceAuth, make)
|
package/src/ConfluenceClient.ts
CHANGED
|
@@ -26,7 +26,7 @@ export interface CreatePageRequest {
|
|
|
26
26
|
readonly title: string
|
|
27
27
|
readonly parentId?: string
|
|
28
28
|
readonly body: {
|
|
29
|
-
readonly representation: "
|
|
29
|
+
readonly representation: "atlas_doc_format"
|
|
30
30
|
readonly value: string
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -45,7 +45,7 @@ export interface UpdatePageRequest {
|
|
|
45
45
|
readonly message?: string
|
|
46
46
|
}
|
|
47
47
|
readonly body: {
|
|
48
|
-
readonly representation: "
|
|
48
|
+
readonly representation: "atlas_doc_format"
|
|
49
49
|
readonly value: string
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -67,9 +67,7 @@ export interface UpdatePageRequest {
|
|
|
67
67
|
*
|
|
68
68
|
* @category Client
|
|
69
69
|
*/
|
|
70
|
-
export class ConfluenceClient extends Context.
|
|
71
|
-
"@knpkv/confluence-to-markdown/ConfluenceClient"
|
|
72
|
-
)<
|
|
70
|
+
export class ConfluenceClient extends Context.Service<
|
|
73
71
|
ConfluenceClient,
|
|
74
72
|
{
|
|
75
73
|
/**
|
|
@@ -126,7 +124,7 @@ export class ConfluenceClient extends Context.Tag(
|
|
|
126
124
|
*/
|
|
127
125
|
readonly setEditorVersion: (pageId: PageId, version: "v1" | "v2") => Effect.Effect<void, ApiError | RateLimitError>
|
|
128
126
|
}
|
|
129
|
-
>() {}
|
|
127
|
+
>()("@knpkv/confluence-to-markdown/ConfluenceClient") {}
|
|
130
128
|
|
|
131
129
|
/**
|
|
132
130
|
* Configuration for the Confluence client.
|
|
@@ -155,11 +153,17 @@ const VERSIONS_PAGE_SIZE = 50
|
|
|
155
153
|
/**
|
|
156
154
|
* Rate limit retry schedule with exponential backoff.
|
|
157
155
|
*/
|
|
158
|
-
const
|
|
159
|
-
Schedule.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
156
|
+
const rateLimitRetry = {
|
|
157
|
+
schedule: Schedule.exponential("1 second").pipe(
|
|
158
|
+
Schedule.either(Schedule.spaced("30 seconds"))
|
|
159
|
+
),
|
|
160
|
+
times: 3,
|
|
161
|
+
while: (error: unknown) =>
|
|
162
|
+
typeof error === "object" &&
|
|
163
|
+
error !== null &&
|
|
164
|
+
"_tag" in error &&
|
|
165
|
+
error._tag === "RateLimitError"
|
|
166
|
+
} as const
|
|
163
167
|
|
|
164
168
|
/**
|
|
165
169
|
* Map API client errors to domain errors.
|
|
@@ -177,7 +181,7 @@ const mapApiError = (error: FetchClientError, endpoint: string, pageId?: string)
|
|
|
177
181
|
*/
|
|
178
182
|
const make = (
|
|
179
183
|
config: ConfluenceClientConfig
|
|
180
|
-
): Effect.Effect<Context.
|
|
184
|
+
): Effect.Effect<Context.Service.Shape<typeof ConfluenceClient>> =>
|
|
181
185
|
Effect.gen(function*() {
|
|
182
186
|
// Create underlying API client
|
|
183
187
|
const apiConfigLayer = Layer.succeed(ConfluenceApiConfig, {
|
|
@@ -194,10 +198,10 @@ const make = (
|
|
|
194
198
|
|
|
195
199
|
const getPage = (id: PageId): Effect.Effect<PageResponse, ApiError | RateLimitError> =>
|
|
196
200
|
toEffect(apiClient.v2.client.GET("/pages/{id}", {
|
|
197
|
-
params: { path: { id: Number(id) }, query: { "body-format": "
|
|
201
|
+
params: { path: { id: Number(id) }, query: { "body-format": "atlas_doc_format" } }
|
|
198
202
|
})).pipe(
|
|
199
203
|
Effect.mapError((e) => mapApiError(e, `/pages/${id}`, id)),
|
|
200
|
-
Effect.retry(
|
|
204
|
+
Effect.retry(rateLimitRetry)
|
|
201
205
|
) as Effect.Effect<PageResponse, ApiError | RateLimitError>
|
|
202
206
|
|
|
203
207
|
const getChildren = (id: PageId): Effect.Effect<PageChildrenResponse, ApiError | RateLimitError> =>
|
|
@@ -205,7 +209,7 @@ const make = (
|
|
|
205
209
|
params: { path: { id: Number(id) } }
|
|
206
210
|
})).pipe(
|
|
207
211
|
Effect.mapError((e) => mapApiError(e, `/pages/${id}/children`, id)),
|
|
208
|
-
Effect.retry(
|
|
212
|
+
Effect.retry(rateLimitRetry)
|
|
209
213
|
) as Effect.Effect<PageChildrenResponse, ApiError | RateLimitError>
|
|
210
214
|
|
|
211
215
|
const getAllChildren = (id: PageId): Effect.Effect<ReadonlyArray<PageListItem>, ApiError | RateLimitError> =>
|
|
@@ -230,7 +234,7 @@ const make = (
|
|
|
230
234
|
params: { path: { id: Number(id) }, query: { ...(cursor ? { cursor } : {}) } }
|
|
231
235
|
})).pipe(
|
|
232
236
|
Effect.mapError((e) => mapApiError(e, `/pages/${id}/children`, id)),
|
|
233
|
-
Effect.retry(
|
|
237
|
+
Effect.retry(rateLimitRetry)
|
|
234
238
|
)
|
|
235
239
|
|
|
236
240
|
for (const child of (response as { results?: Array<PageListItem> }).results ?? []) {
|
|
@@ -260,7 +264,7 @@ const make = (
|
|
|
260
264
|
}
|
|
261
265
|
})).pipe(
|
|
262
266
|
Effect.mapError((e) => mapApiError(e, "/pages")),
|
|
263
|
-
Effect.retry(
|
|
267
|
+
Effect.retry(rateLimitRetry)
|
|
264
268
|
) as Effect.Effect<PageResponse, ApiError | RateLimitError>
|
|
265
269
|
|
|
266
270
|
const updatePage = (req: UpdatePageRequest): Effect.Effect<PageResponse, ApiError | RateLimitError> =>
|
|
@@ -275,7 +279,7 @@ const make = (
|
|
|
275
279
|
}
|
|
276
280
|
})).pipe(
|
|
277
281
|
Effect.mapError((e) => mapApiError(e, `/pages/${req.id}`, req.id)),
|
|
278
|
-
Effect.retry(
|
|
282
|
+
Effect.retry(rateLimitRetry)
|
|
279
283
|
) as Effect.Effect<PageResponse, ApiError | RateLimitError>
|
|
280
284
|
|
|
281
285
|
const deletePage = (id: PageId): Effect.Effect<void, ApiError | RateLimitError> =>
|
|
@@ -284,7 +288,7 @@ const make = (
|
|
|
284
288
|
})).pipe(
|
|
285
289
|
Effect.map(() => void 0),
|
|
286
290
|
Effect.mapError((e) => mapApiError(e, `/pages/${id}`, id)),
|
|
287
|
-
Effect.retry(
|
|
291
|
+
Effect.retry(rateLimitRetry)
|
|
288
292
|
)
|
|
289
293
|
|
|
290
294
|
const getPageVersions = (
|
|
@@ -312,14 +316,14 @@ const make = (
|
|
|
312
316
|
params: {
|
|
313
317
|
path: { id: Number(id) },
|
|
314
318
|
query: {
|
|
315
|
-
...(options?.includeBody ? { "body-format": "
|
|
319
|
+
...(options?.includeBody ? { "body-format": "atlas_doc_format" as const } : {}),
|
|
316
320
|
...(cursor ? { cursor } : {}),
|
|
317
321
|
limit: VERSIONS_PAGE_SIZE
|
|
318
322
|
}
|
|
319
323
|
}
|
|
320
324
|
})).pipe(
|
|
321
325
|
Effect.mapError((e) => mapApiError(e, `/pages/${id}/versions`, id)),
|
|
322
|
-
Effect.retry(
|
|
326
|
+
Effect.retry(rateLimitRetry)
|
|
323
327
|
)
|
|
324
328
|
|
|
325
329
|
for (const version of (response as { results?: Array<PageVersion> }).results ?? []) {
|
|
@@ -345,7 +349,7 @@ const make = (
|
|
|
345
349
|
params: { query: { accountId } }
|
|
346
350
|
})).pipe(
|
|
347
351
|
Effect.mapError((e) => mapApiError(e, `/user?accountId=${accountId}`)),
|
|
348
|
-
Effect.retry(
|
|
352
|
+
Effect.retry(rateLimitRetry)
|
|
349
353
|
) as Effect.Effect<AtlassianUser, ApiError | RateLimitError>
|
|
350
354
|
|
|
351
355
|
const getSpaceId = (pageId: PageId): Effect.Effect<string, ApiError | RateLimitError> =>
|
|
@@ -401,7 +405,7 @@ const make = (
|
|
|
401
405
|
Effect.mapError((e) => mapApiError(e, `/pages/${pageId}/properties/editor`, pageId))
|
|
402
406
|
)
|
|
403
407
|
}
|
|
404
|
-
}).pipe(Effect.retry(
|
|
408
|
+
}).pipe(Effect.retry(rateLimitRetry))
|
|
405
409
|
|
|
406
410
|
return ConfluenceClient.of({
|
|
407
411
|
getPage,
|
|
@@ -438,7 +442,7 @@ const make = (
|
|
|
438
442
|
* auth: {
|
|
439
443
|
* type: "token",
|
|
440
444
|
* email: "you@example.com",
|
|
441
|
-
* token:
|
|
445
|
+
* token: "<api-token>"
|
|
442
446
|
* }
|
|
443
447
|
* }))
|
|
444
448
|
* )
|
package/src/ConfluenceConfig.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import * as FileSystem from "@effect/platform/FileSystem"
|
|
7
|
-
import * as Path from "@effect/platform/Path"
|
|
8
6
|
import * as Context from "effect/Context"
|
|
9
7
|
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as FileSystem from "effect/FileSystem"
|
|
10
9
|
import * as Layer from "effect/Layer"
|
|
10
|
+
import * as Path from "effect/Path"
|
|
11
11
|
import * as Schema from "effect/Schema"
|
|
12
12
|
import type { PageId } from "./Brand.js"
|
|
13
13
|
import { ConfigNotFoundError, ConfigParseError } from "./ConfluenceError.js"
|
|
@@ -31,9 +31,7 @@ import { ConfluenceConfigFileSchema } from "./Schemas.js"
|
|
|
31
31
|
*
|
|
32
32
|
* @category Config
|
|
33
33
|
*/
|
|
34
|
-
export class ConfluenceConfig extends Context.
|
|
35
|
-
"@knpkv/confluence-to-markdown/ConfluenceConfig"
|
|
36
|
-
)<
|
|
34
|
+
export class ConfluenceConfig extends Context.Service<
|
|
37
35
|
ConfluenceConfig,
|
|
38
36
|
{
|
|
39
37
|
/** Root page ID to sync from */
|
|
@@ -51,7 +49,7 @@ export class ConfluenceConfig extends Context.Tag(
|
|
|
51
49
|
/** Glob patterns for files to track in git */
|
|
52
50
|
readonly trackedPaths: ReadonlyArray<string>
|
|
53
51
|
}
|
|
54
|
-
>() {}
|
|
52
|
+
>()("@knpkv/confluence-to-markdown/ConfluenceConfig") {}
|
|
55
53
|
|
|
56
54
|
/**
|
|
57
55
|
* Default config directory.
|
|
@@ -73,7 +71,7 @@ const loadConfig = (
|
|
|
73
71
|
const fs = yield* FileSystem.FileSystem
|
|
74
72
|
|
|
75
73
|
const exists = yield* fs.exists(configPath).pipe(
|
|
76
|
-
Effect.
|
|
74
|
+
Effect.catchCause(() => Effect.succeed(false))
|
|
77
75
|
)
|
|
78
76
|
if (!exists) {
|
|
79
77
|
return yield* Effect.fail(new ConfigNotFoundError({ path: configPath }))
|
|
@@ -88,7 +86,7 @@ const loadConfig = (
|
|
|
88
86
|
catch: (cause) => new ConfigParseError({ path: configPath, cause })
|
|
89
87
|
})
|
|
90
88
|
|
|
91
|
-
return yield* Schema.
|
|
89
|
+
return yield* Schema.decodeUnknownEffect(ConfluenceConfigFileSchema)(json).pipe(
|
|
92
90
|
Effect.mapError((cause) => new ConfigParseError({ path: configPath, cause }))
|
|
93
91
|
)
|
|
94
92
|
})
|
|
@@ -99,7 +97,7 @@ const loadConfig = (
|
|
|
99
97
|
* @example
|
|
100
98
|
* ```typescript
|
|
101
99
|
* import { ConfluenceConfig } from "@knpkv/confluence-to-markdown/ConfluenceConfig"
|
|
102
|
-
* import {
|
|
100
|
+
* import { NodeContext } from "@effect/platform-node"
|
|
103
101
|
* import { Effect } from "effect"
|
|
104
102
|
*
|
|
105
103
|
* const program = Effect.gen(function* () {
|
|
@@ -110,7 +108,7 @@ const loadConfig = (
|
|
|
110
108
|
* Effect.runPromise(
|
|
111
109
|
* program.pipe(
|
|
112
110
|
* Effect.provide(ConfluenceConfig.layer()),
|
|
113
|
-
* Effect.provide(
|
|
111
|
+
* Effect.provide(NodeContext.layer)
|
|
114
112
|
* )
|
|
115
113
|
* )
|
|
116
114
|
* ```
|
|
@@ -153,7 +151,8 @@ export const layer = (
|
|
|
153
151
|
ConfluenceConfig,
|
|
154
152
|
Effect.gen(function*() {
|
|
155
153
|
const path = yield* Path.Path
|
|
156
|
-
const
|
|
154
|
+
const cwd = path.resolve(".")
|
|
155
|
+
const resolvedPath = configPath ?? path.join(cwd, CONFIG_DIR, CONFIG_FILE_NAME)
|
|
157
156
|
const config = yield* loadConfig(resolvedPath)
|
|
158
157
|
|
|
159
158
|
// Validate docsPath
|
|
@@ -206,7 +205,8 @@ export const createConfigFile = (
|
|
|
206
205
|
const fs = yield* FileSystem.FileSystem
|
|
207
206
|
const pathService = yield* Path.Path
|
|
208
207
|
|
|
209
|
-
const
|
|
208
|
+
const cwd = pathService.resolve(".")
|
|
209
|
+
const configDir = pathService.join(cwd, CONFIG_DIR)
|
|
210
210
|
const resolvedPath = configPath ?? pathService.join(configDir, CONFIG_FILE_NAME)
|
|
211
211
|
|
|
212
212
|
const config: ConfluenceConfigFile = {
|
|
@@ -219,12 +219,12 @@ export const createConfigFile = (
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
// Validate the config
|
|
222
|
-
yield* Schema.
|
|
222
|
+
yield* Schema.decodeUnknownEffect(ConfluenceConfigFileSchema)(config).pipe(
|
|
223
223
|
Effect.mapError((cause) => new ConfigParseError({ path: resolvedPath, cause }))
|
|
224
224
|
)
|
|
225
225
|
|
|
226
226
|
// Create .confluence directory if it doesn't exist
|
|
227
|
-
const dirExists = yield* fs.exists(configDir).pipe(Effect.
|
|
227
|
+
const dirExists = yield* fs.exists(configDir).pipe(Effect.catchCause(() => Effect.succeed(false)))
|
|
228
228
|
if (!dirExists) {
|
|
229
229
|
yield* fs.makeDirectory(configDir, { recursive: true }).pipe(
|
|
230
230
|
Effect.mapError((cause) => new ConfigParseError({ path: configDir, cause }))
|
package/src/ConfluenceError.ts
CHANGED
|
@@ -124,16 +124,23 @@ export class RateLimitError extends Data.TaggedError("RateLimitError")<{
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
*
|
|
127
|
+
* Direction of an ADF/Markdown conversion.
|
|
128
|
+
*
|
|
129
|
+
* @category Errors
|
|
130
|
+
*/
|
|
131
|
+
export type ConversionDirection = "adfToMarkdown" | "markdownToAdf"
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Error thrown when ADF/Markdown conversion fails.
|
|
128
135
|
*
|
|
129
136
|
* @category Errors
|
|
130
137
|
*/
|
|
131
138
|
export class ConversionError extends Data.TaggedError("ConversionError")<{
|
|
132
|
-
readonly direction:
|
|
139
|
+
readonly direction: ConversionDirection
|
|
133
140
|
readonly cause: unknown
|
|
134
141
|
readonly message: string
|
|
135
142
|
}> {
|
|
136
|
-
constructor(params: { direction:
|
|
143
|
+
constructor(params: { direction: ConversionDirection; cause: unknown }) {
|
|
137
144
|
super({
|
|
138
145
|
direction: params.direction,
|
|
139
146
|
cause: params.cause,
|
|
@@ -142,6 +149,57 @@ export class ConversionError extends Data.TaggedError("ConversionError")<{
|
|
|
142
149
|
}
|
|
143
150
|
}
|
|
144
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Issue produced by ADF JSON Schema validation.
|
|
154
|
+
*
|
|
155
|
+
* @category Errors
|
|
156
|
+
*/
|
|
157
|
+
export interface AdfSchemaIssue {
|
|
158
|
+
readonly instancePath?: string
|
|
159
|
+
readonly schemaPath?: string
|
|
160
|
+
readonly keyword?: string
|
|
161
|
+
readonly message?: string
|
|
162
|
+
readonly params?: Record<string, unknown>
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Error thrown when an ADF document fails JSON Schema validation.
|
|
167
|
+
*
|
|
168
|
+
* @category Errors
|
|
169
|
+
*/
|
|
170
|
+
export class AdfSchemaError extends Data.TaggedError("AdfSchemaError")<{
|
|
171
|
+
readonly direction: "incoming" | "outgoing"
|
|
172
|
+
readonly issues: ReadonlyArray<AdfSchemaIssue>
|
|
173
|
+
readonly message: string
|
|
174
|
+
}> {
|
|
175
|
+
constructor(params: { direction: "incoming" | "outgoing"; issues: ReadonlyArray<AdfSchemaIssue> }) {
|
|
176
|
+
super({
|
|
177
|
+
direction: params.direction,
|
|
178
|
+
issues: params.issues,
|
|
179
|
+
message: `ADF schema validation failed (${params.direction}): ${params.issues.length} issue(s)`
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Error thrown when the wrapped @atlaskit transformer libraries throw.
|
|
186
|
+
*
|
|
187
|
+
* @category Errors
|
|
188
|
+
*/
|
|
189
|
+
export class AtlaskitTransformersError extends Data.TaggedError("AtlaskitTransformersError")<{
|
|
190
|
+
readonly cause: unknown
|
|
191
|
+
readonly message: string
|
|
192
|
+
}> {
|
|
193
|
+
constructor(params: { cause: unknown }) {
|
|
194
|
+
super({
|
|
195
|
+
cause: params.cause,
|
|
196
|
+
message: `Atlaskit transformer failed: ${
|
|
197
|
+
params.cause instanceof Error ? params.cause.message : String(params.cause)
|
|
198
|
+
}`
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
145
203
|
/**
|
|
146
204
|
* Error thrown when sync conflict is detected.
|
|
147
205
|
*
|
|
@@ -255,6 +313,8 @@ export type ConfluenceError =
|
|
|
255
313
|
| ApiError
|
|
256
314
|
| RateLimitError
|
|
257
315
|
| ConversionError
|
|
316
|
+
| AdfSchemaError
|
|
317
|
+
| AtlaskitTransformersError
|
|
258
318
|
| ConflictError
|
|
259
319
|
| FileSystemError
|
|
260
320
|
| OAuthError
|
|
@@ -281,6 +341,8 @@ export const isConfluenceError = (error: unknown): error is ConfluenceError =>
|
|
|
281
341
|
"ApiError",
|
|
282
342
|
"RateLimitError",
|
|
283
343
|
"ConversionError",
|
|
344
|
+
"AdfSchemaError",
|
|
345
|
+
"AtlaskitTransformersError",
|
|
284
346
|
"ConflictError",
|
|
285
347
|
"FileSystemError",
|
|
286
348
|
"OAuthError",
|