@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.
- package/README.md +44 -410
- package/dist/cli/args.js +1 -1
- package/dist/cli/help.js +214 -115
- package/dist/cli/init.js +44 -5
- package/dist/cli/main.js +42 -11
- package/dist/cli/status.js +83 -0
- package/dist/confluence/client.js +121 -57
- package/dist/confluence/config.js +12 -8
- package/dist/confluence/env-file.js +23 -0
- package/dist/confluence/links.js +18 -0
- package/dist/conversion/asset-paths.js +5 -0
- package/dist/conversion/attachments.js +29 -7
- package/dist/conversion/convert.js +10 -22
- package/dist/conversion/footnotes.js +114 -11
- package/dist/conversion/markdown.js +26 -0
- package/dist/conversion/pdf-pages.js +10 -8
- package/dist/documents/anchors.js +9 -0
- package/dist/documents/callout-roundtrip.js +75 -0
- package/dist/documents/callouts.js +74 -0
- package/dist/documents/catalog.js +2 -2
- package/dist/documents/footnote-roundtrip.js +96 -0
- package/dist/documents/format.js +116 -0
- package/dist/documents/html-tables.js +30 -0
- package/dist/documents/html-to-markdown.js +47 -13
- package/dist/documents/markdown.js +46 -4
- package/dist/documents/obsidian.js +6 -3
- package/dist/documents/tables.js +89 -0
- package/dist/runtime/network.js +4 -0
- package/dist/shared/colors.js +2 -2
- package/dist/shared/progress.js +164 -0
- package/dist/shared/version.js +12 -0
- package/dist/site/assets/Monaco-LICENSE.txt +21 -0
- package/dist/site/assets/Monaco-ThirdPartyNotices.txt +448 -0
- package/dist/site/assets/PDFJS-LICENSE.txt +177 -0
- package/dist/site/assets/app.css +1 -0
- package/dist/site/assets/app.js +4 -0
- package/dist/site/assets/chunks/chunk-TEW74QPN.js +35 -0
- package/dist/site/assets/chunks/markdown-S6623E66.js +1 -0
- package/dist/site/assets/chunks/monaco-36ZGUH4Y.js +897 -0
- package/dist/site/assets/chunks/monaco-HFLEBJTI.css +1 -0
- package/dist/site/assets/chunks/pdf-DDN7TXTP.js +55 -0
- package/dist/site/assets/confluence-env-example.txt +32 -0
- package/dist/site/assets/editor.worker.js +1 -0
- package/dist/site/assets/favicon.svg +3 -0
- package/dist/site/assets/guide/01-account-settings.png +0 -0
- package/dist/site/assets/guide/02-atlassian-security.png +0 -0
- package/dist/site/assets/guide/03-api-tokens.png +0 -0
- package/dist/site/assets/guide/04-scope-api-token-step1.png +0 -0
- package/dist/site/assets/guide/05-scope-api-token-step2.png +0 -0
- package/dist/site/assets/guide/06-scope-api-token-step3.png +0 -0
- package/dist/site/assets/guide/07-scope-api-token-step4.png +0 -0
- package/dist/site/assets/guide/web/document-preview.png +0 -0
- package/dist/site/assets/guide/web/remote-diff.png +0 -0
- package/dist/site/assets/guide/web/sync-workspace.png +0 -0
- package/dist/site/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
- package/dist/site/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
- package/dist/site/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GB-H.bcmap +4 -0
- package/dist/site/assets/pdf/cmaps/GB-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Hankaku.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Hiragana.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Katakana.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/LICENSE +36 -0
- package/dist/site/assets/pdf/cmaps/NWP-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/NWP-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Roman.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
- package/dist/site/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/dist/site/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
- package/dist/site/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
- package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
- package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
- package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
- package/dist/site/assets/pdf/wasm/LICENSE_QCMS +21 -0
- package/dist/site/assets/pdf/wasm/jbig2.wasm +0 -0
- package/dist/site/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
- package/dist/site/assets/pdf/wasm/openjpeg.wasm +0 -0
- package/dist/site/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
- package/dist/site/assets/pdf/wasm/qcms_bg.wasm +0 -0
- package/dist/site/assets/pdf/wasm/quickjs-eval.js +16 -0
- package/dist/site/assets/pdf/wasm/quickjs-eval.wasm +0 -0
- package/dist/site/assets/pdf.worker.min.mjs +29 -0
- package/dist/site/assets/workspace.worker.js +409 -0
- package/dist/site/index.html +253 -0
- package/dist/sync/baseline.js +45 -0
- package/dist/sync/changes.js +51 -0
- package/dist/sync/diff.js +80 -0
- package/dist/sync/fetch.js +287 -0
- package/dist/sync/ignore.js +4 -4
- package/dist/sync/local-state.js +12 -0
- package/dist/sync/mapping.js +31 -8
- package/dist/sync/metadata.js +57 -0
- package/dist/sync/prepare.js +52 -0
- package/dist/sync/pull.js +618 -141
- package/dist/sync/push.js +260 -213
- package/dist/sync/reconcile.js +51 -0
- package/dist/sync/references.js +2 -2
- package/dist/sync/remap.js +17 -5
- package/dist/sync/render.js +3 -2
- package/dist/sync/restore.js +28 -0
- package/dist/sync/scope.js +47 -0
- package/dist/sync/staging.js +193 -0
- package/dist/sync/workspace.js +100 -0
- package/dist/web/assets/PDFJS-LICENSE.txt +177 -0
- package/dist/web/assets/app.css +1 -1
- package/dist/web/assets/app.js +3 -938
- package/dist/web/assets/chunks/chunk-TEW74QPN.js +35 -0
- package/dist/web/assets/chunks/markdown-S6623E66.js +1 -0
- package/dist/web/assets/chunks/monaco-36ZGUH4Y.js +897 -0
- package/dist/web/assets/chunks/monaco-HFLEBJTI.css +1 -0
- package/dist/web/assets/chunks/pdf-DDN7TXTP.js +55 -0
- package/dist/web/assets/confluence-env-example.txt +32 -0
- package/dist/web/assets/editor.worker.js +1 -30
- package/dist/web/assets/favicon.svg +3 -0
- package/dist/web/assets/guide/01-account-settings.png +0 -0
- package/dist/web/assets/guide/02-atlassian-security.png +0 -0
- package/dist/web/assets/guide/03-api-tokens.png +0 -0
- package/dist/web/assets/guide/04-scope-api-token-step1.png +0 -0
- package/dist/web/assets/guide/05-scope-api-token-step2.png +0 -0
- package/dist/web/assets/guide/06-scope-api-token-step3.png +0 -0
- package/dist/web/assets/guide/07-scope-api-token-step4.png +0 -0
- package/dist/web/assets/guide/web/document-preview.png +0 -0
- package/dist/web/assets/guide/web/remote-diff.png +0 -0
- package/dist/web/assets/guide/web/sync-workspace.png +0 -0
- package/dist/web/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
- package/dist/web/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
- package/dist/web/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GB-H.bcmap +4 -0
- package/dist/web/assets/pdf/cmaps/GB-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Hankaku.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Hiragana.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Katakana.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/LICENSE +36 -0
- package/dist/web/assets/pdf/cmaps/NWP-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/NWP-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Roman.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
- package/dist/web/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/dist/web/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
- package/dist/web/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
- package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
- package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
- package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
- package/dist/web/assets/pdf/wasm/LICENSE_QCMS +21 -0
- package/dist/web/assets/pdf/wasm/jbig2.wasm +0 -0
- package/dist/web/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
- package/dist/web/assets/pdf/wasm/openjpeg.wasm +0 -0
- package/dist/web/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
- package/dist/web/assets/pdf/wasm/qcms_bg.wasm +0 -0
- package/dist/web/assets/pdf/wasm/quickjs-eval.js +16 -0
- package/dist/web/assets/pdf/wasm/quickjs-eval.wasm +0 -0
- package/dist/web/assets/pdf.worker.min.mjs +29 -0
- package/dist/web/assets/workspace.worker.js +409 -0
- package/dist/web/document-source.js +14 -0
- package/dist/web/hosted-files.js +189 -0
- package/dist/web/hosted.js +316 -0
- package/dist/web/node-runner.js +26 -0
- package/dist/web/preview.js +74 -0
- package/dist/web/server.js +85 -240
- package/dist/web/sync.js +364 -70
- package/dist/web/table-editor-script.js +99 -0
- package/dist/web/table-format.js +224 -0
- package/dist/web/views/help.js +15 -10
- package/dist/web/views/sync-panel.js +90 -19
- package/dist/web/views/token-guide.js +27 -0
- package/dist/web/views/usage-guide.js +12 -0
- package/dist/web/views/workspace.js +85 -15
- package/dist/web/workspace-api.js +371 -0
- package/docs/user/CLI.md +366 -0
- package/docs/user/CONFIGURATION.md +125 -0
- package/docs/user/OBSIDIAN.md +117 -0
- package/docs/user/WEB.md +90 -0
- package/docs/user/images/web/document-preview.png +0 -0
- package/docs/user/images/web/remote-diff.png +0 -0
- package/docs/user/images/web/sync-workspace.png +0 -0
- 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 {
|
|
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
|
|
19
|
+
import { collectMarkdown } from '../documents/catalog.js';
|
|
11
20
|
import { buildIgnorer } from '../sync/ignore.js';
|
|
12
|
-
const keys =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 (
|
|
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,
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
hash.update(
|
|
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.
|
|
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
|
|
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 문서가 없습니다. 선택 범위와 .
|
|
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 =
|
|
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('
|
|
124
|
+
throw new Error('페이지 매핑 파일이 올바르지 않습니다. .csync/mapping.json 또는 기존 매핑을 확인해 주세요.');
|
|
92
125
|
}
|
|
93
|
-
|
|
94
|
-
const
|
|
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
|
|
106
|
-
const
|
|
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
|
-
|
|
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,
|
|
390
|
+
config: async (base, envId) => {
|
|
186
391
|
const resolved = await realpath(resolve(base));
|
|
187
|
-
const { env, source } = await settings(resolved,
|
|
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
|
+
}
|