@knpkv/confluence-to-markdown 0.6.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.
Files changed (357) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +22 -13
  4. package/dist/AdfPlaceholders.d.ts +42 -0
  5. package/dist/AdfPlaceholders.d.ts.map +1 -0
  6. package/dist/AdfPlaceholders.js +547 -0
  7. package/dist/AdfPlaceholders.js.map +1 -0
  8. package/dist/AdfSchemaValidator.d.ts +37 -0
  9. package/dist/AdfSchemaValidator.d.ts.map +1 -0
  10. package/dist/AdfSchemaValidator.js +37 -0
  11. package/dist/AdfSchemaValidator.js.map +1 -0
  12. package/dist/AdfWalker.d.ts +39 -0
  13. package/dist/AdfWalker.d.ts.map +1 -0
  14. package/dist/AdfWalker.js +527 -0
  15. package/dist/AdfWalker.js.map +1 -0
  16. package/dist/AtlaskitTransformers.d.ts +35 -0
  17. package/dist/AtlaskitTransformers.d.ts.map +1 -0
  18. package/dist/AtlaskitTransformers.js +48 -0
  19. package/dist/AtlaskitTransformers.js.map +1 -0
  20. package/dist/Brand.d.ts +6 -6
  21. package/dist/Brand.d.ts.map +1 -1
  22. package/dist/Brand.js +8 -6
  23. package/dist/Brand.js.map +1 -1
  24. package/dist/ConfluenceAuth.d.ts +4 -4
  25. package/dist/ConfluenceAuth.d.ts.map +1 -1
  26. package/dist/ConfluenceAuth.js +37 -39
  27. package/dist/ConfluenceAuth.js.map +1 -1
  28. package/dist/ConfluenceClient.d.ts +7 -17
  29. package/dist/ConfluenceClient.d.ts.map +1 -1
  30. package/dist/ConfluenceClient.js +81 -38
  31. package/dist/ConfluenceClient.js.map +1 -1
  32. package/dist/ConfluenceConfig.d.ts +3 -3
  33. package/dist/ConfluenceConfig.d.ts.map +1 -1
  34. package/dist/ConfluenceConfig.js +13 -11
  35. package/dist/ConfluenceConfig.js.map +1 -1
  36. package/dist/ConfluenceError.d.ts +68 -16
  37. package/dist/ConfluenceError.d.ts.map +1 -1
  38. package/dist/ConfluenceError.js +30 -1
  39. package/dist/ConfluenceError.js.map +1 -1
  40. package/dist/GitError.d.ts +5 -5
  41. package/dist/GitService.d.ts +11 -3
  42. package/dist/GitService.d.ts.map +1 -1
  43. package/dist/GitService.js +22 -27
  44. package/dist/GitService.js.map +1 -1
  45. package/dist/LocalFileSystem.d.ts +3 -3
  46. package/dist/LocalFileSystem.d.ts.map +1 -1
  47. package/dist/LocalFileSystem.js +6 -6
  48. package/dist/LocalFileSystem.js.map +1 -1
  49. package/dist/MarkdownConverter.d.ts +16 -65
  50. package/dist/MarkdownConverter.d.ts.map +1 -1
  51. package/dist/MarkdownConverter.js +64 -85
  52. package/dist/MarkdownConverter.js.map +1 -1
  53. package/dist/Schemas.d.ts +128 -141
  54. package/dist/Schemas.d.ts.map +1 -1
  55. package/dist/Schemas.js +21 -23
  56. package/dist/Schemas.js.map +1 -1
  57. package/dist/SyncEngine.d.ts +8 -5
  58. package/dist/SyncEngine.d.ts.map +1 -1
  59. package/dist/SyncEngine.js +189 -113
  60. package/dist/SyncEngine.js.map +1 -1
  61. package/dist/bin.js +23 -35
  62. package/dist/bin.js.map +1 -1
  63. package/dist/commands/auth.d.ts +2 -14
  64. package/dist/commands/auth.d.ts.map +1 -1
  65. package/dist/commands/auth.js +11 -16
  66. package/dist/commands/auth.js.map +1 -1
  67. package/dist/commands/clone.d.ts +4 -6
  68. package/dist/commands/clone.d.ts.map +1 -1
  69. package/dist/commands/clone.js +34 -32
  70. package/dist/commands/clone.js.map +1 -1
  71. package/dist/commands/delete.d.ts +2 -10
  72. package/dist/commands/delete.d.ts.map +1 -1
  73. package/dist/commands/delete.js +5 -4
  74. package/dist/commands/delete.js.map +1 -1
  75. package/dist/commands/errorHandler.d.ts +2 -1
  76. package/dist/commands/errorHandler.d.ts.map +1 -1
  77. package/dist/commands/errorHandler.js +22 -15
  78. package/dist/commands/errorHandler.js.map +1 -1
  79. package/dist/commands/fetch.d.ts +27 -0
  80. package/dist/commands/fetch.d.ts.map +1 -0
  81. package/dist/commands/fetch.js +48 -0
  82. package/dist/commands/fetch.js.map +1 -0
  83. package/dist/commands/git.d.ts +7 -10
  84. package/dist/commands/git.d.ts.map +1 -1
  85. package/dist/commands/git.js +6 -6
  86. package/dist/commands/git.js.map +1 -1
  87. package/dist/commands/index.d.ts +1 -0
  88. package/dist/commands/index.d.ts.map +1 -1
  89. package/dist/commands/index.js +1 -0
  90. package/dist/commands/index.js.map +1 -1
  91. package/dist/commands/layers.d.ts +10 -9
  92. package/dist/commands/layers.d.ts.map +1 -1
  93. package/dist/commands/layers.js +41 -30
  94. package/dist/commands/layers.js.map +1 -1
  95. package/dist/commands/new.d.ts +2 -6
  96. package/dist/commands/new.d.ts.map +1 -1
  97. package/dist/commands/new.js +5 -4
  98. package/dist/commands/new.js.map +1 -1
  99. package/dist/commands/pageInput.d.ts +19 -0
  100. package/dist/commands/pageInput.d.ts.map +1 -0
  101. package/dist/commands/pageInput.js +68 -0
  102. package/dist/commands/pageInput.js.map +1 -0
  103. package/dist/commands/root.d.ts +8 -0
  104. package/dist/commands/root.d.ts.map +1 -0
  105. package/dist/commands/root.js +29 -0
  106. package/dist/commands/root.js.map +1 -0
  107. package/dist/commands/sync.d.ts +6 -9
  108. package/dist/commands/sync.d.ts.map +1 -1
  109. package/dist/commands/sync.js +5 -6
  110. package/dist/commands/sync.js.map +1 -1
  111. package/dist/index.d.ts +3 -8
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +2 -13
  114. package/dist/index.js.map +1 -1
  115. package/dist/internal/NodeLayers.d.ts.map +1 -1
  116. package/dist/internal/NodeLayers.js +1 -2
  117. package/dist/internal/NodeLayers.js.map +1 -1
  118. package/dist/internal/adfMetadata.d.ts +30 -0
  119. package/dist/internal/adfMetadata.d.ts.map +1 -0
  120. package/dist/internal/adfMetadata.js +126 -0
  121. package/dist/internal/adfMetadata.js.map +1 -0
  122. package/dist/internal/cleanMarkdown.d.ts +5 -0
  123. package/dist/internal/cleanMarkdown.d.ts.map +1 -0
  124. package/dist/internal/cleanMarkdown.js +13 -0
  125. package/dist/internal/cleanMarkdown.js.map +1 -0
  126. package/dist/internal/frontmatter.d.ts.map +1 -1
  127. package/dist/internal/frontmatter.js +41 -8
  128. package/dist/internal/frontmatter.js.map +1 -1
  129. package/dist/internal/gitCommands.d.ts +9 -3
  130. package/dist/internal/gitCommands.d.ts.map +1 -1
  131. package/dist/internal/gitCommands.js +18 -9
  132. package/dist/internal/gitCommands.js.map +1 -1
  133. package/dist/internal/hashUtils.d.ts +1 -1
  134. package/dist/internal/hashUtils.d.ts.map +1 -1
  135. package/dist/internal/hashUtils.js +1 -1
  136. package/dist/internal/hashUtils.js.map +1 -1
  137. package/dist/internal/oauthServer.d.ts +10 -5
  138. package/dist/internal/oauthServer.d.ts.map +1 -1
  139. package/dist/internal/oauthServer.js +19 -40
  140. package/dist/internal/oauthServer.js.map +1 -1
  141. package/dist/internal/pathUtils.d.ts +1 -1
  142. package/dist/internal/pathUtils.d.ts.map +1 -1
  143. package/dist/internal/pathUtils.js +1 -1
  144. package/dist/internal/pathUtils.js.map +1 -1
  145. package/dist/internal/process.d.ts +15 -0
  146. package/dist/internal/process.d.ts.map +1 -0
  147. package/dist/internal/process.js +10 -0
  148. package/dist/internal/process.js.map +1 -0
  149. package/dist/internal/stdio.d.ts +6 -0
  150. package/dist/internal/stdio.d.ts.map +1 -0
  151. package/dist/internal/stdio.js +15 -0
  152. package/dist/internal/stdio.js.map +1 -0
  153. package/dist/internal/tokenStorage.d.ts +3 -13
  154. package/dist/internal/tokenStorage.d.ts.map +1 -1
  155. package/dist/internal/tokenStorage.js +26 -24
  156. package/dist/internal/tokenStorage.js.map +1 -1
  157. package/dist/internal/userCache.d.ts +1 -1
  158. package/dist/internal/userCache.d.ts.map +1 -1
  159. package/dist/internal/userCache.js +1 -1
  160. package/dist/internal/userCache.js.map +1 -1
  161. package/package.json +30 -30
  162. package/skills/confluence/SKILL.md +143 -0
  163. package/skills/confluence/agents/openai.yaml +4 -0
  164. package/src/AdfPlaceholders.ts +310 -13
  165. package/src/AdfSchemaValidator.ts +2 -4
  166. package/src/AdfWalker.ts +122 -42
  167. package/src/AtlaskitTransformers.ts +2 -4
  168. package/src/Brand.ts +11 -16
  169. package/src/ConfluenceAuth.ts +22 -30
  170. package/src/ConfluenceClient.ts +24 -20
  171. package/src/ConfluenceConfig.ts +14 -14
  172. package/src/GitService.ts +39 -49
  173. package/src/LocalFileSystem.ts +7 -9
  174. package/src/MarkdownConverter.ts +2 -4
  175. package/src/Schemas.ts +13 -12
  176. package/src/SyncEngine.ts +151 -53
  177. package/src/bin.ts +30 -56
  178. package/src/commands/auth.ts +21 -18
  179. package/src/commands/clone.ts +38 -37
  180. package/src/commands/delete.ts +5 -4
  181. package/src/commands/errorHandler.ts +25 -18
  182. package/src/commands/fetch.ts +90 -0
  183. package/src/commands/git.ts +6 -6
  184. package/src/commands/index.ts +1 -0
  185. package/src/commands/layers.ts +53 -33
  186. package/src/commands/new.ts +5 -4
  187. package/src/commands/pageInput.ts +103 -0
  188. package/src/commands/root.ts +59 -0
  189. package/src/commands/sync.ts +7 -6
  190. package/src/internal/NodeLayers.ts +1 -2
  191. package/src/internal/adfMetadata.ts +145 -0
  192. package/src/internal/cleanMarkdown.ts +15 -0
  193. package/src/internal/frontmatter.ts +45 -8
  194. package/src/internal/gitCommands.ts +23 -17
  195. package/src/internal/hashUtils.ts +2 -2
  196. package/src/internal/oauthServer.ts +84 -105
  197. package/src/internal/pathUtils.ts +1 -1
  198. package/src/internal/process.ts +15 -0
  199. package/src/internal/stdio.ts +22 -0
  200. package/src/internal/tokenStorage.ts +39 -29
  201. package/src/internal/userCache.ts +2 -2
  202. package/test/AdfPlaceholders.test.ts +213 -0
  203. package/test/AdfSchemaValidator.test.ts +6 -6
  204. package/test/AdfWalker.test.ts +167 -21
  205. package/test/AtlaskitTransformers.test.ts +4 -4
  206. package/test/Brand.test.ts +11 -11
  207. package/test/GitService.test.ts +6 -2
  208. package/test/MarkdownConverter.test.ts +12 -11
  209. package/test/RoundTrip.test.ts +258 -3
  210. package/test/Schemas.test.ts +40 -40
  211. package/test/adfMetadata.test.ts +110 -0
  212. package/test/cleanMarkdown.test.ts +36 -0
  213. package/test/commandHarness.test.ts +79 -0
  214. package/test/commandHarness.ts +147 -0
  215. package/test/fetch.test.ts +61 -0
  216. package/test/frontmatter.test.ts +41 -0
  217. package/test/integration.test.ts +569 -156
  218. package/test/layers.test.ts +12 -0
  219. package/test/oauthServer.test.ts +4 -5
  220. package/test/pageInput.test.ts +83 -0
  221. package/test/tokenStorage.test.ts +17 -17
  222. package/dist/SchemaConverterError.d.ts +0 -108
  223. package/dist/SchemaConverterError.d.ts.map +0 -1
  224. package/dist/SchemaConverterError.js +0 -84
  225. package/dist/SchemaConverterError.js.map +0 -1
  226. package/dist/ast/BlockNode.d.ts +0 -468
  227. package/dist/ast/BlockNode.d.ts.map +0 -1
  228. package/dist/ast/BlockNode.js +0 -319
  229. package/dist/ast/BlockNode.js.map +0 -1
  230. package/dist/ast/Document.d.ts +0 -244
  231. package/dist/ast/Document.d.ts.map +0 -1
  232. package/dist/ast/Document.js +0 -69
  233. package/dist/ast/Document.js.map +0 -1
  234. package/dist/ast/InlineNode.d.ts +0 -477
  235. package/dist/ast/InlineNode.d.ts.map +0 -1
  236. package/dist/ast/InlineNode.js +0 -263
  237. package/dist/ast/InlineNode.js.map +0 -1
  238. package/dist/ast/MacroNode.d.ts +0 -267
  239. package/dist/ast/MacroNode.d.ts.map +0 -1
  240. package/dist/ast/MacroNode.js +0 -164
  241. package/dist/ast/MacroNode.js.map +0 -1
  242. package/dist/ast/index.d.ts +0 -10
  243. package/dist/ast/index.d.ts.map +0 -1
  244. package/dist/ast/index.js +0 -14
  245. package/dist/ast/index.js.map +0 -1
  246. package/dist/parsers/ConfluenceParser.d.ts +0 -26
  247. package/dist/parsers/ConfluenceParser.d.ts.map +0 -1
  248. package/dist/parsers/ConfluenceParser.js +0 -792
  249. package/dist/parsers/ConfluenceParser.js.map +0 -1
  250. package/dist/parsers/MarkdownParser.d.ts +0 -26
  251. package/dist/parsers/MarkdownParser.d.ts.map +0 -1
  252. package/dist/parsers/MarkdownParser.js +0 -873
  253. package/dist/parsers/MarkdownParser.js.map +0 -1
  254. package/dist/parsers/index.d.ts +0 -8
  255. package/dist/parsers/index.d.ts.map +0 -1
  256. package/dist/parsers/index.js +0 -8
  257. package/dist/parsers/index.js.map +0 -1
  258. package/dist/parsers/preprocessing/ConfluencePreprocessing.d.ts +0 -23
  259. package/dist/parsers/preprocessing/ConfluencePreprocessing.d.ts.map +0 -1
  260. package/dist/parsers/preprocessing/ConfluencePreprocessing.js +0 -323
  261. package/dist/parsers/preprocessing/ConfluencePreprocessing.js.map +0 -1
  262. package/dist/parsers/preprocessing/index.d.ts +0 -7
  263. package/dist/parsers/preprocessing/index.d.ts.map +0 -1
  264. package/dist/parsers/preprocessing/index.js +0 -7
  265. package/dist/parsers/preprocessing/index.js.map +0 -1
  266. package/dist/schemas/ConfluenceSchema.d.ts +0 -21
  267. package/dist/schemas/ConfluenceSchema.d.ts.map +0 -1
  268. package/dist/schemas/ConfluenceSchema.js +0 -38
  269. package/dist/schemas/ConfluenceSchema.js.map +0 -1
  270. package/dist/schemas/ConversionSchema.d.ts +0 -35
  271. package/dist/schemas/ConversionSchema.d.ts.map +0 -1
  272. package/dist/schemas/ConversionSchema.js +0 -208
  273. package/dist/schemas/ConversionSchema.js.map +0 -1
  274. package/dist/schemas/MarkdownSchema.d.ts +0 -21
  275. package/dist/schemas/MarkdownSchema.d.ts.map +0 -1
  276. package/dist/schemas/MarkdownSchema.js +0 -38
  277. package/dist/schemas/MarkdownSchema.js.map +0 -1
  278. package/dist/schemas/hast/HastFromHtml.d.ts +0 -27
  279. package/dist/schemas/hast/HastFromHtml.d.ts.map +0 -1
  280. package/dist/schemas/hast/HastFromHtml.js +0 -107
  281. package/dist/schemas/hast/HastFromHtml.js.map +0 -1
  282. package/dist/schemas/hast/HastSchema.d.ts +0 -195
  283. package/dist/schemas/hast/HastSchema.d.ts.map +0 -1
  284. package/dist/schemas/hast/HastSchema.js +0 -183
  285. package/dist/schemas/hast/HastSchema.js.map +0 -1
  286. package/dist/schemas/hast/index.d.ts +0 -9
  287. package/dist/schemas/hast/index.d.ts.map +0 -1
  288. package/dist/schemas/hast/index.js +0 -3
  289. package/dist/schemas/hast/index.js.map +0 -1
  290. package/dist/schemas/index.d.ts +0 -14
  291. package/dist/schemas/index.d.ts.map +0 -1
  292. package/dist/schemas/index.js +0 -16
  293. package/dist/schemas/index.js.map +0 -1
  294. package/dist/schemas/mdast/MdastFromMarkdown.d.ts +0 -30
  295. package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +0 -1
  296. package/dist/schemas/mdast/MdastFromMarkdown.js +0 -79
  297. package/dist/schemas/mdast/MdastFromMarkdown.js.map +0 -1
  298. package/dist/schemas/mdast/MdastSchema.d.ts +0 -385
  299. package/dist/schemas/mdast/MdastSchema.d.ts.map +0 -1
  300. package/dist/schemas/mdast/MdastSchema.js +0 -266
  301. package/dist/schemas/mdast/MdastSchema.js.map +0 -1
  302. package/dist/schemas/mdast/index.d.ts +0 -10
  303. package/dist/schemas/mdast/index.d.ts.map +0 -1
  304. package/dist/schemas/mdast/index.js +0 -4
  305. package/dist/schemas/mdast/index.js.map +0 -1
  306. package/dist/schemas/mdast/mdastToString.d.ts +0 -13
  307. package/dist/schemas/mdast/mdastToString.d.ts.map +0 -1
  308. package/dist/schemas/mdast/mdastToString.js +0 -85
  309. package/dist/schemas/mdast/mdastToString.js.map +0 -1
  310. package/dist/schemas/nodes/block/BlockSchema.d.ts +0 -43
  311. package/dist/schemas/nodes/block/BlockSchema.d.ts.map +0 -1
  312. package/dist/schemas/nodes/block/BlockSchema.js +0 -634
  313. package/dist/schemas/nodes/block/BlockSchema.js.map +0 -1
  314. package/dist/schemas/nodes/block/index.d.ts +0 -7
  315. package/dist/schemas/nodes/block/index.d.ts.map +0 -1
  316. package/dist/schemas/nodes/block/index.js +0 -7
  317. package/dist/schemas/nodes/block/index.js.map +0 -1
  318. package/dist/schemas/nodes/index.d.ts +0 -9
  319. package/dist/schemas/nodes/index.d.ts.map +0 -1
  320. package/dist/schemas/nodes/index.js +0 -12
  321. package/dist/schemas/nodes/index.js.map +0 -1
  322. package/dist/schemas/nodes/inline/InlineSchema.d.ts +0 -48
  323. package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +0 -1
  324. package/dist/schemas/nodes/inline/InlineSchema.js +0 -436
  325. package/dist/schemas/nodes/inline/InlineSchema.js.map +0 -1
  326. package/dist/schemas/nodes/inline/index.d.ts +0 -7
  327. package/dist/schemas/nodes/inline/index.d.ts.map +0 -1
  328. package/dist/schemas/nodes/inline/index.js +0 -7
  329. package/dist/schemas/nodes/inline/index.js.map +0 -1
  330. package/dist/schemas/nodes/macro/MacroSchema.d.ts +0 -27
  331. package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +0 -1
  332. package/dist/schemas/nodes/macro/MacroSchema.js +0 -162
  333. package/dist/schemas/nodes/macro/MacroSchema.js.map +0 -1
  334. package/dist/schemas/nodes/macro/index.d.ts +0 -7
  335. package/dist/schemas/nodes/macro/index.d.ts.map +0 -1
  336. package/dist/schemas/nodes/macro/index.js +0 -7
  337. package/dist/schemas/nodes/macro/index.js.map +0 -1
  338. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +0 -53
  339. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
  340. package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -349
  341. package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +0 -1
  342. package/dist/schemas/preprocessing/index.d.ts +0 -8
  343. package/dist/schemas/preprocessing/index.d.ts.map +0 -1
  344. package/dist/schemas/preprocessing/index.js +0 -2
  345. package/dist/schemas/preprocessing/index.js.map +0 -1
  346. package/dist/serializers/ConfluenceSerializer.d.ts +0 -30
  347. package/dist/serializers/ConfluenceSerializer.d.ts.map +0 -1
  348. package/dist/serializers/ConfluenceSerializer.js +0 -551
  349. package/dist/serializers/ConfluenceSerializer.js.map +0 -1
  350. package/dist/serializers/MarkdownSerializer.d.ts +0 -34
  351. package/dist/serializers/MarkdownSerializer.d.ts.map +0 -1
  352. package/dist/serializers/MarkdownSerializer.js +0 -355
  353. package/dist/serializers/MarkdownSerializer.js.map +0 -1
  354. package/dist/serializers/index.d.ts +0 -8
  355. package/dist/serializers/index.d.ts.map +0 -1
  356. package/dist/serializers/index.js +0 -8
  357. package/dist/serializers/index.js.map +0 -1
@@ -40,16 +40,14 @@ const transformers: Transformers = { md, json }
40
40
  *
41
41
  * @category Service
42
42
  */
43
- export class AtlaskitTransformers extends Context.Tag(
44
- "@knpkv/confluence-to-markdown/AtlaskitTransformers"
45
- )<
43
+ export class AtlaskitTransformers extends Context.Service<
46
44
  AtlaskitTransformers,
47
45
  {
48
46
  readonly use: <A>(
49
47
  fn: (t: Transformers) => A
50
48
  ) => Effect.Effect<A, AtlaskitTransformersError>
51
49
  }
52
- >() {}
50
+ >()("@knpkv/confluence-to-markdown/AtlaskitTransformers") {}
53
51
 
54
52
  /**
55
53
  * Live Layer providing the wrapped @atlaskit transformers. The transformer
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.refined<PageId>(
30
- (s): s is PageId => typeof s === "string" && s.length > 0,
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.String.pipe(
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.refined<SpaceKey>(
64
- (s): s is SpaceKey => typeof s === "string" && s.length > 0 && /^[A-Z0-9]+$/.test(s),
65
- (s) => Brand.error(`Invalid space key: "${s}" (must be uppercase alphanumeric)`)
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.nonEmptyString(),
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.refined<ContentHash>(
92
- (s): s is ContentHash => typeof s === "string" && /^[a-f0-9]{64}$/.test(s),
93
- (s) => Brand.error(`Invalid content hash: "${s}" (must be 64-char hex string)`)
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.pattern(/^[a-f0-9]{64}$/),
97
+ Schema.check(Schema.isPattern(/^[a-f0-9]{64}$/)),
103
98
  Schema.brand("ContentHash")
104
99
  )
@@ -11,12 +11,7 @@
11
11
  *
12
12
  * @module
13
13
  */
14
- import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem"
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
- NodeFileSystem.layer,
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.Tag("@knpkv/confluence-to-markdown/ConfluenceAuth")<
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 commandExecutor = yield* CommandExecutor.CommandExecutor
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 platform = process.platform
208
- let command: Command.Command
209
-
210
- if (platform === "darwin") {
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* Command.exitCode(command).pipe(
219
- Effect.provide(Layer.succeed(CommandExecutor.CommandExecutor, commandExecutor))
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.decodeUnknown(TokenResponseSchema)(body)
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.decodeUnknown(Schema.Array(AccessibleResourceSchema))(body)
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.decodeUnknown(UserInfoSchema)(body)
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.decodeUnknown(TokenResponseSchema)(body).pipe(
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("TimeoutException", () =>
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.catchAll((error) => Effect.log(`Warning: Failed to revoke token: ${error.message}`))
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 | CommandExecutor.CommandExecutor
572
+ HttpClient.HttpClient | ChildProcessSpawner.ChildProcessSpawner
581
573
  > = Layer.effect(ConfluenceAuth, make)
@@ -67,9 +67,7 @@ export interface UpdatePageRequest {
67
67
  *
68
68
  * @category Client
69
69
  */
70
- export class ConfluenceClient extends Context.Tag(
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 rateLimitSchedule = Schedule.exponential("1 second").pipe(
159
- Schedule.union(Schedule.spaced("30 seconds")),
160
- Schedule.whileInput<RateLimitError | ApiError>((error) => error._tag === "RateLimitError"),
161
- Schedule.intersect(Schedule.recurs(3))
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.Tag.Service<typeof ConfluenceClient>> =>
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, {
@@ -197,7 +201,7 @@ const make = (
197
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(rateLimitSchedule)
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(rateLimitSchedule)
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(rateLimitSchedule)
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(rateLimitSchedule)
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(rateLimitSchedule)
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(rateLimitSchedule)
291
+ Effect.retry(rateLimitRetry)
288
292
  )
289
293
 
290
294
  const getPageVersions = (
@@ -319,7 +323,7 @@ const make = (
319
323
  }
320
324
  })).pipe(
321
325
  Effect.mapError((e) => mapApiError(e, `/pages/${id}/versions`, id)),
322
- Effect.retry(rateLimitSchedule)
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(rateLimitSchedule)
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(rateLimitSchedule))
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: process.env.CONFLUENCE_API_KEY
445
+ * token: "<api-token>"
442
446
  * }
443
447
  * }))
444
448
  * )
@@ -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.Tag(
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.catchAll(() => Effect.succeed(false))
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.decodeUnknown(ConfluenceConfigFileSchema)(json).pipe(
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 { NodeFileSystem } from "@effect/platform-node"
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(NodeFileSystem.layer)
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 resolvedPath = configPath ?? path.join(process.cwd(), CONFIG_DIR, CONFIG_FILE_NAME)
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 configDir = pathService.join(process.cwd(), CONFIG_DIR)
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.decodeUnknown(ConfluenceConfigFileSchema)(config).pipe(
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.catchAll(() => Effect.succeed(false)))
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/GitService.ts CHANGED
@@ -3,17 +3,13 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import * as NodeCommandExecutor from "@effect/platform-node/NodeCommandExecutor"
7
- import * as NodeContext from "@effect/platform-node/NodeContext"
8
- import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem"
9
- import * as NodePath from "@effect/platform-node/NodePath"
10
- import * as CommandExecutor from "@effect/platform/CommandExecutor"
11
- import type * as PlatformError from "@effect/platform/Error"
12
- import * as FileSystem from "@effect/platform/FileSystem"
13
- import * as Path from "@effect/platform/Path"
14
6
  import * as Context from "effect/Context"
15
7
  import * as Effect from "effect/Effect"
8
+ import * as FileSystem from "effect/FileSystem"
16
9
  import * as Layer from "effect/Layer"
10
+ import * as Path from "effect/Path"
11
+ import type * as PlatformError from "effect/PlatformError"
12
+ import { ChildProcessSpawner } from "effect/unstable/process"
17
13
  import {
18
14
  GitError,
19
15
  GitMergeConflictError,
@@ -249,10 +245,10 @@ export interface GitServiceShape {
249
245
  *
250
246
  * @category Service
251
247
  */
252
- export class GitService extends Context.Tag("@knpkv/confluence-to-markdown/GitService")<
248
+ export class GitService extends Context.Service<
253
249
  GitService,
254
250
  GitServiceShape
255
- >() {}
251
+ >()("@knpkv/confluence-to-markdown/GitService") {}
256
252
 
257
253
  /**
258
254
  * Map PlatformError to GitError.
@@ -260,13 +256,15 @@ export class GitService extends Context.Tag("@knpkv/confluence-to-markdown/GitSe
260
256
  const mapFsError = (error: PlatformError.PlatformError): GitError =>
261
257
  new GitError({ command: "filesystem", message: error.message })
262
258
 
263
- // Dependencies layer for git operations (CommandExecutor + FileSystem + Path + NodeContext)
264
- // NodeCommandExecutor requires FileSystem, so use provideMerge to satisfy its dependencies
265
- const GitDepsLive = NodeCommandExecutor.layer.pipe(
266
- Layer.provideMerge(NodeFileSystem.layer),
267
- Layer.provideMerge(NodePath.layer),
268
- Layer.provideMerge(NodeContext.layer)
269
- )
259
+ const existsOrFalse = (
260
+ effect: Effect.Effect<boolean, PlatformError.PlatformError>
261
+ ): Effect.Effect<boolean> =>
262
+ effect.pipe(
263
+ Effect.catchIf(
264
+ (error): error is PlatformError.PlatformError => error._tag === "PlatformError",
265
+ () => Effect.succeed(false)
266
+ )
267
+ )
270
268
 
271
269
  /**
272
270
  * Copy a single file, creating parent directories as needed.
@@ -279,7 +277,7 @@ const copyFileFn = (
279
277
  ): Effect.Effect<void, GitError> =>
280
278
  Effect.gen(function*() {
281
279
  const destDir = pathService.dirname(dest)
282
- yield* fs.makeDirectory(destDir, { recursive: true }).pipe(Effect.catchAll(() => Effect.void))
280
+ yield* fs.makeDirectory(destDir, { recursive: true }).pipe(Effect.mapError(mapFsError))
283
281
  yield* fs.copyFile(source, dest).pipe(Effect.mapError(mapFsError))
284
282
  })
285
283
 
@@ -293,7 +291,7 @@ const copyDirectoryFn = (
293
291
  dest: string
294
292
  ): Effect.Effect<void, GitError> =>
295
293
  Effect.gen(function*() {
296
- yield* fs.makeDirectory(dest, { recursive: true }).pipe(Effect.catchAll(() => Effect.void))
294
+ yield* fs.makeDirectory(dest, { recursive: true }).pipe(Effect.mapError(mapFsError))
297
295
 
298
296
  const entries = yield* fs.readDirectory(source).pipe(Effect.mapError(mapFsError))
299
297
 
@@ -321,7 +319,7 @@ const copyMarkdownFilesFn = (
321
319
  dest: string
322
320
  ): Effect.Effect<void, GitError> =>
323
321
  Effect.gen(function*() {
324
- const exists = yield* fs.exists(source).pipe(Effect.catchAll(() => Effect.succeed(false)))
322
+ const exists = yield* existsOrFalse(fs.exists(source))
325
323
  if (!exists) {
326
324
  return
327
325
  }
@@ -349,7 +347,7 @@ const copyMarkdownFilesFn = (
349
347
 
350
348
  // Get paths helper - takes pathService as param
351
349
  const getPaths = (pathService: Path.Path) => {
352
- const cwd = process.cwd()
350
+ const cwd = pathService.resolve(".")
353
351
  const confluenceDir = pathService.join(cwd, ".confluence")
354
352
  const gitDir = pathService.join(confluenceDir, ".git")
355
353
  return { cwd, confluenceDir, gitDir, pathService }
@@ -358,7 +356,7 @@ const getPaths = (pathService: Path.Path) => {
358
356
  // Ensure initialized helper - takes fs and gitDir
359
357
  const ensureInitializedFn = (fs: FileSystem.FileSystem, gitDir: string) =>
360
358
  Effect.gen(function*() {
361
- const initialized = yield* fs.exists(gitDir).pipe(Effect.catchAll(() => Effect.succeed(false)))
359
+ const initialized = yield* existsOrFalse(fs.exists(gitDir))
362
360
  if (!initialized) {
363
361
  return yield* Effect.fail(new GitNotInitializedError())
364
362
  }
@@ -368,17 +366,18 @@ const ensureInitializedFn = (fs: FileSystem.FileSystem, gitDir: string) =>
368
366
  const make = Effect.gen(function*() {
369
367
  const fs = yield* FileSystem.FileSystem
370
368
  const pathService = yield* Path.Path
371
- const commandExecutor = yield* CommandExecutor.CommandExecutor
369
+ const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner
372
370
  const paths = getPaths(pathService)
373
371
  const { confluenceDir, cwd, gitDir } = paths
374
372
 
375
373
  // Create context with captured services for providing to returned Effects
376
- const depsContext: Context.Context<FileSystem.FileSystem | Path.Path | CommandExecutor.CommandExecutor> = Context
377
- .empty().pipe(
378
- Context.add(FileSystem.FileSystem, fs),
379
- Context.add(Path.Path, pathService),
380
- Context.add(CommandExecutor.CommandExecutor, commandExecutor)
381
- )
374
+ const depsContext: Context.Context<FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner> =
375
+ Context
376
+ .empty().pipe(
377
+ Context.add(FileSystem.FileSystem, fs),
378
+ Context.add(Path.Path, pathService),
379
+ Context.add(ChildProcessSpawner.ChildProcessSpawner, childProcessSpawner)
380
+ )
382
381
 
383
382
  // Helper to provide deps to an effect - uses any for R since we know depsContext covers all needs
384
383
  const provideDeps = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E> =>
@@ -396,11 +395,7 @@ const make = Effect.gen(function*() {
396
395
  )
397
396
  )
398
397
 
399
- const isInitialized = () =>
400
- Effect.succeed(fs).pipe(
401
- Effect.flatMap((f) => f.exists(gitDir)),
402
- Effect.catchAll(() => Effect.succeed(false))
403
- )
398
+ const isInitialized = () => existsOrFalse(fs.exists(gitDir))
404
399
 
405
400
  const init = () =>
406
401
  provideDeps(
@@ -410,12 +405,12 @@ const make = Effect.gen(function*() {
410
405
  Effect.catchTag("GitError", () => Effect.fail(new GitNotInstalledError({ message: "Git not found" })))
411
406
  )
412
407
 
413
- const exists = yield* fs.exists(confluenceDir).pipe(Effect.catchAll(() => Effect.succeed(false)))
408
+ const exists = yield* existsOrFalse(fs.exists(confluenceDir))
414
409
  if (!exists) {
415
410
  yield* fs.makeDirectory(confluenceDir, { recursive: true }).pipe(Effect.mapError(mapFsError))
416
411
  }
417
412
 
418
- const gitExists = yield* fs.exists(gitDir).pipe(Effect.catchAll(() => Effect.succeed(false)))
413
+ const gitExists = yield* existsOrFalse(fs.exists(gitDir))
419
414
  if (!gitExists) {
420
415
  yield* runGit(["init"], confluenceDir)
421
416
  // Configure local git user for commits (needed in CI environments)
@@ -583,7 +578,7 @@ const make = Effect.gen(function*() {
583
578
  const sourcePath = pathService.join(absoluteDocsPath, pattern)
584
579
  const destPath = pathService.join(confluenceDir, pattern)
585
580
 
586
- const exists = yield* fs.exists(sourcePath).pipe(Effect.catchAll(() => Effect.succeed(false)))
581
+ const exists = yield* existsOrFalse(fs.exists(sourcePath))
587
582
  if (exists) {
588
583
  const stat = yield* fs.stat(sourcePath).pipe(Effect.mapError(mapFsError))
589
584
  if (stat.type === "Directory") {
@@ -614,7 +609,7 @@ const make = Effect.gen(function*() {
614
609
  const sourcePath = pathService.join(confluenceDir, pattern)
615
610
  const destPath = pathService.join(absoluteDocsPath, pattern)
616
611
 
617
- const exists = yield* fs.exists(sourcePath).pipe(Effect.catchAll(() => Effect.succeed(false)))
612
+ const exists = yield* existsOrFalse(fs.exists(sourcePath))
618
613
  if (exists) {
619
614
  const stat = yield* fs.stat(sourcePath).pipe(Effect.mapError(mapFsError))
620
615
  if (stat.type === "Directory") {
@@ -842,18 +837,13 @@ const make = Effect.gen(function*() {
842
837
  })
843
838
  })
844
839
 
845
- // Layer with deps - requires FileSystem, Path, CommandExecutor
846
- const layerWithDeps: Layer.Layer<
847
- GitService,
848
- never,
849
- FileSystem.FileSystem | Path.Path | CommandExecutor.CommandExecutor
850
- > = Layer.effect(GitService, make)
851
-
852
840
  /**
853
- * Create GitService layer with all platform dependencies.
841
+ * Create GitService layer.
854
842
  *
855
843
  * @category Layers
856
844
  */
857
- export const layer = layerWithDeps.pipe(
858
- Layer.provide(GitDepsLive)
859
- )
845
+ export const layer: Layer.Layer<
846
+ GitService,
847
+ never,
848
+ FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner
849
+ > = Layer.effect(GitService, make)