@heycys/gallery 0.1.1 → 0.2.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/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +11 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +15 -4
- package/browser/editor/components/installed/page.mjs +103 -25
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +30 -9
- package/browser/editor/components/table/index.mjs +61 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +182 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +1059 -0
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +210 -0
- package/browser/editor/page/caret.mjs +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +133 -15
- package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +34 -16
- package/browser/editor/page/custom-page.mjs +110 -0
- package/browser/editor/page/editor.mjs +71 -17
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +41 -6
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +33 -14
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +9 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +15 -5
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/index.mjs +24 -9
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +103 -0
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +97 -15
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/block-packs.mjs +419 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +330 -46
- package/browser/shared/component-source.mjs +39 -0
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +20 -8
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +330 -27
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +359 -67
- package/browser/shared/pack-manifest.mjs +88 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +500 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +139 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/chunk-3MBRL2PM.mjs +16 -0
- package/dist/chunk-4OKWZY5E.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5K44HLTZ.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
- package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/chunk-6N3PX4XX.mjs +8 -0
- package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/chunk-7JDX4E65.mjs +13 -0
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/chunk-7OG26PGF.mjs +2 -0
- package/dist/chunk-AHN3NFKJ.mjs +3 -0
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/chunk-AR5D57ZD.mjs +170 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CMA72MAG.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-F4ZA6JRZ.mjs +3 -0
- package/dist/chunk-F6HVDZR4.mjs +2 -0
- package/dist/chunk-FDMAXMQA.mjs +2 -0
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/chunk-GHOYKMQ3.mjs +4 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/chunk-HPOI4ZX7.mjs +6 -0
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/chunk-IV64FFI4.mjs +2 -0
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/chunk-JA7G53PC.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JLTZF4LA.mjs +2 -0
- package/dist/chunk-JZT7I2OJ.mjs +2 -0
- package/dist/chunk-K5XATEOO.mjs +2 -0
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-LM4XFQHZ.mjs +2 -0
- package/dist/chunk-MN7BZL4R.mjs +2 -0
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/chunk-MXUBKDRO.mjs +15 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/chunk-OFHXGWOX.mjs +2 -0
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-PGDE24N5.mjs +2 -0
- package/dist/chunk-POTA2FV4.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QE5RG76S.mjs +549 -0
- package/dist/chunk-R2ZDLJYT.mjs +10 -0
- package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TR7TWGHB.mjs +2 -0
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/chunk-UGWMMEJ5.mjs +15 -0
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/chunk-VFX2KNHP.mjs +4 -0
- package/dist/chunk-VS7JIGJW.mjs +24 -0
- package/dist/chunk-W7665ZEC.mjs +6 -0
- package/dist/chunk-WQDQWCX5.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/chunk-YNAWBAYN.mjs +3 -0
- package/dist/chunk-YROX2O22.mjs +2 -0
- package/dist/chunk-ZDLPUOAG.mjs +6 -0
- package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZWWC4KLF.mjs +20 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +17 -17
- package/kit/report.css +335 -18
- package/kit/runtime.js +1638 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +130 -43
- package/kit/ui.js +79 -35
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +216 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +118 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +334 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +174 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +513 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +189 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +129 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +97 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +293 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +85 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +171 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +347 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +73 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +220 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +149 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +489 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +214 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +387 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +140 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +225 -0
- package/skill/references/writing-html.md +8 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BM_K-Auu.css +1 -0
- package/web/assets/index-DRslOBiv.js +15 -0
- package/web/index.html +2 -2
- package/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { writeAtomic } from "./files.mjs";
|
|
7
|
+
import { userDirectory } from "./user-directory.mjs";
|
|
8
|
+
import { layoutOf, markerOf } from "./workspace.mjs";
|
|
9
|
+
|
|
10
|
+
// The registry of the workspaces used on this machine (notes/plans/workspaces-links-plan-2026-11-08.md
|
|
11
|
+
// §2.3): one file in the user's data folder (../shared/user-directory.mjs "data": %LOCALAPPDATA%\gallery
|
|
12
|
+
// on Windows, ~/Library/Application Support/gallery on macOS, $XDG_STATE_HOME/gallery or
|
|
13
|
+
// ~/.local/state/gallery elsewhere; GALLERY_DATA_DIR in its place, which the tests set), so that a
|
|
14
|
+
// workspace an Agent made in a project's folder is found from any other (gallery workspaces, gallery
|
|
15
|
+
// list --all, and the sidebar's columns of other workspaces):
|
|
16
|
+
// { "version": 1, "workspaces": [{ "root": "<absolute path>", "seen": "<ISO time>" }] }
|
|
17
|
+
// A workspace is registered once a gallery command has found it (src/cli/gallery.mjs: every command
|
|
18
|
+
// but stop and skill; init and workspaces --name once they made it) and when its server starts
|
|
19
|
+
// (src/server/routes.mjs listening), `seen` written again an hour later at the soonest; never one in
|
|
20
|
+
// the system's temporary folder (the tests', a trial's, a check's), nor a folder whose gallery.json is
|
|
21
|
+
// not Gallery's. A path is one entry however it is spelt (upper and lower case alike on Windows). A
|
|
22
|
+
// change is made under the registry's lock (workspaces.json.lock), on the file as it is then, and
|
|
23
|
+
// written whole to a file beside it renamed over it, so that two commands registering at once each
|
|
24
|
+
// keep the other's (updateRegistry). A workspace whose folder
|
|
25
|
+
// is gone stays registered (an external drive comes back) until gallery workspaces --forget forgets it.
|
|
26
|
+
// Each workspace has a short id that never changes while its path does not: ws- and six hex digits of
|
|
27
|
+
// the hash of its path (workspaceId), for the sidebar's places and addresses.
|
|
28
|
+
|
|
29
|
+
export const REGISTRY_FILE = "workspaces.json";
|
|
30
|
+
/** How long a registration's `seen` is believed before a command writes it again. */
|
|
31
|
+
export const SEEN_EVERY = 60 * 60 * 1000;
|
|
32
|
+
|
|
33
|
+
/** The registry's file: <data folder>/workspaces.json. Only a path. */
|
|
34
|
+
export const registryFile = (options = {}) => path.join(userDirectory("data", options), REGISTRY_FILE);
|
|
35
|
+
|
|
36
|
+
/** A workspace's path as one key, however it is spelt: absolute, and lower case on Windows. */
|
|
37
|
+
export const workspaceKey = (root, platform = process.platform) => (platform === "win32" ? path.resolve(root).toLowerCase() : path.resolve(root));
|
|
38
|
+
|
|
39
|
+
/** The workspace's short id: ws- and the first six hex digits of the SHA-256 of its key. */
|
|
40
|
+
export const workspaceId = (root, platform = process.platform) => `ws-${createHash("sha256").update(workspaceKey(root, platform)).digest("hex").slice(0, 6)}`;
|
|
41
|
+
|
|
42
|
+
/** Whether `value` names a workspace's id (ws- and six hex digits). */
|
|
43
|
+
export const isWorkspaceId = (value) => /^ws-[0-9a-f]{6}$/.test(String(value ?? ""));
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The registry as `text` (the file's) holds it: { version: 1, workspaces: [{ root, seen }] }, each
|
|
47
|
+
* path absolute and once (the latest `seen` of two spellings kept), in the file's order; an entry that
|
|
48
|
+
* is not one left out, a file that does not read an empty registry.
|
|
49
|
+
*/
|
|
50
|
+
export function registryOf(text, platform = process.platform) {
|
|
51
|
+
let stored = null;
|
|
52
|
+
try {
|
|
53
|
+
stored = JSON.parse(String(text ?? "").replace(/^/, ""));
|
|
54
|
+
} catch {}
|
|
55
|
+
const workspaces = [];
|
|
56
|
+
const at = new Map();
|
|
57
|
+
for (const entry of Array.isArray(stored?.workspaces) ? stored.workspaces : []) {
|
|
58
|
+
if (typeof entry?.root !== "string" || !path.isAbsolute(entry.root)) continue;
|
|
59
|
+
const seen = typeof entry.seen === "string" && Number.isFinite(Date.parse(entry.seen)) ? entry.seen : new Date(0).toISOString();
|
|
60
|
+
const key = workspaceKey(entry.root, platform);
|
|
61
|
+
if (!at.has(key)) {
|
|
62
|
+
at.set(key, workspaces.length);
|
|
63
|
+
workspaces.push({ root: path.resolve(entry.root), seen });
|
|
64
|
+
} else if (Date.parse(seen) > Date.parse(workspaces[at.get(key)].seen)) workspaces[at.get(key)].seen = seen;
|
|
65
|
+
}
|
|
66
|
+
return { version: 1, workspaces };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The registry as read now (registryOf of its file; none there: an empty one). */
|
|
70
|
+
export function readRegistry({ file = registryFile() } = {}) {
|
|
71
|
+
try {
|
|
72
|
+
return registryOf(readFileSync(file, "utf8"));
|
|
73
|
+
} catch {
|
|
74
|
+
return { version: 1, workspaces: [] };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// The registry's lock (workspaces.json.lock beside it): a file one process alone can make ("wx"),
|
|
79
|
+
// removed after; one older than LOCK_STALE was left by a process that ended and is taken over, and so is
|
|
80
|
+
// one held past LOCK_WAIT (a writer holds it for a read and a rename: a command never waits long).
|
|
81
|
+
// EPERM is a lock being removed (Windows: a file whose removal is pending) and a folder that cannot be
|
|
82
|
+
// written as well (Windows' rights, the sandbox of macOS an Agent may run in, which allows writes in its
|
|
83
|
+
// project alone): where no lock is there, LOCK_REFUSED of them in a row are the folder's, thrown at once,
|
|
84
|
+
// so that a command in such a sandbox is not held LOCK_WAIT twice over by every registration.
|
|
85
|
+
const LOCK_STALE = 10_000;
|
|
86
|
+
const LOCK_WAIT = 3_000;
|
|
87
|
+
const LOCK_REFUSED = 3;
|
|
88
|
+
async function withLock(file, task) {
|
|
89
|
+
const lock = `${file}.lock`;
|
|
90
|
+
const mine = `${process.pid} ${Math.random().toString(16).slice(2)}`;
|
|
91
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
92
|
+
for (let refused = 0, until = Date.now() + LOCK_WAIT; ;) {
|
|
93
|
+
try {
|
|
94
|
+
await fs.writeFile(lock, mine, { flag: "wx" });
|
|
95
|
+
break;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (error.code !== "EEXIST" && error.code !== "EPERM") throw error;
|
|
98
|
+
// The lock's age; null where there is none (removed meanwhile, or never made: a folder refusing it).
|
|
99
|
+
const age = await fs.stat(lock).then(({ mtimeMs }) => Date.now() - mtimeMs, (statError) => (statError.code === "ENOENT" ? null : 0));
|
|
100
|
+
refused = error.code === "EPERM" && age === null ? refused + 1 : 0;
|
|
101
|
+
if (refused >= LOCK_REFUSED) throw error; // a folder that cannot be written
|
|
102
|
+
if (Date.now() > until + LOCK_WAIT) throw error; // neither made nor taken over
|
|
103
|
+
if (age !== null && (age > LOCK_STALE || Date.now() > until)) await fs.rm(lock, { force: true }).catch(() => {});
|
|
104
|
+
await new Promise((resolve) => setTimeout(resolve, 10 + Math.random() * 20));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
return await task();
|
|
109
|
+
} finally {
|
|
110
|
+
if ((await fs.readFile(lock, "utf8").catch(() => null)) === mine) await fs.rm(lock, { force: true }).catch(() => {});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Change the registry: `change(registry)` gives the registry to write, or null for nothing to write.
|
|
116
|
+
* Under the registry's lock, so that two commands writing at once each make their change on what the
|
|
117
|
+
* other wrote: read, changed and written whole (a file beside it, renamed over it), made again on what
|
|
118
|
+
* the file holds when it changed between the read and the rename all the same (a lock taken over).
|
|
119
|
+
* Resolves to the registry as it stands after.
|
|
120
|
+
*/
|
|
121
|
+
export async function updateRegistry(change, { file = registryFile() } = {}) {
|
|
122
|
+
return withLock(file, async () => {
|
|
123
|
+
for (let tries = 0; tries < 8; tries++) {
|
|
124
|
+
const text = await fs.readFile(file, "utf8").catch((error) => (error.code === "ENOENT" ? null : Promise.reject(error)));
|
|
125
|
+
const current = registryOf(text);
|
|
126
|
+
const next = change(current);
|
|
127
|
+
if (!next) return current;
|
|
128
|
+
if (await writeAtomic(file, `${JSON.stringify({ version: 1, workspaces: next.workspaces }, null, 2)}\n`, { expect: text })) return next;
|
|
129
|
+
}
|
|
130
|
+
throw new Error(`${file} kept changing while it was written: try again.`);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// The system's temporary folders, each as its path is written and as it really is (macOS's /var is
|
|
135
|
+
// /private/var, its /tmp /private/tmp): os.tmpdir()'s (`tmp`), and /tmp but on Windows, for macOS's
|
|
136
|
+
// os.tmpdir() is a folder of the user's under /var/folders while Agents' trials go to /tmp, which a
|
|
137
|
+
// restart clears.
|
|
138
|
+
function temporaryFolders(tmp, platform) {
|
|
139
|
+
const folders = [];
|
|
140
|
+
for (const folder of [tmp, ...(platform === "win32" ? [] : ["/tmp"])]) {
|
|
141
|
+
folders.push(path.resolve(folder));
|
|
142
|
+
try {
|
|
143
|
+
folders.push(realpathSync.native(folder));
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
146
|
+
return folders;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Whether `root` is in one of the system's temporary folders (`tmp`, os.tmpdir()'s, and /tmp but on Windows), or is one. */
|
|
150
|
+
export function isTemporary(root, { tmp = os.tmpdir(), platform = process.platform } = {}) {
|
|
151
|
+
const roots = [path.resolve(root)];
|
|
152
|
+
try {
|
|
153
|
+
roots.push(realpathSync.native(root));
|
|
154
|
+
} catch {}
|
|
155
|
+
return temporaryFolders(tmp, platform).some((folder) => {
|
|
156
|
+
const base = workspaceKey(folder, platform);
|
|
157
|
+
return roots.some((each) => {
|
|
158
|
+
const key = workspaceKey(each, platform);
|
|
159
|
+
return key === base || key.startsWith(base.endsWith(path.sep) ? base : `${base}${path.sep}`);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Whether the folder `root` is a workspace now: its gallery.json there, and Gallery's. */
|
|
165
|
+
export function isWorkspace(root) {
|
|
166
|
+
try {
|
|
167
|
+
return markerOf(readFileSync(layoutOf(root).marker, "utf8")).ours;
|
|
168
|
+
} catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Register the workspace at `root`: added with `seen` now, or its `seen` written again when it is
|
|
175
|
+
* SEEN_EVERY old (`force`: whatever its age). Nothing is written for a folder in the system's
|
|
176
|
+
* temporary folder or one that is no workspace of Gallery's. Resolves to "added", "seen", "fresh" (its
|
|
177
|
+
* `seen` recent: nothing written), "temporary" or "none" (no workspace there).
|
|
178
|
+
*/
|
|
179
|
+
export async function registerWorkspace(root, { file = registryFile(), now = Date.now(), tmp = os.tmpdir(), force = false } = {}) {
|
|
180
|
+
const resolved = path.resolve(root);
|
|
181
|
+
if (isTemporary(resolved, { tmp })) return "temporary";
|
|
182
|
+
if (!isWorkspace(resolved)) return "none";
|
|
183
|
+
const key = workspaceKey(resolved);
|
|
184
|
+
const recent = (entry) => {
|
|
185
|
+
const age = now - Date.parse(entry.seen);
|
|
186
|
+
return !force && age >= 0 && age < SEEN_EVERY;
|
|
187
|
+
};
|
|
188
|
+
// Seen within the hour, as most commands find it: read alone, no lock taken.
|
|
189
|
+
const known = readRegistry({ file }).workspaces.find((each) => workspaceKey(each.root) === key);
|
|
190
|
+
if (known && recent(known)) return "fresh";
|
|
191
|
+
let did = "fresh";
|
|
192
|
+
await updateRegistry((registry) => {
|
|
193
|
+
const seen = new Date(now).toISOString();
|
|
194
|
+
const entry = registry.workspaces.find((each) => workspaceKey(each.root) === key);
|
|
195
|
+
if (!entry) {
|
|
196
|
+
did = "added";
|
|
197
|
+
return { version: 1, workspaces: [...registry.workspaces, { root: resolved, seen }] };
|
|
198
|
+
}
|
|
199
|
+
if (recent(entry)) {
|
|
200
|
+
did = "fresh";
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
did = "seen";
|
|
204
|
+
return { version: 1, workspaces: registry.workspaces.map((each) => (each === entry ? { root: each.root, seen } : each)) };
|
|
205
|
+
}, { file });
|
|
206
|
+
return did;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** registerWorkspace for a command or a server, which never fails for it: a registry that cannot be read or written is passed over ("failed"). */
|
|
210
|
+
export const registerQuietly = (root, options) => registerWorkspace(root, options).catch(() => "failed");
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Forget the registered workspaces `target` names (a path, as the registry holds it in any spelling, or
|
|
214
|
+
* a ws- id): nothing on disk but the registry changes. Resolves to the roots forgotten ([] for none).
|
|
215
|
+
*/
|
|
216
|
+
export async function forgetWorkspace(target, { file = registryFile(), cwd = process.cwd() } = {}) {
|
|
217
|
+
const byId = isWorkspaceId(target);
|
|
218
|
+
const key = byId ? null : workspaceKey(path.resolve(cwd, target));
|
|
219
|
+
const named = (entry) => (byId ? workspaceId(entry.root) === target : workspaceKey(entry.root) === key);
|
|
220
|
+
let forgotten = [];
|
|
221
|
+
await updateRegistry((registry) => {
|
|
222
|
+
forgotten = registry.workspaces.filter(named).map((entry) => entry.root);
|
|
223
|
+
return forgotten.length ? { version: 1, workspaces: registry.workspaces.filter((entry) => !named(entry)) } : null;
|
|
224
|
+
}, { file });
|
|
225
|
+
return forgotten;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The folders a scan passes over by name (upper and lower case alike), besides every dot folder: a
|
|
230
|
+
* package's and a repository's own, and Windows' own on a drive, its recycle bin among them (a workspace
|
|
231
|
+
* thrown away there is no workspace to find).
|
|
232
|
+
*/
|
|
233
|
+
export const SCAN_SKIPS = new Set(["node_modules", ".git", "$recycle.bin", "recycler", "system volume information"]);
|
|
234
|
+
/** How deep a scan looks below its folder, and how many folders it reads at most. */
|
|
235
|
+
export const SCAN_DEPTH = 6;
|
|
236
|
+
export const SCAN_LIMIT = 50_000;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* The workspaces in `folder` and below it, `depth` levels down at most (gallery workspaces --scan):
|
|
240
|
+
* each folder whose gallery.json is Gallery's, sorted, none looked in further (a workspace holds
|
|
241
|
+
* documents, not workspaces). Passed over: dot folders, those SCAN_SKIPS names (node_modules, the
|
|
242
|
+
* recycle bin), links (they lead out of it) and folders that cannot be read. Resolves to { found:
|
|
243
|
+
* [root], read: folders read, cut: whether it stopped at `limit` folders }.
|
|
244
|
+
*/
|
|
245
|
+
export async function scanForWorkspaces(folder, { depth = SCAN_DEPTH, limit = SCAN_LIMIT } = {}) {
|
|
246
|
+
const found = [];
|
|
247
|
+
let read = 0;
|
|
248
|
+
let cut = false;
|
|
249
|
+
let level = [path.resolve(folder)];
|
|
250
|
+
for (let at = 0; at <= depth && level.length && !cut; at++) {
|
|
251
|
+
const next = [];
|
|
252
|
+
for (const directory of level) {
|
|
253
|
+
if (read >= limit) {
|
|
254
|
+
cut = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
read++;
|
|
258
|
+
if (isWorkspace(directory)) {
|
|
259
|
+
found.push(directory);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (at === depth) continue;
|
|
263
|
+
const entries = await fs.readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
264
|
+
for (const entry of entries) {
|
|
265
|
+
if (!entry.isDirectory() || entry.name.startsWith(".") || SCAN_SKIPS.has(entry.name.toLowerCase())) continue;
|
|
266
|
+
next.push(path.join(directory, entry.name));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
level = next;
|
|
270
|
+
}
|
|
271
|
+
return { found: found.sort(), read, cut };
|
|
272
|
+
}
|
|
@@ -4,6 +4,8 @@ import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
+
import { DOC_SLUG, earlierId, newPageId, pageId } from "./page-links.mjs";
|
|
8
|
+
import { LINK_FILE, readLinkText } from "./web-links.mjs";
|
|
7
9
|
|
|
8
10
|
// A workspace: the folder of the user's documents (docs/internals.md, "Where things live"). Found in
|
|
9
11
|
// this order: --workspace <dir> (the gallery command sets GALLERY_WORKSPACE from it before it loads
|
|
@@ -11,20 +13,26 @@ import path from "node:path";
|
|
|
11
13
|
// one holding a gallery.json that says it is ours ({ "gallery": "workspace", "version": 1 }: another
|
|
12
14
|
// program's gallery.json is not), else Gallery in the user's Documents folder (~/Documents/Gallery:
|
|
13
15
|
// documentsFolder() says which folder that is on each system). Its root shows the user's documents,
|
|
14
|
-
// gallery.json, preferences.md (写作偏好), exports/ and
|
|
16
|
+
// gallery.json, preferences.md (写作偏好), exports/, components/, pages/ and extensions/ only:
|
|
15
17
|
//
|
|
16
18
|
// <workspace>/gallery.json, preferences.md, exports/<slug>.html (the offline deliverables)
|
|
17
19
|
// <workspace>/components/<scope>/<name>/ a component package (./component-catalog.mjs), no document
|
|
20
|
+
// <workspace>/pages/<slug>/page.html, page.json a custom page (./pages.mjs), no document
|
|
21
|
+
// <workspace>/extensions/<id>/sidebar.json the sidebar column an extension provides (./extensions.mjs), no document
|
|
18
22
|
// <workspace>/<slug>/doc.html, doc.json (report.html, report.json in a document made before
|
|
19
23
|
// Gallery 0.1: read and written under those names, never renamed), assets/, materials/, annotations.json
|
|
24
|
+
// <workspace>/<slug>/link.json a web link of the sidebar (./web-links.mjs), no document
|
|
20
25
|
// <workspace>/.gallery/ everything else Gallery keeps: the sidebar's outline, the trash, the emoji
|
|
21
26
|
// library, the 写作偏好 page (pages/<slug>/), the edit state (state/), qa's pictures, backups, built
|
|
22
|
-
// previews, the server's announcement, port and log,
|
|
27
|
+
// previews, the server's announcement, port and log, what was adopted of an old layout, and the
|
|
28
|
+
// scratch copies gallery block try makes a trial on (try/try-<8 hex>/, each gone once its trial ends).
|
|
23
29
|
//
|
|
24
30
|
// A document is a folder at the root holding doc.html or report.html, its name a slug that is not
|
|
25
31
|
// reserved (exports, generated, which the preview's addresses keep, the names Windows keeps for
|
|
26
|
-
// devices: a workspace moves between systems) and not a dot name. components/
|
|
27
|
-
// one of
|
|
32
|
+
// devices: a workspace moves between systems) and not a dot name. components/, pages/ and extensions/
|
|
33
|
+
// hold no document, but one of those names made before they came stays one, and no new one takes it
|
|
34
|
+
// (COMPONENTS_FOLDER, PAGES_FOLDER, EXTENSIONS_FOLDER). A custom page's slug and a document's are one pool: no new
|
|
35
|
+
// document takes a page's slug, nor a new page a document's (slugTaken).
|
|
28
36
|
// Nothing here writes outside the workspace, and nothing writes an old folder it copies from.
|
|
29
37
|
// Node's built-ins only: every system reads its layout from here.
|
|
30
38
|
|
|
@@ -50,12 +58,27 @@ export const RESERVED = new Set(["exports", "generated", ...DEVICE_NAMES]);
|
|
|
50
58
|
* name no new document takes (slugTaken, keptName), the next free one coming instead.
|
|
51
59
|
*/
|
|
52
60
|
export const COMPONENTS_FOLDER = "components";
|
|
61
|
+
/**
|
|
62
|
+
* The folder of a workspace's custom pages (pages/<slug>/: ./pages.mjs). As components/, it hides
|
|
63
|
+
* nothing: a document called so, made before the custom pages came, keeps its folder and stays a
|
|
64
|
+
* document beside them; it is only a name no new document or page takes.
|
|
65
|
+
*/
|
|
66
|
+
export const PAGES_FOLDER = "pages";
|
|
67
|
+
/**
|
|
68
|
+
* The folder of a workspace's extensions (extensions/<id>/: ./extensions.mjs), each of which may provide a
|
|
69
|
+
* column of the sidebar (sidebar.json) and holds whatever else the extension keeps. As components/ and
|
|
70
|
+
* pages/, it hides nothing: a document called so, made before extensions came, keeps its folder and stays
|
|
71
|
+
* a document beside them; it is only a name no new document or page takes.
|
|
72
|
+
*/
|
|
73
|
+
export const EXTENSIONS_FOLDER = "extensions";
|
|
53
74
|
/** A component package's manifest, which is what makes a folder of components/ a package. */
|
|
54
75
|
export const PACKAGE_MANIFEST = "component.json";
|
|
55
|
-
/** The folders a document keeps beside its files: what is its own of a folder it shares with the packages. */
|
|
76
|
+
/** The folders a document keeps beside its files: what is its own of a folder it shares with the packages or the custom pages. */
|
|
56
77
|
export const DOCUMENT_FOLDERS = ["assets", "materials"];
|
|
57
|
-
/**
|
|
58
|
-
export const
|
|
78
|
+
/** The folders at the root that hold no document but may share their name with one made before them. */
|
|
79
|
+
export const SHARED_FOLDERS = [COMPONENTS_FOLDER, PAGES_FOLDER, EXTENSIONS_FOLDER];
|
|
80
|
+
/** Whether a new document (or custom page) may not be called `name`, whatever the workspace holds. */
|
|
81
|
+
export const keptName = (name) => RESERVED.has(name) || SHARED_FOLDERS.includes(name);
|
|
59
82
|
/** Whether `name` may be a document's slug. */
|
|
60
83
|
export const isSlugName = (name) => typeof name === "string" && slugPattern.test(name) && !RESERVED.has(name);
|
|
61
84
|
/** The slug of the 写作偏好 page made new (one copied from an old layout keeps its own). */
|
|
@@ -98,6 +121,15 @@ const markerAt = (file) => {
|
|
|
98
121
|
}
|
|
99
122
|
};
|
|
100
123
|
|
|
124
|
+
/**
|
|
125
|
+
* The default workspace, where a command goes when nothing names one and none is found up from the
|
|
126
|
+
* current folder: Gallery in the user's Documents folder, or the folder GALLERY_DEFAULT_WORKSPACE names
|
|
127
|
+
* (the browser scenarios', whose studio is the default workspace for a draft made elsewhere: src/shared/drafts.mjs).
|
|
128
|
+
*/
|
|
129
|
+
export const defaultWorkspace = ({ env = process.env, home = os.homedir(), cwd = process.cwd() } = {}) => (env.GALLERY_DEFAULT_WORKSPACE
|
|
130
|
+
? path.resolve(cwd, env.GALLERY_DEFAULT_WORKSPACE)
|
|
131
|
+
: path.join(documentsFolder({ home, env }), "Gallery"));
|
|
132
|
+
|
|
101
133
|
/**
|
|
102
134
|
* Where the workspace is: { root, how } (how: "flag", "env", "found" or "default"). Reads gallery.json
|
|
103
135
|
* files on the way up, writes nothing (ensureWorkspace makes it).
|
|
@@ -109,7 +141,7 @@ export function findWorkspace({ flag = null, env = process.env, cwd = process.cw
|
|
|
109
141
|
if (markerAt(path.join(directory, WORKSPACE_FILE)).ours) return { root: directory, how: "found" };
|
|
110
142
|
if (path.dirname(directory) === directory) break;
|
|
111
143
|
}
|
|
112
|
-
return { root:
|
|
144
|
+
return { root: defaultWorkspace({ env, home, cwd }), how: "default" };
|
|
113
145
|
}
|
|
114
146
|
|
|
115
147
|
// Where Windows keeps the Documents folder Explorer shows as 文档: the Personal shell folder, as the
|
|
@@ -193,14 +225,34 @@ export function layoutOf(root) {
|
|
|
193
225
|
preferences: path.join(resolved, "preferences.md"),
|
|
194
226
|
exports: path.join(resolved, "exports"),
|
|
195
227
|
components: path.join(resolved, COMPONENTS_FOLDER),
|
|
228
|
+
// The custom pages (./pages.mjs), at the root as the packages are: the user's and the Agent's. Not
|
|
229
|
+
// called pages, which named .gallery/pages/ before (preferencesPage now): code written for that
|
|
230
|
+
// meaning finds no such key and fails, never reading this folder for the 写作偏好 page's.
|
|
231
|
+
customPages: path.join(resolved, PAGES_FOLDER),
|
|
232
|
+
// The extensions (./extensions.mjs: extensions/<id>/sidebar.json), the user's and the Agent's.
|
|
233
|
+
extensions: path.join(resolved, EXTENSIONS_FOLDER),
|
|
196
234
|
gallery,
|
|
197
235
|
outline: path.join(gallery, "outline.json"),
|
|
236
|
+
blocks: path.join(gallery, "blocks.json"),
|
|
237
|
+
// What the reader closed of Gallery's own notes, once for the workspace: the home page's first-open
|
|
238
|
+
// note (src/shared/pages.mjs homeHintClosed).
|
|
239
|
+
hints: path.join(gallery, "hints.json"),
|
|
240
|
+
// The keys of the sites the workspace's blocks reach, by host (./net-keys.mjs: gallery block key),
|
|
241
|
+
// never in gallery.json, whose settings every page is told; and what the net route fetched for them
|
|
242
|
+
// (./net-cache.mjs), which may be thrown away.
|
|
243
|
+
keys: path.join(gallery, "keys.json"),
|
|
244
|
+
netCache: path.join(gallery, "cache", "net"),
|
|
198
245
|
trash: path.join(gallery, "trash"),
|
|
199
246
|
emojiLibrary: path.join(gallery, "emoji-library"),
|
|
200
|
-
|
|
247
|
+
// The 写作偏好 page's folder (.gallery/pages/<slug>/: a document of Gallery's own, never a custom page).
|
|
248
|
+
preferencesPage: path.join(gallery, "pages"),
|
|
201
249
|
state,
|
|
250
|
+
// The workspace's record of edits by day (src/workbench/activity.mjs): what the 编辑热力图 shows; losable.
|
|
251
|
+
activity: path.join(state, "activity.json"),
|
|
202
252
|
history: path.join(state, "history"),
|
|
203
253
|
qa: path.join(gallery, "qa"),
|
|
254
|
+
// The scratch copies gallery block try makes a trial on (try-<8 hex>/: ownOrScratch).
|
|
255
|
+
scratch: path.join(gallery, "try"),
|
|
204
256
|
backups: path.join(gallery, "backups"),
|
|
205
257
|
built: path.join(gallery, "built"),
|
|
206
258
|
logs: path.join(gallery, "logs"),
|
|
@@ -252,17 +304,81 @@ export function documentFiles(directory) {
|
|
|
252
304
|
};
|
|
253
305
|
}
|
|
254
306
|
|
|
255
|
-
/** Where document `slug` is: the 写作偏好 page's folder under .gallery/pages/ when it is one, else
|
|
307
|
+
/** Where document `slug` is: the 写作偏好 page's folder under .gallery/pages/ when it is one, else ownOrScratch's. */
|
|
256
308
|
export function documentDirectory(slug, root) {
|
|
257
|
-
const page = path.join(layoutOf(root).
|
|
258
|
-
return existsSync(page) ? page :
|
|
309
|
+
const page = path.join(layoutOf(root).preferencesPage, slug);
|
|
310
|
+
return existsSync(page) ? page : ownOrScratch(slug, root);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Where document `slug` that is no 写作偏好 page is: <root>/<slug>; or, where no folder at the root has
|
|
315
|
+
* that name, a scratch copy's in .gallery/try/ (gallery block try's, try-<8 hex>: served and edited
|
|
316
|
+
* as any document, listed nowhere, and gone once its trial ends, src/cli/component-try.mjs).
|
|
317
|
+
*/
|
|
318
|
+
function ownOrScratch(slug, root) {
|
|
319
|
+
const own = path.join(path.resolve(root), slug);
|
|
320
|
+
const copy = path.join(layoutOf(root).scratch, slug);
|
|
321
|
+
return !existsSync(own) && existsSync(copy) ? copy : own;
|
|
259
322
|
}
|
|
260
323
|
|
|
261
|
-
/**
|
|
324
|
+
/**
|
|
325
|
+
* Whether `slug` can name no new document or custom page (one pool): a name kept, or held by a folder
|
|
326
|
+
* at the root, the 写作偏好 page or a custom page (pages/<slug>/).
|
|
327
|
+
*/
|
|
262
328
|
export function slugTaken(slug, root) {
|
|
263
|
-
|
|
329
|
+
const layout = layoutOf(root);
|
|
330
|
+
return keptName(slug) || [layout.root, layout.preferencesPage, layout.customPages].some((folder) => existsSync(path.join(folder, slug)));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* The folder names a page id may come of in a workspace, every one that has an address: a folder at
|
|
335
|
+
* the root (a document, a web link, whatever else), a custom page's, the 写作偏好 page's, and the slug
|
|
336
|
+
* of everything in the trash (a document there goes by its id until it is restored).
|
|
337
|
+
*/
|
|
338
|
+
export async function pageNames(root) {
|
|
339
|
+
const layout = layoutOf(root);
|
|
340
|
+
const names = new Set();
|
|
341
|
+
await Promise.all([layout.root, layout.preferencesPage, layout.customPages].map(async (folder) => {
|
|
342
|
+
for (const entry of await fs.readdir(folder, { withFileTypes: true }).catch(() => [])) if (entry.isDirectory() && !entry.name.startsWith(".")) names.add(entry.name);
|
|
343
|
+
}));
|
|
344
|
+
for (const { slug } of await listTrash(root)) if (typeof slug === "string") names.add(slug);
|
|
345
|
+
return names;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* The folder name of a new document: doc-<a new page id> (DOC_SLUG), an id that no name of the
|
|
350
|
+
* workspace has (pageNames: the hash id of an old name counts as the id of a doc-<id> one, and the
|
|
351
|
+
* earlier id of a doc-<eight> name, which its old addresses still open), its folder
|
|
352
|
+
* free (slugTaken: the root, the 写作偏好 page and the custom pages; the trash's slugs are among the
|
|
353
|
+
* names). `random` is newPageId's, for the tests.
|
|
354
|
+
* @param {string} root
|
|
355
|
+
* @param {{ random?: () => number }} [options]
|
|
356
|
+
*/
|
|
357
|
+
export async function newDocSlug(root, { random = undefined } = {}) {
|
|
358
|
+
const taken = new Set();
|
|
359
|
+
for (const name of await pageNames(root)) for (const id of [pageId(name), earlierId(name)]) if (id !== null) taken.add(id);
|
|
360
|
+
for (;;) {
|
|
361
|
+
const slug = `doc-${newPageId(taken, random)}`;
|
|
362
|
+
if (!slugTaken(slug, root)) return slug;
|
|
363
|
+
taken.add(slug.slice(4));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Another name of the workspace that has the page id of `slug` (pageNames), or null: what makes a
|
|
369
|
+
* doc-<id> name a document may not take, its id being another's.
|
|
370
|
+
* @param {string} slug
|
|
371
|
+
* @param {string} root
|
|
372
|
+
*/
|
|
373
|
+
export async function idHolder(slug, root) {
|
|
374
|
+
const id = pageId(slug);
|
|
375
|
+
for (const name of await pageNames(root)) if (name !== slug && pageId(name) === id) return name;
|
|
376
|
+
return null;
|
|
264
377
|
}
|
|
265
378
|
|
|
379
|
+
/** Whether `slug` is a name the workbench's new documents have (doc-<eight>: DOC_SLUG), whose id is in it. */
|
|
380
|
+
export const isDocSlug = (slug) => DOC_SLUG.test(slug);
|
|
381
|
+
|
|
266
382
|
// The folders right in `directory`, by name, sorted: no dot name, and no link, which leads out of it.
|
|
267
383
|
const foldersIn = (directory) => {
|
|
268
384
|
try {
|
|
@@ -325,20 +441,55 @@ export async function listDocumentSlugs(root) {
|
|
|
325
441
|
return (await documentsIn(path.resolve(root))).filter((entry) => !entry.instructions).map((entry) => entry.slug);
|
|
326
442
|
}
|
|
327
443
|
|
|
444
|
+
/**
|
|
445
|
+
* The web links of a workspace (./web-links.mjs), by slug, sorted: the folders at its root, named as
|
|
446
|
+
* documents are, holding a link.json that reads as a link and no doc.html or report.html (a document,
|
|
447
|
+
* whatever else it holds).
|
|
448
|
+
*/
|
|
449
|
+
export async function listLinkSlugs(root) {
|
|
450
|
+
const directory = path.resolve(root);
|
|
451
|
+
const entries = await fs.readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
452
|
+
const found = await Promise.all(entries
|
|
453
|
+
.filter((entry) => entry.isDirectory() && isSlugName(entry.name))
|
|
454
|
+
.map(async ({ name }) => {
|
|
455
|
+
const folder = path.join(directory, name);
|
|
456
|
+
if (existsSync(path.join(folder, NEW.html)) || existsSync(path.join(folder, OLD.html))) return null;
|
|
457
|
+
return (await readLink(folder)) ? name : null;
|
|
458
|
+
}));
|
|
459
|
+
return found.filter(Boolean).sort();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** The web link of folder `folder` ({ url, title, icon? }), or null where there is none or it does not read. */
|
|
463
|
+
export async function readLink(folder) {
|
|
464
|
+
const text = await fs.readFile(path.join(folder, LINK_FILE), "utf8").catch(() => null);
|
|
465
|
+
return text === null ? null : readLinkText(text);
|
|
466
|
+
}
|
|
467
|
+
|
|
328
468
|
/** The 写作偏好 page's slug (the first document under .gallery/pages/), or null when there is none yet. */
|
|
329
469
|
export async function pageSlug(root) {
|
|
330
|
-
return (await documentsIn(layoutOf(root).
|
|
470
|
+
return (await documentsIn(layoutOf(root).preferencesPage))[0]?.slug ?? null;
|
|
331
471
|
}
|
|
332
472
|
|
|
333
473
|
/** The id of an entry of the trash, a folder of .gallery/trash/. */
|
|
334
474
|
export const trashIdPattern = /^[a-z0-9]+-[a-z0-9]+$/;
|
|
335
475
|
|
|
336
|
-
/**
|
|
476
|
+
/**
|
|
477
|
+
* What a trash entry holds: a document, a custom page (./pages.mjs) or a web link (./web-links.mjs).
|
|
478
|
+
* An entry written before the custom pages came holds a document.
|
|
479
|
+
*/
|
|
480
|
+
export const TRASH_KINDS = ["document", "page", "link"];
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* What the trash holds, the latest first: each folder's entry.json ({ id, kind, slug, title, at,
|
|
484
|
+
* parent, index }), `kind` "document" (its folder report/), "page" (its folder page/, parent "" and
|
|
485
|
+
* index -1: a custom page has no place in the outline) or "link" (its folder link/); one written before
|
|
486
|
+
* kinds came is a document's.
|
|
487
|
+
*/
|
|
337
488
|
export async function listTrash(root) {
|
|
338
489
|
const { trash } = layoutOf(root);
|
|
339
490
|
const names = await fs.readdir(trash).catch(() => []);
|
|
340
491
|
const entries = await Promise.all(names.filter((name) => trashIdPattern.test(name)).map((id) => readJson(path.join(trash, id, "entry.json"))));
|
|
341
|
-
return entries.filter(Boolean).sort((a, b) => b.at - a.at);
|
|
492
|
+
return entries.filter(Boolean).map((entry) => (TRASH_KINDS.includes(entry.kind) ? entry : { ...entry, kind: "document" })).sort((a, b) => b.at - a.at);
|
|
342
493
|
}
|
|
343
494
|
|
|
344
495
|
// ---------- copying an old layout ----------
|
|
@@ -423,8 +574,8 @@ export async function copyOldDocuments({ from, to, state = undefined }) {
|
|
|
423
574
|
if (instructions) {
|
|
424
575
|
if (await pageSlug(layout.root)) page = "kept";
|
|
425
576
|
else {
|
|
426
|
-
await fs.mkdir(layout.
|
|
427
|
-
await copyTree(folder, path.join(layout.
|
|
577
|
+
await fs.mkdir(layout.preferencesPage, { recursive: true });
|
|
578
|
+
await copyTree(folder, path.join(layout.preferencesPage, slug));
|
|
428
579
|
page = "copied";
|
|
429
580
|
}
|
|
430
581
|
continue;
|
|
@@ -514,7 +665,7 @@ export async function adoptOldLayout(root, { devState = null } = {}) {
|
|
|
514
665
|
if ((await copyMissing(path.join(layout.root, ".trash"), layout.trash)).length) copied.push("trash");
|
|
515
666
|
if ((await mergeEmojiLibrary(path.join(layout.root, ".emoji-library"), layout.emojiLibrary)) > 0) copied.push("emoji-library");
|
|
516
667
|
const oldPage = (await documentsIn(layout.root)).find((entry) => entry.instructions);
|
|
517
|
-
if (oldPage && !(await pageSlug(layout.root))) await once("page", oldPage.folder, path.join(layout.
|
|
668
|
+
if (oldPage && !(await pageSlug(layout.root))) await once("page", oldPage.folder, path.join(layout.preferencesPage, oldPage.slug));
|
|
518
669
|
|
|
519
670
|
if (devState && (await isFolder(devState))) {
|
|
520
671
|
const slugs = [...(await listDocumentSlugs(layout.root)), ...(oldPage ? [oldPage.slug] : [])];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { createRequire as __galleryRequire } from "node:module"; import { fileURLToPath as __galleryPath } from "node:url"; const require = __galleryRequire(import.meta.url); const __filename = __galleryPath(import.meta.url); const __dirname = __galleryPath(new URL(".", import.meta.url));
|
|
2
|
+
import{constants as G}from"node:buffer";import E from"node:fs";import{Transform as H}from"node:stream";import{pipeline as P}from"node:stream/promises";import b from"node:zlib";import{refusal as k,said as M}from"../browser/shared/i18n/index.mjs";var A=67324752,Z=33639248,F=101010256,W=101075792,X=117853008,U=4294967295,T=2048;function v(t=new Date){let o=t.getHours()<<11|t.getMinutes()<<5|Math.floor(t.getSeconds()/2),e=Math.max(1980,t.getFullYear())-1980<<9|t.getMonth()+1<<5|t.getDate();return[o,e]}function tt(t){let[o,e]=v(),c=[],h=[],n=0;for(let a of t){let s=Buffer.isBuffer(a.data)?a.data:Buffer.from(a.data??"","utf8"),r=Buffer.from(a.name,"utf8"),u=s.length>64?b.deflateRawSync(s):null,w=u&&u.length<s.length?u:s,L=w===s?0:8,g=b.crc32(s);if(s.length>=U||n>=U)throw new Error("\u538B\u7F29\u5305\u592A\u5927\uFF08\u8D85\u8FC7 4GB\uFF09");let l=Buffer.alloc(30);l.writeUInt32LE(A,0),l.writeUInt16LE(20,4),l.writeUInt16LE(T,6),l.writeUInt16LE(L,8),l.writeUInt16LE(o,10),l.writeUInt16LE(e,12),l.writeUInt32LE(g,14),l.writeUInt32LE(w.length,18),l.writeUInt32LE(s.length,22),l.writeUInt16LE(r.length,26),l.writeUInt16LE(0,28);let d=Buffer.alloc(46);d.writeUInt32LE(Z,0),d.writeUInt16LE(20,4),d.writeUInt16LE(20,6),d.writeUInt16LE(T,8),d.writeUInt16LE(L,10),d.writeUInt16LE(o,12),d.writeUInt16LE(e,14),d.writeUInt32LE(g,16),d.writeUInt32LE(w.length,20),d.writeUInt32LE(s.length,24),d.writeUInt16LE(r.length,28),d.writeUInt32LE(n,42),c.push(l,r,w),h.push(d,r),n+=l.length+r.length+w.length}if(t.length>=65535)throw new Error("\u538B\u7F29\u5305\u91CC\u7684\u6587\u4EF6\u592A\u591A");let i=Buffer.concat(h),f=Buffer.alloc(22);return f.writeUInt32LE(F,0),f.writeUInt16LE(t.length,8),f.writeUInt16LE(t.length,10),f.writeUInt32LE(i.length,12),f.writeUInt32LE(n,16),Buffer.concat([...c,i,f])}var Y=new TextDecoder("utf-8",{fatal:!0}),j=new TextDecoder("gbk");function q(t,o){if(o&T)return t.toString("utf8");try{return Y.decode(t)}catch{return j.decode(t)}}var et=t=>t.length>=4&&t.readUInt32LE(0)===A,m=()=>new Error("ZIP \u6587\u4EF6\u5DF2\u635F\u574F"),I=(t,o)=>Number(t.readBigUInt64LE(o));function N(t,o){let e=Math.min(o,65557),c=t(o-e,e),h=-1;for(let r=c.length-22;r>=0;r-=1)if(c.readUInt32LE(r)===F){h=r;break}if(h<0)throw new Error("\u4E0D\u662F\u6709\u6548\u7684 ZIP \u6587\u4EF6");let n=c.readUInt16LE(h+10),i=c.readUInt32LE(h+12),f=c.readUInt32LE(h+16);if(n===65535||i===U||f===U){let r=t(o-e+h-20,20);if(r.readUInt32LE(0)!==X)throw m();let u=t(I(r,8),56);if(u.readUInt32LE(0)!==W)throw m();n=I(u,32),i=I(u,40),f=I(u,48)}let a=t(f,i),s=[];for(let r=0,u=0;u<n;u+=1){if(a.readUInt32LE(r)!==Z)throw m();let w=a.readUInt16LE(r+8),L=a.readUInt16LE(r+10),g=a.readUInt32LE(r+20),l=a.readUInt32LE(r+24),d=a.readUInt16LE(r+28),D=a.readUInt16LE(r+30),_=a.readUInt16LE(r+32),R=a.readUInt32LE(r+42),B=q(a.subarray(r+46,r+46+d),w),p=a.subarray(r+46+d,r+46+d+D);for(let x=0;x+4<=p.length;x+=4+p.readUInt16LE(x+2)){if(p.readUInt16LE(x)!==1)continue;let z=x+4;l===U&&(l=I(p,z),z+=8),g===U&&(g=I(p,z),z+=8),R===U&&(R=I(p,z))}if(r+=46+d+D+_,!B.endsWith("/")){if(w&1)throw k(M("{0} \u5DF2\u52A0\u5BC6",B));if(L!==0&&L!==8)throw k(M("{0}\uFF1A\u4E0D\u652F\u6301\u7684\u538B\u7F29\u65B9\u5F0F",B));s.push({name:B,method:L,packedSize:g,size:l,local:R})}}return s}var S=t=>k(M("{0}\uFF1A\u5927\u5C0F\u4E0D\u7B26",t.name),{code:"size"});function C(t,o){try{return b.inflateRawSync(t,{maxOutputLength:Math.min(G.MAX_LENGTH,Math.max(1,o.size))})}catch(e){throw e?.code==="ERR_BUFFER_TOO_LARGE"?S(o):e}}function O(t,o){let e=t(o.local,30);if(e.readUInt32LE(0)!==A)throw m();return o.local+30+e.readUInt16LE(26)+e.readUInt16LE(28)}function nt(t){let o=(e,c)=>{if(e<0||e+c>t.length)throw m();return t.subarray(e,e+c)};return N(o,t.length).map(e=>{let c=o(O(o,e),e.packedSize),h=e.method===0?Buffer.from(c):C(c,e);if(h.length!==e.size)throw S(e);return{name:e.name,data:h}})}function rt(t){let o=E.openSync(t,"r"),e=E.fstatSync(o).size,c=(n,i)=>{if(n<0||n+i>e)throw m();let f=Buffer.alloc(i);for(let a=0;a<i;){let s=E.readSync(o,f,a,i-a,n+a);if(s===0)throw m();a+=s}return f},h;try{h=N(c,e)}catch(n){throw E.closeSync(o),n}return{entries:h,read(n){let i=c(O(c,n),n.packedSize),f=n.method===0?i:C(i,n);if(f.length!==n.size)throw S(n);return f},async extract(n,i){let f=O(c,n);if(n.packedSize===0)await E.promises.writeFile(i,"");else{let a=E.createReadStream(t,{start:f,end:f+n.packedSize-1}),s=0,r=new H({transform(u,w,L){s+=u.length,L(s>n.size?S(n):null,u)}});await P(...n.method===0?[a]:[a,b.createInflateRaw()],r,E.createWriteStream(i))}if((await E.promises.stat(i)).size!==n.size)throw S(n)},close:()=>E.closeSync(o)}}export{tt as a,et as b,nt as c,rt as d};
|