@wonseok-han/confluence-sync 1.8.0 → 2.0.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 (518) hide show
  1. package/README.md +44 -410
  2. package/dist/cli/args.js +1 -1
  3. package/dist/cli/help.js +214 -115
  4. package/dist/cli/init.js +44 -5
  5. package/dist/cli/main.js +42 -11
  6. package/dist/cli/status.js +83 -0
  7. package/dist/confluence/client.js +121 -57
  8. package/dist/confluence/config.js +12 -8
  9. package/dist/confluence/env-file.js +23 -0
  10. package/dist/confluence/links.js +18 -0
  11. package/dist/conversion/asset-paths.js +5 -0
  12. package/dist/conversion/attachments.js +29 -7
  13. package/dist/conversion/convert.js +10 -22
  14. package/dist/conversion/footnotes.js +114 -11
  15. package/dist/conversion/markdown.js +26 -0
  16. package/dist/conversion/pdf-pages.js +10 -8
  17. package/dist/documents/anchors.js +9 -0
  18. package/dist/documents/callout-roundtrip.js +75 -0
  19. package/dist/documents/callouts.js +74 -0
  20. package/dist/documents/catalog.js +2 -2
  21. package/dist/documents/footnote-roundtrip.js +96 -0
  22. package/dist/documents/format.js +116 -0
  23. package/dist/documents/html-tables.js +30 -0
  24. package/dist/documents/html-to-markdown.js +47 -13
  25. package/dist/documents/markdown.js +46 -4
  26. package/dist/documents/obsidian.js +6 -3
  27. package/dist/documents/tables.js +89 -0
  28. package/dist/runtime/network.js +4 -0
  29. package/dist/shared/colors.js +2 -2
  30. package/dist/shared/progress.js +164 -0
  31. package/dist/shared/version.js +12 -0
  32. package/dist/site/assets/Monaco-LICENSE.txt +21 -0
  33. package/dist/site/assets/Monaco-ThirdPartyNotices.txt +448 -0
  34. package/dist/site/assets/PDFJS-LICENSE.txt +177 -0
  35. package/dist/site/assets/app.css +1 -0
  36. package/dist/site/assets/app.js +4 -0
  37. package/dist/site/assets/chunks/chunk-TEW74QPN.js +35 -0
  38. package/dist/site/assets/chunks/markdown-S6623E66.js +1 -0
  39. package/dist/site/assets/chunks/monaco-36ZGUH4Y.js +897 -0
  40. package/dist/site/assets/chunks/monaco-HFLEBJTI.css +1 -0
  41. package/dist/site/assets/chunks/pdf-DDN7TXTP.js +55 -0
  42. package/dist/site/assets/confluence-env-example.txt +32 -0
  43. package/dist/site/assets/editor.worker.js +1 -0
  44. package/dist/site/assets/favicon.svg +3 -0
  45. package/dist/site/assets/guide/01-account-settings.png +0 -0
  46. package/dist/site/assets/guide/02-atlassian-security.png +0 -0
  47. package/dist/site/assets/guide/03-api-tokens.png +0 -0
  48. package/dist/site/assets/guide/04-scope-api-token-step1.png +0 -0
  49. package/dist/site/assets/guide/05-scope-api-token-step2.png +0 -0
  50. package/dist/site/assets/guide/06-scope-api-token-step3.png +0 -0
  51. package/dist/site/assets/guide/07-scope-api-token-step4.png +0 -0
  52. package/dist/site/assets/guide/web/document-preview.png +0 -0
  53. package/dist/site/assets/guide/web/remote-diff.png +0 -0
  54. package/dist/site/assets/guide/web/sync-workspace.png +0 -0
  55. package/dist/site/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
  56. package/dist/site/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
  57. package/dist/site/assets/pdf/cmaps/78-H.bcmap +0 -0
  58. package/dist/site/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
  59. package/dist/site/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
  60. package/dist/site/assets/pdf/cmaps/78-V.bcmap +0 -0
  61. package/dist/site/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
  62. package/dist/site/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
  63. package/dist/site/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
  64. package/dist/site/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
  65. package/dist/site/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
  66. package/dist/site/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
  67. package/dist/site/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
  68. package/dist/site/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
  69. package/dist/site/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
  70. package/dist/site/assets/pdf/cmaps/Add-H.bcmap +0 -0
  71. package/dist/site/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
  72. package/dist/site/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
  73. package/dist/site/assets/pdf/cmaps/Add-V.bcmap +0 -0
  74. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
  75. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
  76. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
  77. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
  78. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
  79. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
  80. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
  81. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  82. package/dist/site/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
  83. package/dist/site/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
  84. package/dist/site/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
  85. package/dist/site/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
  86. package/dist/site/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
  87. package/dist/site/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
  88. package/dist/site/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  89. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
  90. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
  91. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
  92. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
  93. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
  94. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
  95. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
  96. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  97. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
  98. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
  99. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
  100. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  101. package/dist/site/assets/pdf/cmaps/B5-H.bcmap +0 -0
  102. package/dist/site/assets/pdf/cmaps/B5-V.bcmap +0 -0
  103. package/dist/site/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
  104. package/dist/site/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
  105. package/dist/site/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
  106. package/dist/site/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
  107. package/dist/site/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
  108. package/dist/site/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
  109. package/dist/site/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
  110. package/dist/site/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
  111. package/dist/site/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
  112. package/dist/site/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
  113. package/dist/site/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
  114. package/dist/site/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
  115. package/dist/site/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
  116. package/dist/site/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
  117. package/dist/site/assets/pdf/cmaps/EUC-H.bcmap +0 -0
  118. package/dist/site/assets/pdf/cmaps/EUC-V.bcmap +0 -0
  119. package/dist/site/assets/pdf/cmaps/Ext-H.bcmap +0 -0
  120. package/dist/site/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
  121. package/dist/site/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
  122. package/dist/site/assets/pdf/cmaps/Ext-V.bcmap +0 -0
  123. package/dist/site/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
  124. package/dist/site/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
  125. package/dist/site/assets/pdf/cmaps/GB-H.bcmap +4 -0
  126. package/dist/site/assets/pdf/cmaps/GB-V.bcmap +0 -0
  127. package/dist/site/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
  128. package/dist/site/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
  129. package/dist/site/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
  130. package/dist/site/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
  131. package/dist/site/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
  132. package/dist/site/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
  133. package/dist/site/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
  134. package/dist/site/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
  135. package/dist/site/assets/pdf/cmaps/GBT-H.bcmap +0 -0
  136. package/dist/site/assets/pdf/cmaps/GBT-V.bcmap +0 -0
  137. package/dist/site/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
  138. package/dist/site/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
  139. package/dist/site/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
  140. package/dist/site/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
  141. package/dist/site/assets/pdf/cmaps/H.bcmap +0 -0
  142. package/dist/site/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
  143. package/dist/site/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
  144. package/dist/site/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
  145. package/dist/site/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
  146. package/dist/site/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
  147. package/dist/site/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
  148. package/dist/site/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
  149. package/dist/site/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
  150. package/dist/site/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
  151. package/dist/site/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
  152. package/dist/site/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
  153. package/dist/site/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
  154. package/dist/site/assets/pdf/cmaps/Hankaku.bcmap +0 -0
  155. package/dist/site/assets/pdf/cmaps/Hiragana.bcmap +0 -0
  156. package/dist/site/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
  157. package/dist/site/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
  158. package/dist/site/assets/pdf/cmaps/KSC-H.bcmap +0 -0
  159. package/dist/site/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
  160. package/dist/site/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
  161. package/dist/site/assets/pdf/cmaps/KSC-V.bcmap +0 -0
  162. package/dist/site/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
  163. package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  164. package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  165. package/dist/site/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
  166. package/dist/site/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
  167. package/dist/site/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
  168. package/dist/site/assets/pdf/cmaps/Katakana.bcmap +0 -0
  169. package/dist/site/assets/pdf/cmaps/LICENSE +36 -0
  170. package/dist/site/assets/pdf/cmaps/NWP-H.bcmap +0 -0
  171. package/dist/site/assets/pdf/cmaps/NWP-V.bcmap +0 -0
  172. package/dist/site/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
  173. package/dist/site/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
  174. package/dist/site/assets/pdf/cmaps/Roman.bcmap +0 -0
  175. package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  176. package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  177. package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  178. package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  179. package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  180. package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  181. package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  182. package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  183. package/dist/site/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
  184. package/dist/site/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
  185. package/dist/site/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
  186. package/dist/site/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
  187. package/dist/site/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
  188. package/dist/site/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
  189. package/dist/site/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
  190. package/dist/site/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
  191. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  192. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  193. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  194. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  195. package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  196. package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  197. package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  198. package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  199. package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  200. package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  201. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  202. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  203. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  204. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  205. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  206. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  207. package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  208. package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  209. package/dist/site/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  210. package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  211. package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  212. package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  213. package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  214. package/dist/site/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
  215. package/dist/site/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
  216. package/dist/site/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
  217. package/dist/site/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
  218. package/dist/site/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
  219. package/dist/site/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
  220. package/dist/site/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
  221. package/dist/site/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
  222. package/dist/site/assets/pdf/cmaps/V.bcmap +0 -0
  223. package/dist/site/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
  224. package/dist/site/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
  225. package/dist/site/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
  226. package/dist/site/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
  227. package/dist/site/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  228. package/dist/site/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
  229. package/dist/site/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
  230. package/dist/site/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
  231. package/dist/site/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  232. package/dist/site/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
  233. package/dist/site/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
  234. package/dist/site/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
  235. package/dist/site/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
  236. package/dist/site/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
  237. package/dist/site/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  238. package/dist/site/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
  239. package/dist/site/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
  240. package/dist/site/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
  241. package/dist/site/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
  242. package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
  243. package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
  244. package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
  245. package/dist/site/assets/pdf/wasm/LICENSE_QCMS +21 -0
  246. package/dist/site/assets/pdf/wasm/jbig2.wasm +0 -0
  247. package/dist/site/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
  248. package/dist/site/assets/pdf/wasm/openjpeg.wasm +0 -0
  249. package/dist/site/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
  250. package/dist/site/assets/pdf/wasm/qcms_bg.wasm +0 -0
  251. package/dist/site/assets/pdf/wasm/quickjs-eval.js +16 -0
  252. package/dist/site/assets/pdf/wasm/quickjs-eval.wasm +0 -0
  253. package/dist/site/assets/pdf.worker.min.mjs +29 -0
  254. package/dist/site/assets/workspace.worker.js +409 -0
  255. package/dist/site/index.html +253 -0
  256. package/dist/sync/baseline.js +45 -0
  257. package/dist/sync/changes.js +51 -0
  258. package/dist/sync/diff.js +80 -0
  259. package/dist/sync/fetch.js +287 -0
  260. package/dist/sync/ignore.js +4 -4
  261. package/dist/sync/local-state.js +12 -0
  262. package/dist/sync/mapping.js +31 -8
  263. package/dist/sync/metadata.js +57 -0
  264. package/dist/sync/prepare.js +52 -0
  265. package/dist/sync/pull.js +618 -141
  266. package/dist/sync/push.js +260 -213
  267. package/dist/sync/reconcile.js +51 -0
  268. package/dist/sync/references.js +2 -2
  269. package/dist/sync/remap.js +17 -5
  270. package/dist/sync/render.js +3 -2
  271. package/dist/sync/restore.js +28 -0
  272. package/dist/sync/scope.js +47 -0
  273. package/dist/sync/staging.js +193 -0
  274. package/dist/sync/workspace.js +100 -0
  275. package/dist/web/assets/PDFJS-LICENSE.txt +177 -0
  276. package/dist/web/assets/app.css +1 -1
  277. package/dist/web/assets/app.js +3 -938
  278. package/dist/web/assets/chunks/chunk-TEW74QPN.js +35 -0
  279. package/dist/web/assets/chunks/markdown-S6623E66.js +1 -0
  280. package/dist/web/assets/chunks/monaco-36ZGUH4Y.js +897 -0
  281. package/dist/web/assets/chunks/monaco-HFLEBJTI.css +1 -0
  282. package/dist/web/assets/chunks/pdf-DDN7TXTP.js +55 -0
  283. package/dist/web/assets/confluence-env-example.txt +32 -0
  284. package/dist/web/assets/editor.worker.js +1 -30
  285. package/dist/web/assets/favicon.svg +3 -0
  286. package/dist/web/assets/guide/01-account-settings.png +0 -0
  287. package/dist/web/assets/guide/02-atlassian-security.png +0 -0
  288. package/dist/web/assets/guide/03-api-tokens.png +0 -0
  289. package/dist/web/assets/guide/04-scope-api-token-step1.png +0 -0
  290. package/dist/web/assets/guide/05-scope-api-token-step2.png +0 -0
  291. package/dist/web/assets/guide/06-scope-api-token-step3.png +0 -0
  292. package/dist/web/assets/guide/07-scope-api-token-step4.png +0 -0
  293. package/dist/web/assets/guide/web/document-preview.png +0 -0
  294. package/dist/web/assets/guide/web/remote-diff.png +0 -0
  295. package/dist/web/assets/guide/web/sync-workspace.png +0 -0
  296. package/dist/web/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
  297. package/dist/web/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
  298. package/dist/web/assets/pdf/cmaps/78-H.bcmap +0 -0
  299. package/dist/web/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
  300. package/dist/web/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
  301. package/dist/web/assets/pdf/cmaps/78-V.bcmap +0 -0
  302. package/dist/web/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
  303. package/dist/web/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
  304. package/dist/web/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
  305. package/dist/web/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
  306. package/dist/web/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
  307. package/dist/web/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
  308. package/dist/web/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
  309. package/dist/web/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
  310. package/dist/web/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
  311. package/dist/web/assets/pdf/cmaps/Add-H.bcmap +0 -0
  312. package/dist/web/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
  313. package/dist/web/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
  314. package/dist/web/assets/pdf/cmaps/Add-V.bcmap +0 -0
  315. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
  316. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
  317. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
  318. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
  319. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
  320. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
  321. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
  322. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  323. package/dist/web/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
  324. package/dist/web/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
  325. package/dist/web/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
  326. package/dist/web/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
  327. package/dist/web/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
  328. package/dist/web/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
  329. package/dist/web/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  330. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
  331. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
  332. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
  333. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
  334. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
  335. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
  336. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
  337. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  338. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
  339. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
  340. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
  341. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  342. package/dist/web/assets/pdf/cmaps/B5-H.bcmap +0 -0
  343. package/dist/web/assets/pdf/cmaps/B5-V.bcmap +0 -0
  344. package/dist/web/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
  345. package/dist/web/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
  346. package/dist/web/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
  347. package/dist/web/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
  348. package/dist/web/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
  349. package/dist/web/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
  350. package/dist/web/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
  351. package/dist/web/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
  352. package/dist/web/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
  353. package/dist/web/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
  354. package/dist/web/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
  355. package/dist/web/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
  356. package/dist/web/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
  357. package/dist/web/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
  358. package/dist/web/assets/pdf/cmaps/EUC-H.bcmap +0 -0
  359. package/dist/web/assets/pdf/cmaps/EUC-V.bcmap +0 -0
  360. package/dist/web/assets/pdf/cmaps/Ext-H.bcmap +0 -0
  361. package/dist/web/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
  362. package/dist/web/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
  363. package/dist/web/assets/pdf/cmaps/Ext-V.bcmap +0 -0
  364. package/dist/web/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
  365. package/dist/web/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
  366. package/dist/web/assets/pdf/cmaps/GB-H.bcmap +4 -0
  367. package/dist/web/assets/pdf/cmaps/GB-V.bcmap +0 -0
  368. package/dist/web/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
  369. package/dist/web/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
  370. package/dist/web/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
  371. package/dist/web/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
  372. package/dist/web/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
  373. package/dist/web/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
  374. package/dist/web/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
  375. package/dist/web/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
  376. package/dist/web/assets/pdf/cmaps/GBT-H.bcmap +0 -0
  377. package/dist/web/assets/pdf/cmaps/GBT-V.bcmap +0 -0
  378. package/dist/web/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
  379. package/dist/web/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
  380. package/dist/web/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
  381. package/dist/web/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
  382. package/dist/web/assets/pdf/cmaps/H.bcmap +0 -0
  383. package/dist/web/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
  384. package/dist/web/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
  385. package/dist/web/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
  386. package/dist/web/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
  387. package/dist/web/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
  388. package/dist/web/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
  389. package/dist/web/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
  390. package/dist/web/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
  391. package/dist/web/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
  392. package/dist/web/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
  393. package/dist/web/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
  394. package/dist/web/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
  395. package/dist/web/assets/pdf/cmaps/Hankaku.bcmap +0 -0
  396. package/dist/web/assets/pdf/cmaps/Hiragana.bcmap +0 -0
  397. package/dist/web/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
  398. package/dist/web/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
  399. package/dist/web/assets/pdf/cmaps/KSC-H.bcmap +0 -0
  400. package/dist/web/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
  401. package/dist/web/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
  402. package/dist/web/assets/pdf/cmaps/KSC-V.bcmap +0 -0
  403. package/dist/web/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
  404. package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  405. package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  406. package/dist/web/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
  407. package/dist/web/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
  408. package/dist/web/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
  409. package/dist/web/assets/pdf/cmaps/Katakana.bcmap +0 -0
  410. package/dist/web/assets/pdf/cmaps/LICENSE +36 -0
  411. package/dist/web/assets/pdf/cmaps/NWP-H.bcmap +0 -0
  412. package/dist/web/assets/pdf/cmaps/NWP-V.bcmap +0 -0
  413. package/dist/web/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
  414. package/dist/web/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
  415. package/dist/web/assets/pdf/cmaps/Roman.bcmap +0 -0
  416. package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  417. package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  418. package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  419. package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  420. package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  421. package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  422. package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  423. package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  424. package/dist/web/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
  425. package/dist/web/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
  426. package/dist/web/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
  427. package/dist/web/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
  428. package/dist/web/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
  429. package/dist/web/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
  430. package/dist/web/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
  431. package/dist/web/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
  432. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  433. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  434. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  435. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  436. package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  437. package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  438. package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  439. package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  440. package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  441. package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  442. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  443. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  444. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  445. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  446. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  447. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  448. package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  449. package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  450. package/dist/web/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  451. package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  452. package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  453. package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  454. package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  455. package/dist/web/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
  456. package/dist/web/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
  457. package/dist/web/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
  458. package/dist/web/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
  459. package/dist/web/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
  460. package/dist/web/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
  461. package/dist/web/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
  462. package/dist/web/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
  463. package/dist/web/assets/pdf/cmaps/V.bcmap +0 -0
  464. package/dist/web/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
  465. package/dist/web/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
  466. package/dist/web/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
  467. package/dist/web/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
  468. package/dist/web/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  469. package/dist/web/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
  470. package/dist/web/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
  471. package/dist/web/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
  472. package/dist/web/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  473. package/dist/web/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
  474. package/dist/web/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
  475. package/dist/web/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
  476. package/dist/web/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
  477. package/dist/web/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
  478. package/dist/web/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  479. package/dist/web/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
  480. package/dist/web/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
  481. package/dist/web/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
  482. package/dist/web/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
  483. package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
  484. package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
  485. package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
  486. package/dist/web/assets/pdf/wasm/LICENSE_QCMS +21 -0
  487. package/dist/web/assets/pdf/wasm/jbig2.wasm +0 -0
  488. package/dist/web/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
  489. package/dist/web/assets/pdf/wasm/openjpeg.wasm +0 -0
  490. package/dist/web/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
  491. package/dist/web/assets/pdf/wasm/qcms_bg.wasm +0 -0
  492. package/dist/web/assets/pdf/wasm/quickjs-eval.js +16 -0
  493. package/dist/web/assets/pdf/wasm/quickjs-eval.wasm +0 -0
  494. package/dist/web/assets/pdf.worker.min.mjs +29 -0
  495. package/dist/web/assets/workspace.worker.js +409 -0
  496. package/dist/web/document-source.js +14 -0
  497. package/dist/web/hosted-files.js +189 -0
  498. package/dist/web/hosted.js +316 -0
  499. package/dist/web/node-runner.js +26 -0
  500. package/dist/web/preview.js +74 -0
  501. package/dist/web/server.js +85 -240
  502. package/dist/web/sync.js +364 -70
  503. package/dist/web/table-editor-script.js +99 -0
  504. package/dist/web/table-format.js +224 -0
  505. package/dist/web/views/help.js +15 -10
  506. package/dist/web/views/sync-panel.js +90 -19
  507. package/dist/web/views/token-guide.js +27 -0
  508. package/dist/web/views/usage-guide.js +12 -0
  509. package/dist/web/views/workspace.js +85 -15
  510. package/dist/web/workspace-api.js +371 -0
  511. package/docs/user/CLI.md +366 -0
  512. package/docs/user/CONFIGURATION.md +125 -0
  513. package/docs/user/OBSIDIAN.md +117 -0
  514. package/docs/user/WEB.md +90 -0
  515. package/docs/user/images/web/document-preview.png +0 -0
  516. package/docs/user/images/web/remote-diff.png +0 -0
  517. package/docs/user/images/web/sync-workspace.png +0 -0
  518. package/package.json +23 -6
package/dist/web/sync.js CHANGED
@@ -1,66 +1,95 @@
1
+ import { validateRestorePaths } from '../sync/pull.js';
2
+ import { observeChanges } from '../sync/changes.js';
3
+ import { documentDiff } from '../sync/diff.js';
4
+ import { inspectStaging, changeStaging, stagedPaths, loadIndex } from '../sync/staging.js';
5
+ import { connectionKeys, importConnection, mergeConnection } from '../confluence/env-file.js';
6
+ import { loadWorkspace, inScope, inNestedWorkspace, requireScope } from '../sync/workspace.js';
7
+ import { mappingPath as defaultMappingPath, METADATA_DIR } from '../sync/metadata.js';
8
+ import { connectWorkspace } from '../sync/scope.js';
1
9
  import { referenceRoots } from '../sync/references.js';
2
10
  /** Web adapter for the existing push CLI. Only preview and incremental push are exposed. */
3
- import { spawn } from 'node:child_process';
11
+ import { runSyncCLI } from './node-runner.js';
12
+ export { runSyncCLI };
13
+ import { createReadStream } from 'node:fs';
4
14
  import { createHash, randomUUID } from 'node:crypto';
5
- import { readFile, readdir, realpath, stat, lstat } from 'node:fs/promises';
15
+ import { readFile, readdir, realpath, stat, lstat, writeFile, rename, unlink } from 'node:fs/promises';
6
16
  import { dirname, join, relative, resolve } from 'node:path';
7
- import { fileURLToPath } from 'node:url';
8
17
  import { parse } from 'dotenv';
9
18
  import { within } from './output.js';
10
- import { collectMarkdown, resolveSelection } from '../documents/catalog.js';
19
+ import { collectMarkdown } from '../documents/catalog.js';
11
20
  import { buildIgnorer } from '../sync/ignore.js';
12
- const keys = ['CONFLUENCE_BASE_URL', 'CONFLUENCE_EMAIL', 'CONFLUENCE_API_TOKEN', 'CONFLUENCE_SPACE_KEY', 'CONFLUENCE_PARENT_ID', 'CONFLUENCE_PARENT_PAGE_ID'];
13
- async function settings(base, envFile) {
14
- let source = envFile ? resolve(envFile) : join(base, '.env');
15
- let values;
21
+ const keys = connectionKeys;
22
+ function receiveFormat(input) {
23
+ const format = input?.format;
24
+ if (format !== undefined && format !== 'markdown' && format !== 'obsidian')
25
+ throw new Error('내부 링크 형식을 확인하세요. Markdown 또는 Obsidian을 선택하세요.');
26
+ return format ?? 'markdown';
27
+ }
28
+ async function settings(base, envId, imports) {
29
+ if (envId) {
30
+ const imported = imports.get(envId);
31
+ if (!imported)
32
+ throw new Error('가져온 .env 설정이 만료되었습니다. 파일을 다시 가져오세요.');
33
+ return { env: imported.env, source: imported.source };
34
+ }
35
+ const source = join(base, '.env');
36
+ let values = {};
16
37
  try {
17
- source = await realpath(source);
18
38
  values = parse(await readFile(source));
19
39
  }
20
40
  catch (error) {
21
- if (envFile || error.code !== 'ENOENT')
22
- throw new Error('.env 파일을 읽을 수 없습니다. 경로와 권한을 확인해 주세요.');
23
- source = '웹 서버 실행 환경 (.env / 환경변수)';
24
- values = process.env;
41
+ if (error.code !== 'ENOENT')
42
+ throw new Error('기준 폴더의 .env 파일을 읽을 수 없습니다.');
25
43
  }
26
44
  const env = {};
27
45
  for (const key of keys)
28
46
  env[key] = values[key]?.trim() ?? '';
29
- env.CONFLUENCE_PARENT_ID ||= env.CONFLUENCE_PARENT_PAGE_ID;
30
47
  return { env, source };
31
48
  }
32
- function publicConfig(env, source) {
49
+ function publicConfig(env, source, workspace) {
33
50
  return { source, baseUrl: env.CONFLUENCE_BASE_URL, email: env.CONFLUENCE_EMAIL,
34
- spaceKey: env.CONFLUENCE_SPACE_KEY, parentId: env.CONFLUENCE_PARENT_ID,
35
- hasToken: !!env.CONFLUENCE_API_TOKEN,
51
+ spaceKey: env.CONFLUENCE_SPACE_KEY, connected: workspace?.version === 2 && !!workspace.remoteRoot && workspace.connection?.baseUrl.replace(/\/$/, '') === env.CONFLUENCE_BASE_URL?.replace(/\/$/, '') && workspace.connection?.spaceKey === env.CONFLUENCE_SPACE_KEY,
52
+ rootPath: workspace?.remoteRoot?.path ?? null, hasToken: !!env.CONFLUENCE_API_TOKEN,
36
53
  missing: keys.slice(0, 4).filter(key => !env[key]) };
37
54
  }
38
55
  // The preview is invalidated if documents, attachments, mapping, ignore rules or credentials change.
39
- async function fingerprint(base, env) {
56
+ async function fingerprint(base, env, skipIndex = false) {
40
57
  const hash = createHash('sha256').update(JSON.stringify(env));
41
58
  const walk = async (dir) => {
42
59
  const entries = (await readdir(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
43
60
  for (const entry of entries) {
44
- if (entry.name === 'node_modules' || (entry.name.startsWith('.') && !['.confluence-sync.json', '.confluence-syncignore'].includes(entry.name)))
61
+ if (entry.name === 'node_modules' || (entry.name.startsWith('.') && ![METADATA_DIR, '.confluence-sync.json', '.confluence-syncignore', '.confluence-workspace.json'].includes(entry.name)))
45
62
  continue;
46
63
  const path = join(dir, entry.name);
64
+ if (relative(base, path).split('\\').join('/') === `${METADATA_DIR}/remote.json` || skipIndex && relative(base, path).split('\\').join('/') === `${METADATA_DIR}/index.json`)
65
+ continue;
47
66
  if (entry.isDirectory())
48
67
  await walk(path);
49
68
  else if (entry.isFile()) {
50
- const info = await stat(path);
51
- hash.update(JSON.stringify([relative(base, path), info.size, info.mtimeMs, info.ctimeMs]));
52
- if (/\.md$/i.test(path) || entry.name.startsWith('.'))
53
- hash.update(await readFile(path));
69
+ if (skipIndex) {
70
+ // Background local scans keep the lightweight metadata shortcut.
71
+ const info = await stat(path);
72
+ hash.update(JSON.stringify([relative(base, path), info.size, info.mtimeMs, info.ctimeMs]));
73
+ if (/\.md$/i.test(path) || entry.name.startsWith('.') || relative(base, path).split(/[\\/]/).includes(METADATA_DIR))
74
+ hash.update(await readFile(path));
75
+ }
76
+ else {
77
+ // Approval follows bytes, not OneDrive hydration/timestamp changes.
78
+ const content = createHash('sha256');
79
+ for await (const chunk of createReadStream(path))
80
+ content.update(chunk);
81
+ hash.update(JSON.stringify([relative(base, path), content.digest('hex')]));
82
+ }
54
83
  }
55
84
  }
56
85
  };
57
86
  await walk(base);
58
87
  return hash.digest('hex');
59
88
  }
60
- async function prepare(input) {
89
+ async function prepare(input, imports) {
61
90
  const body = input;
62
91
  if (!body || typeof body.base !== 'string' || typeof body.target !== 'string'
63
- || typeof body.envFile !== 'string' || typeof body.verify !== 'boolean')
92
+ || typeof body.envId !== 'string' || typeof body.verify !== 'boolean')
64
93
  throw new Error('동기화 옵션을 확인해 주세요.');
65
94
  const base = await realpath(resolve(body.base));
66
95
  if (dirname(base) === base || !(await stat(base)).isDirectory())
@@ -71,13 +100,17 @@ async function prepare(input) {
71
100
  const target = body.target ? await realpath(resolve(body.target)) : base;
72
101
  if (!within(base, target))
73
102
  throw new Error('동기화 대상은 기준 폴더 안에 있어야 합니다.');
103
+ if (target !== base)
104
+ throw new Error('웹 Push는 기준 폴더 전체를 대상으로 합니다. 개별 파일은 csync push <파일>을 사용하세요.');
74
105
  const ignorer = buildIgnorer(base, []);
75
106
  const docs = collectMarkdown(base).map(path => relative(base, path).split('\\').join('/')).filter(path => !ignorer.ignores(path));
76
- const picked = target === base ? docs : resolveSelection(docs, [target], base);
107
+ const workspace = loadWorkspace(base);
108
+ requireScope(workspace);
109
+ const picked = docs.filter(rel => inScope(rel, workspace) && !inNestedWorkspace(base, rel));
77
110
  if (!picked.length)
78
- throw new Error('동기화할 Markdown 문서가 없습니다. 선택 범위와 .confluence-syncignore를 확인해 주세요.');
111
+ throw new Error('동기화할 Markdown 문서가 없습니다. 선택 범위와 .csync/ignore(또는 기존 제외 파일)를 확인해 주세요.');
79
112
  // A damaged mapping must not silently turn a whole document set into new pages.
80
- const mappingPath = join(base, '.confluence-sync.json');
113
+ const mappingPath = defaultMappingPath(base);
81
114
  try {
82
115
  if (!(await lstat(mappingPath)).isFile())
83
116
  throw new Error('invalid mapping');
@@ -88,10 +121,11 @@ async function prepare(input) {
88
121
  }
89
122
  catch (error) {
90
123
  if (error.code !== 'ENOENT')
91
- throw new Error('.confluence-sync.json 매핑 파일이 올바르지 않습니다. 기존 매핑을 확인해 주세요.');
124
+ throw new Error('페이지 매핑 파일이 올바르지 않습니다. .csync/mapping.json 또는 기존 매핑을 확인해 주세요.');
92
125
  }
93
- const { env, source } = await settings(base, body.envFile);
94
- const selection = { base, target: target === base ? '' : target, envFile: body.envFile, verify: body.verify, referenceRoots: refs };
126
+ stagedPaths(base);
127
+ const { env, source } = await settings(base, body.envId, imports);
128
+ const selection = { base, target: target === base ? '' : target, envId: body.envId, verify: body.verify, referenceRoots: refs };
95
129
  const snapshots = await Promise.all([base, ...refs].map(async (root) => {
96
130
  const config = await readFile(join(root, '.env'), 'utf8').catch(error => {
97
131
  if (error.code === 'ENOENT')
@@ -100,50 +134,51 @@ async function prepare(input) {
100
134
  });
101
135
  return [root, await fingerprint(root, env), createHash('sha256').update(config).digest('hex')];
102
136
  }));
103
- return { selection, env, config: publicConfig(env, source), fingerprint: JSON.stringify(snapshots) };
137
+ return { selection, env, config: publicConfig(env, source, workspace), fingerprint: JSON.stringify(snapshots) };
104
138
  }
105
- export const runSyncCLI = (args, settings, log) => new Promise((resolveJob, reject) => {
106
- const source = import.meta.url.endsWith('.ts');
107
- const worker = fileURLToPath(new URL(source ? '../sync.ts' : '../sync.js', import.meta.url));
108
- const child = spawn(process.execPath, [...(source ? process.execArgv : []), worker, ...args], {
109
- env: { ...process.env, ...settings, NO_COLOR: '1' }, stdio: ['ignore', 'pipe', 'pipe'],
110
- });
111
- // Emit complete lines so secret masking cannot be bypassed by split stream chunks.
112
- for (const stream of [child.stdout, child.stderr]) {
113
- let pending = '';
114
- stream.setEncoding('utf8');
115
- stream.on('data', (chunk) => {
116
- pending += chunk;
117
- const end = pending.lastIndexOf('\n');
118
- if (end >= 0) {
119
- log(pending.slice(0, end + 1));
120
- pending = pending.slice(end + 1);
121
- }
122
- });
123
- stream.on('end', () => { if (pending)
124
- log(pending); });
125
- }
126
- child.once('error', reject);
127
- child.once('close', code => resolveJob(code ?? 1));
128
- });
129
- export function createWebSync(runner = runSyncCLI) {
139
+ export function createWebSync(runner = runSyncCLI, initialImports = []) {
140
+ const imports = new Map(initialImports);
130
141
  let job = null;
131
142
  let plan = null;
132
143
  let locked = false;
144
+ let restorePlan = null;
145
+ let stagingCache;
146
+ const connectionSettings = async (input) => {
147
+ const body = input;
148
+ if (!body || typeof body.base !== 'string' || typeof body.envId !== 'string')
149
+ throw new Error('설정 경로를 확인하세요.');
150
+ const base = await realpath(resolve(body.base));
151
+ if (!(await stat(base)).isDirectory() || dirname(base) === base)
152
+ throw new Error('로컬 기준 폴더를 선택하세요.');
153
+ const { env } = await settings(base, body.envId, imports);
154
+ const config = { baseUrl: env.CONFLUENCE_BASE_URL, email: env.CONFLUENCE_EMAIL, token: env.CONFLUENCE_API_TOKEN, spaceKey: env.CONFLUENCE_SPACE_KEY };
155
+ return { base, config, body };
156
+ };
133
157
  const running = () => locked || job?.state === 'running';
134
158
  const launch = (kind, prepared) => {
135
159
  const current = { id: randomUUID(), kind, state: 'running', log: '', selection: prepared.selection, config: prepared.config, planId: null, startedAt: new Date().toISOString() };
136
160
  job = current;
137
161
  plan = null;
138
162
  const { base, target, verify } = prepared.selection;
139
- const args = ['--base', base];
140
- for (const root of prepared.selection.referenceRoots)
163
+ const args = [kind === 'pull' ? 'pull' : kind === 'fetch' ? 'fetch' : kind === 'restore' ? 'restore' : 'push', '--base', base];
164
+ for (const root of kind === 'pull' || kind === 'fetch' || kind === 'restore' ? [] : prepared.selection.referenceRoots)
141
165
  args.push('--reference-root', root);
142
- if (target)
166
+ if (target && kind !== 'pull')
143
167
  args.push(target);
144
168
  if (kind === 'preview')
145
169
  args.push('--dry-run');
146
- else if (verify)
170
+ if (kind === 'restore') {
171
+ args.push(...prepared.selection.restorePaths);
172
+ if (prepared.selection.restoreOverwrite)
173
+ args.push('--overwrite');
174
+ }
175
+ if (['pull', 'restore'].includes(kind) && prepared.selection.format === 'obsidian')
176
+ args.push('--obsidian');
177
+ if (kind === 'pull' && prepared.selection.full)
178
+ args.push('--full');
179
+ if (kind === 'pull' && prepared.selection.remoteOnly)
180
+ args.push('--remote-only');
181
+ if (verify && kind !== 'pull')
147
182
  args.push('--verify');
148
183
  let reportedFailure = false;
149
184
  const secrets = [prepared.env.CONFLUENCE_API_TOKEN, Buffer.from(`${prepared.env.CONFLUENCE_EMAIL}:${prepared.env.CONFLUENCE_API_TOKEN}`).toString('base64')].filter(Boolean);
@@ -161,12 +196,30 @@ export function createWebSync(runner = runSyncCLI) {
161
196
  if (!succeeded)
162
197
  log('\n일부 작업이 실패했을 수 있습니다. 위 내역을 확인하고 다시 미리보기해 주세요.\n');
163
198
  if (kind === 'preview' && succeeded) {
164
- const updated = await prepare(prepared.selection);
199
+ const updated = await prepare(prepared.selection, imports);
165
200
  if (updated.fingerprint !== prepared.fingerprint)
166
201
  throw new Error('미리보기 중 문서나 설정이 바뀌었습니다. 다시 미리보기해 주세요.');
167
202
  plan = { id: randomUUID(), prepared };
168
203
  current.planId = plan.id;
169
204
  }
205
+ if (succeeded && ['push', 'pull'].includes(kind)) {
206
+ current.phase = 'fetch';
207
+ log('\n[자동 Fetch] 최신 원격 상태를 다시 확인합니다.\n');
208
+ reportedFailure = false;
209
+ try {
210
+ const refreshCode = await runner(['fetch', '--base', base, '--refresh'], prepared.env, log);
211
+ if (refreshCode !== 0 || reportedFailure)
212
+ throw new Error('후속 Fetch가 완료되지 않았습니다.');
213
+ }
214
+ catch (error) {
215
+ current.refreshFailed = true;
216
+ log(`[후속 Fetch 실패] ${error instanceof Error ? error.message : String(error)} 이미 완료된 ${kind === 'push' ? '업로드' : '가져오기'}는 유지됩니다. Fetch를 다시 실행하세요.\n`);
217
+ }
218
+ finally {
219
+ delete current.phase;
220
+ }
221
+ }
222
+ current.warningCount = Number(current.log.match(/(?:^|\n)\[경고 요약\] 원격 첨부 (\d+)개/)?.[1] ?? 0);
170
223
  current.state = succeeded ? 'succeeded' : 'failed';
171
224
  }
172
225
  catch (error) {
@@ -180,20 +233,261 @@ export function createWebSync(runner = runSyncCLI) {
180
233
  return current;
181
234
  };
182
235
  return {
236
+ connectionImports: () => [...imports],
183
237
  running,
238
+ diff: async (input) => {
239
+ if (running())
240
+ throw new Error('다른 작업이 진행 중입니다.');
241
+ locked = true;
242
+ try {
243
+ const { base, config } = await connectionSettings(input);
244
+ const body = input;
245
+ if (typeof body.path !== 'string' || body.remote !== undefined && typeof body.remote !== 'boolean')
246
+ throw new Error('비교할 문서를 선택하세요.');
247
+ return await documentDiff(base, body.path, { remote: body.remote, env: config });
248
+ }
249
+ finally {
250
+ locked = false;
251
+ }
252
+ },
253
+ staging: async (input) => {
254
+ if (running())
255
+ throw new Error('다른 작업이 진행 중입니다.');
256
+ locked = true;
257
+ try {
258
+ const { base, config } = await connectionSettings(input);
259
+ const body = input;
260
+ if (body.remoteOnly !== undefined && typeof body.remoteOnly !== 'boolean')
261
+ throw new Error('원격 목록 조회 옵션을 확인하세요.');
262
+ if (body.remoteOnly) {
263
+ if (body.action !== undefined)
264
+ throw new Error('원격 목록 조회에서는 업로드 선택을 변경할 수 없습니다.');
265
+ const view = observeChanges(base, [], config);
266
+ const rows = view.rows.filter(row => row.remoteState && row.remoteState !== 'unchanged').map(row => ({ ...row, localUnverified: !(row.remoteState === 'new' && row.status === 'unavailable') }));
267
+ return { ...view, rows, revision: JSON.stringify([view.remoteCheckedAt, rows]) };
268
+ }
269
+ if (body.referenceRoots !== undefined && (!Array.isArray(body.referenceRoots) || body.referenceRoots.some(p => typeof p !== 'string')))
270
+ throw new Error('참조 폴더를 확인하세요.');
271
+ const options = { referenceRoots: body.referenceRoots ?? [], baseUrl: config.baseUrl };
272
+ const cacheKey = JSON.stringify([base, options, loadWorkspace(base)]);
273
+ const revision = async () => JSON.stringify(await Promise.all([base, ...referenceRoots(base, options.referenceRoots)].map(root => fingerprint(root, { connection: JSON.stringify(config) }, true))));
274
+ let currentRevision = await revision();
275
+ let rows;
276
+ const cacheMatched = stagingCache?.key === cacheKey && stagingCache.revision === currentRevision;
277
+ if (body.action !== undefined) {
278
+ if (!['add', 'remove'].includes(String(body.action)) || !Array.isArray(body.paths) || body.paths.some(p => typeof p !== 'string'))
279
+ throw new Error('문서 선택을 확인하세요.');
280
+ plan = null;
281
+ const touched = await changeStaging(base, body.paths, body.action, options);
282
+ const prior = stagingCache?.key === cacheKey ? stagingCache.rows : [];
283
+ const merged = new Map(prior.map(row => [row.path, row]));
284
+ if (body.action === 'add')
285
+ for (const row of touched)
286
+ merged.set(row.path, { ...row, pageId: row.pageId, staged: true, stale: false });
287
+ const entries = loadIndex(base).entries;
288
+ rows = [...merged.values()].map(row => ({ ...row, staged: !!entries[row.path], stale: !!entries[row.path] && (!!row.unmapped || JSON.stringify(entries[row.path]) !== JSON.stringify(row.entry)) }));
289
+ if (!cacheMatched)
290
+ currentRevision = '';
291
+ }
292
+ else
293
+ rows = stagingCache?.key === cacheKey && stagingCache.revision === currentRevision ? stagingCache.rows : await inspectStaging(base, options);
294
+ const activeEntries = loadIndex(base).entries;
295
+ rows = rows.map(row => ({ ...row, staged: !!activeEntries[row.path], stale: !!activeEntries[row.path] && (!!row.unmapped || JSON.stringify(activeEntries[row.path]) !== JSON.stringify(row.entry)) }));
296
+ for (const [path, entry] of Object.entries(activeEntries))
297
+ if (!rows.some(row => row.path === path))
298
+ rows.push({ path, status: 'unavailable', staged: true, stale: true, entry });
299
+ stagingCache = { key: cacheKey, rows, revision: currentRevision };
300
+ const view = observeChanges(base, rows, config);
301
+ return { ...view, revision: JSON.stringify([currentRevision, activeEntries, view.remoteCheckedAt, view.rows]) };
302
+ }
303
+ finally {
304
+ locked = false;
305
+ }
306
+ },
307
+ importEnv: async (input) => {
308
+ if (running())
309
+ throw new Error('다른 Confluence 작업이 진행 중입니다.');
310
+ const body = input;
311
+ if (!body || typeof body.base !== 'string' || typeof body.text !== 'string' || typeof body.name !== 'string' || body.name.length > 255)
312
+ throw new Error('.env 파일을 선택해 주세요.');
313
+ const base = await realpath(resolve(body.base));
314
+ if (!(await stat(base)).isDirectory() || dirname(base) === base)
315
+ throw new Error('로컬 기준 폴더를 선택하세요.');
316
+ const imported = { ...importConnection(body.text), source: `가져온 파일 · ${body.name}` };
317
+ const envId = randomUUID();
318
+ imports.set(envId, imported);
319
+ plan = null;
320
+ if (imports.size > 20)
321
+ imports.delete(imports.keys().next().value);
322
+ return { envId, config: publicConfig(imported.env, imported.source, loadWorkspace(base)) };
323
+ },
324
+ saveEnv: async (input) => {
325
+ if (running())
326
+ throw new Error('다른 Confluence 작업이 진행 중입니다.');
327
+ locked = true;
328
+ let temp;
329
+ try {
330
+ const body = input;
331
+ if (!body || typeof body.base !== 'string' || typeof body.envId !== 'string')
332
+ throw new Error('가져온 .env 설정을 확인하세요.');
333
+ const imported = imports.get(body.envId);
334
+ if (!imported || keys.some(key => !imported.env[key]))
335
+ throw new Error('필수 연결 설정을 모두 포함한 .env를 가져오세요.');
336
+ const base = await realpath(resolve(body.base));
337
+ if (!(await stat(base)).isDirectory() || dirname(base) === base)
338
+ throw new Error('로컬 기준 폴더를 선택하세요.');
339
+ const path = join(base, '.env');
340
+ const snapshot = async () => {
341
+ try {
342
+ if (!(await lstat(path)).isFile())
343
+ throw new Error('.env는 일반 파일이어야 합니다. 심볼릭 링크는 저장할 수 없습니다.');
344
+ const content = await readFile(path, 'utf8');
345
+ return { content, hash: createHash('sha256').update(content).digest('hex') };
346
+ }
347
+ catch (error) {
348
+ if (error.code === 'ENOENT')
349
+ return { content: '', hash: null };
350
+ throw error;
351
+ }
352
+ };
353
+ const before = await snapshot();
354
+ if (!Object.hasOwn(body, 'expectedHash'))
355
+ return { needsConfirmation: before.hash !== null, expectedHash: before.hash, path };
356
+ if (body.expectedHash !== before.hash)
357
+ throw new Error('.env가 변경되었습니다. 저장을 다시 시도해 주세요.');
358
+ temp = join(base, `.csync-env-${randomUUID()}.tmp`);
359
+ await writeFile(temp, mergeConnection(before.content, imported.content), { mode: 0o600, flag: 'wx' });
360
+ if ((await snapshot()).hash !== before.hash)
361
+ throw new Error('.env가 변경되었습니다. 저장을 다시 시도해 주세요.');
362
+ await rename(temp, path);
363
+ temp = undefined;
364
+ plan = null;
365
+ const { env, source } = await settings(base, '', imports);
366
+ return { saved: true, config: publicConfig(env, source, loadWorkspace(base)) };
367
+ }
368
+ finally {
369
+ if (temp)
370
+ await unlink(temp).catch(() => { });
371
+ locked = false;
372
+ }
373
+ },
374
+ connect: async (input) => {
375
+ if (running())
376
+ throw new Error('다른 Confluence 작업이 진행 중입니다.');
377
+ locked = true;
378
+ plan = null;
379
+ try {
380
+ const { base, config, body } = await connectionSettings(input);
381
+ await connectWorkspace(base, config);
382
+ const { env, source } = await settings(base, body.envId, imports);
383
+ return publicConfig(env, source, loadWorkspace(base));
384
+ }
385
+ finally {
386
+ locked = false;
387
+ }
388
+ },
184
389
  current: () => job,
185
- config: async (base, envFile) => {
390
+ config: async (base, envId) => {
186
391
  const resolved = await realpath(resolve(base));
187
- const { env, source } = await settings(resolved, envFile);
188
- return publicConfig(env, source);
392
+ const { env, source } = await settings(resolved, envId, imports);
393
+ return publicConfig(env, source, loadWorkspace(resolved));
394
+ },
395
+ fetch: async (input) => {
396
+ if (running())
397
+ throw new Error('다른 작업이 진행 중입니다.');
398
+ locked = true;
399
+ plan = null;
400
+ try {
401
+ const { base, config, body } = await connectionSettings(input);
402
+ const workspace = loadWorkspace(base);
403
+ requireScope(workspace);
404
+ const { env, source } = await settings(base, body.envId, imports);
405
+ const visible = publicConfig(env, source, workspace);
406
+ if (visible.missing.length)
407
+ throw new Error(`설정 누락: ${visible.missing.join(', ')}`);
408
+ const url = new URL(config.baseUrl);
409
+ if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash)
410
+ throw new Error('Confluence BASE_URL은 인증정보·쿼리가 없는 HTTPS 주소여야 합니다.');
411
+ return launch('fetch', { selection: { base, target: '', envId: body.envId, verify: false, referenceRoots: [] }, env, config: visible, fingerprint: '' });
412
+ }
413
+ finally {
414
+ locked = false;
415
+ }
416
+ },
417
+ restore: async (input) => {
418
+ if (running())
419
+ throw new Error('다른 작업이 진행 중입니다.');
420
+ locked = true;
421
+ try {
422
+ const { base, body } = await connectionSettings(input);
423
+ const request = input;
424
+ const format = receiveFormat(input);
425
+ const workspace = loadWorkspace(base);
426
+ requireScope(workspace);
427
+ const { env, source } = await settings(base, body.envId, imports);
428
+ const config = publicConfig(env, source, workspace);
429
+ if (!config.connected || config.missing.length)
430
+ throw new Error('스페이스 연결과 .env 설정을 확인하세요.');
431
+ const url = new URL(config.baseUrl);
432
+ if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash)
433
+ throw new Error('Confluence BASE_URL은 인증정보·쿼리가 없는 HTTPS 주소여야 합니다.');
434
+ if (request.confirmationId !== undefined) {
435
+ const approved = restorePlan;
436
+ restorePlan = null;
437
+ if (!approved || request.confirmationId !== approved.id || approved.prepared.selection.base !== base || approved.prepared.selection.envId !== body.envId || approved.prepared.selection.format !== format)
438
+ throw new Error('복구 대상을 다시 확인하세요.');
439
+ if (await fingerprint(base, env) !== approved.prepared.fingerprint)
440
+ throw new Error('확인 이후 로컬 문서나 설정이 바뀌었습니다. 복구 대상을 다시 확인하세요.');
441
+ validateRestorePaths(base, approved.prepared.selection.restorePaths, approved.prepared.selection.restoreOverwrite);
442
+ return { job: launch('restore', approved.prepared) };
443
+ }
444
+ if (typeof request.path !== 'string' || typeof request.overwrite !== 'boolean')
445
+ throw new Error('복구할 문서와 덮어쓰기 여부를 확인하세요.');
446
+ const paths = validateRestorePaths(base, [request.path], request.overwrite);
447
+ const id = randomUUID();
448
+ restorePlan = { id, prepared: { selection: { base, target: '', envId: body.envId, verify: false, referenceRoots: [], format, restorePaths: paths, restoreOverwrite: request.overwrite }, env, config, fingerprint: await fingerprint(base, env) } };
449
+ return { confirmationId: id, path: paths[0], overwrite: request.overwrite, format };
450
+ }
451
+ finally {
452
+ locked = false;
453
+ }
454
+ },
455
+ pull: async (input) => {
456
+ if (running())
457
+ throw new Error('다른 작업이 진행 중입니다.');
458
+ locked = true;
459
+ plan = null;
460
+ try {
461
+ const { base, config, body } = await connectionSettings(input);
462
+ const format = receiveFormat(input);
463
+ const full = body.full;
464
+ const remoteOnly = body.remoteOnly;
465
+ if (remoteOnly !== undefined && typeof remoteOnly !== 'boolean' || remoteOnly && full)
466
+ throw new Error('원격 변경 가져오기 옵션을 확인하세요.');
467
+ if (full !== undefined && typeof full !== 'boolean')
468
+ throw new Error('전체 탐색 설정을 확인하세요.');
469
+ const workspace = loadWorkspace(base);
470
+ requireScope(workspace);
471
+ const { env, source } = await settings(base, body.envId, imports);
472
+ const visible = publicConfig(env, source, workspace);
473
+ if (visible.missing.length)
474
+ throw new Error(`설정 누락: ${visible.missing.join(', ')}`);
475
+ const url = new URL(config.baseUrl);
476
+ if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash)
477
+ throw new Error('Confluence BASE_URL은 인증정보·쿼리가 없는 HTTPS 주소여야 합니다.');
478
+ return launch('pull', { selection: { base, target: '', envId: body.envId, verify: false, referenceRoots: [], format, ...(full ? { full: true } : {}), ...(remoteOnly ? { remoteOnly: true } : {}) }, env, config: visible, fingerprint: '' });
479
+ }
480
+ finally {
481
+ locked = false;
482
+ }
189
483
  },
190
484
  preview: async (input) => {
191
485
  if (running())
192
- throw new Error('동기화 작업이 진행 중입니다.');
486
+ throw new Error('다른 Confluence 작업이 진행 중입니다.');
193
487
  locked = true;
194
488
  plan = null;
195
489
  try {
196
- return launch('preview', await prepare(input));
490
+ return launch('preview', await prepare(input, imports));
197
491
  }
198
492
  finally {
199
493
  locked = false;
@@ -201,14 +495,14 @@ export function createWebSync(runner = runSyncCLI) {
201
495
  },
202
496
  push: async (id) => {
203
497
  if (running())
204
- throw new Error('동기화 작업이 진행 중입니다.');
498
+ throw new Error('다른 Confluence 작업이 진행 중입니다.');
205
499
  if (typeof id !== 'string' || !plan || plan.id !== id)
206
- throw new Error('먼저 동기화 대상을 미리보기해 주세요.');
500
+ throw new Error('먼저 업로드 대상을 미리보기해 주세요.');
207
501
  locked = true;
208
502
  const approved = plan;
209
503
  plan = null;
210
504
  try {
211
- const updated = await prepare(approved.prepared.selection);
505
+ const updated = await prepare(approved.prepared.selection, imports);
212
506
  if (updated.fingerprint !== approved.prepared.fingerprint)
213
507
  throw new Error('문서나 설정이 변경되었습니다. 다시 미리보기해 주세요.');
214
508
  if (updated.config.missing.length)
@@ -0,0 +1,99 @@
1
+ /** Trusted bridge runs in an opaque-origin sandbox; document scripts are removed first. */
2
+ export function tableEditorBridge() {
3
+ const channel = document.currentScript.getAttribute('data-channel');
4
+ let enabled = false, selected = null, index = -1, widths = [];
5
+ let handles = [];
6
+ const send = (type) => parent.postMessage({ type, channel, index, widths }, '*');
7
+ const clear = () => { handles.forEach(h => h.remove()); handles = []; selected?.classList.remove('csync-selected'); };
8
+ const place = () => {
9
+ if (!selected)
10
+ return;
11
+ const rect = selected.getBoundingClientRect();
12
+ const total = widths.reduce((a, b) => a + b, 0);
13
+ let left = rect.left + scrollX;
14
+ handles.forEach((h, i) => {
15
+ left += widths[i] / total * rect.width;
16
+ Object.assign(h.style, { left: (left - 5) + 'px', top: (rect.top + scrollY) + 'px', height: rect.height + 'px' });
17
+ });
18
+ };
19
+ const apply = () => {
20
+ if (!selected)
21
+ return;
22
+ for (const group of Array.from(selected.children).filter(el => el.tagName === 'COLGROUP'))
23
+ group.remove();
24
+ const group = document.createElement('colgroup');
25
+ widths.forEach(width => { const col = document.createElement('col'); col.style.width = width + 'px'; group.append(col); });
26
+ selected.prepend(group);
27
+ selected.style.width = widths.reduce((a, b) => a + b, 0) + 'px';
28
+ selected.style.tableLayout = 'fixed';
29
+ place();
30
+ };
31
+ const select = (table, next, values) => {
32
+ clear();
33
+ selected = table;
34
+ index = next;
35
+ widths = values.slice();
36
+ selected.classList.add('csync-selected');
37
+ widths.slice(1).forEach((_, i) => {
38
+ const h = document.createElement('div');
39
+ h.className = 'csync-resize';
40
+ h.title = '열 너비 조절';
41
+ h.onpointerdown = event => {
42
+ event.preventDefault();
43
+ const start = event.clientX, original = widths.slice();
44
+ const scale = original.reduce((a, b) => a + b, 0) / selected.getBoundingClientRect().width;
45
+ h.setPointerCapture(event.pointerId);
46
+ h.onpointermove = move => {
47
+ const delta = Math.round((move.clientX - start) * scale);
48
+ const change = Math.max(40 - original[i], Math.min(original[i + 1] - 40, delta));
49
+ widths[i] = original[i] + change;
50
+ widths[i + 1] = original[i + 1] - change;
51
+ apply();
52
+ send('csync-table-change');
53
+ };
54
+ const end = () => { h.onpointermove = null; h.onpointerup = null; h.onpointercancel = null; };
55
+ h.onpointerup = end;
56
+ h.onpointercancel = end;
57
+ };
58
+ document.body.append(h);
59
+ handles.push(h);
60
+ });
61
+ apply();
62
+ };
63
+ document.addEventListener('click', event => {
64
+ if (!enabled || !(event.target instanceof Element))
65
+ return;
66
+ const table = event.target.closest('table[data-csync-table]');
67
+ if (!table)
68
+ return;
69
+ index = Number(table.dataset.csyncTable);
70
+ send('csync-table-select');
71
+ });
72
+ window.addEventListener('message', event => {
73
+ if (event.source !== parent || event.data?.channel !== channel)
74
+ return;
75
+ const data = event.data;
76
+ if (data.type === 'csync-table-edit') {
77
+ enabled = data.enabled === true;
78
+ document.body.classList.toggle('csync-editing', enabled);
79
+ if (!enabled) {
80
+ clear();
81
+ selected = null;
82
+ }
83
+ }
84
+ if (data.type === 'csync-table-widths' && enabled && Number.isInteger(data.index)
85
+ && Array.isArray(data.widths) && data.widths.length <= 32 && data.widths.every((w) => typeof w === 'number' && Number.isInteger(w) && w >= 40 && w <= 3000)) {
86
+ const table = document.querySelector(`table[data-csync-table="${data.index}"]`);
87
+ if (!table)
88
+ return;
89
+ if (table === selected) {
90
+ widths = data.widths.slice();
91
+ apply();
92
+ }
93
+ else
94
+ select(table, data.index, data.widths);
95
+ }
96
+ });
97
+ window.addEventListener('resize', place);
98
+ window.addEventListener('scroll', place);
99
+ }