├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ └── release.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── esbuild.config.mjs ├── manifest.json ├── package-lock.json ├── package.json ├── screenshot-big.png ├── screenshot.png ├── settings.png ├── src ├── frame.ts ├── main.ts ├── settings-tab.ts ├── settings.ts └── view.ts ├── styles.css ├── test-vault ├── .obsidian │ ├── app.json │ ├── appearance.json │ ├── community-plugins.json │ ├── core-plugins-migration.json │ ├── core-plugins.json │ ├── graph.json │ ├── hotkeys.json │ └── plugins │ │ └── obsidian-custom-frames │ │ ├── .gitignore │ │ └── data.json ├── Untitled.canvas └── note.md ├── tsconfig.json └── versions.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | tab_width = 4 10 | 11 | [{*.yml,*.yaml}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Ellpeck 2 | ko_fi: Ellpeck 3 | patreon: Ellpeck -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: ["*"] 4 | jobs: 5 | release: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Clone Repository 9 | uses: actions/checkout@v4 10 | - name: Setup Node 11 | uses: actions/setup-node@v4 12 | with: 13 | node-version: 18 14 | - name: Install 15 | run: npm i 16 | - name: Build Release 17 | run: npm run build 18 | - name: Grab Changelog from Commit Message Body 19 | run: | 20 | changelog=$(echo -e "$MESSAGE" | sed -n '/^$/,$p' | sed '1d') 21 | echo -e "$changelog" 22 | { 23 | echo 'CHANGELOG<> "$GITHUB_ENV" 27 | env: 28 | MESSAGE: ${{ github.event.head_commit.message }} 29 | - name: Upload Release 30 | uses: softprops/action-gh-release@v2 31 | with: 32 | body: ${{ env.CHANGELOG }} 33 | files: | 34 | main.js 35 | manifest.json 36 | styles.css 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # vscode 2 | .vscode 3 | 4 | # Intellij 5 | *.iml 6 | .idea 7 | 8 | # npm 9 | node_modules 10 | 11 | # Don't include the compiled main.js file in the repo. 12 | # They should be uploaded to GitHub releases instead. 13 | /main.js 14 | 15 | # Exclude sourcemaps 16 | *.map 17 | 18 | # obsidian 19 | workspace 20 | workspace.json 21 | 22 | # Exclude macOS Finder (System Explorer) View States 23 | .DS_Store 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hi, thanks for contributing to Custom Frames! 2 | 3 | Before reporting an issue or suggesting a new feature, please check the [README](README.md)'s [Roadmap](README.md#%EF%B8%8F-roadmap) and [Known Issues](https://github.com/Ellpeck/ObsidianCustomFrames/blob/master/README.md#%EF%B8%8F-known-issues) sections. If your issue or suggestion is already listed there, you don't need to report it here. 4 | 5 | Thanks! ❤️ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ellpeck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Obsidian Custom Frames 2 | An Obsidian plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more. 3 | 4 | ![A screenshot of the plugin in action, where you can see Google Keep attached as a narrow side pane on the right](https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/master/screenshot.png) 5 | 6 | ![A screenshot of the plugin in action, where you can see Google Calendar opened in the center, and the mouse hovering over the corresponding ribbon button](https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/master/screenshot-big.png) 7 | 8 | ![A screenshot of the plugin's settings](https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/master/settings.png) 9 | 10 | ## 🤔 Usage 11 | To use this plugin, simply go into its settings and add a new frame, either from a preset shipped with the plugin, or a custom one that you can edit yourself. 12 | 13 | ### 🪟 Pane Mode 14 | To open a Custom Frame as a pane, you can use the "Custom Frames: Open" command. 15 | 16 | There are also plenty of settings to customize your frame further, including adding custom CSS to the site, adding a ribbon icon, displaying the frame in the center of the editor, and more. 17 | 18 | ### 🗒️ Markdown Mode 19 | You can also display your custom frames in your Markdown documents. Custom Frames adds a special code block syntax that transforms the code block into a custom frame in Live Preview and Reading mode. Your code block should look like this: 20 | ~~~ 21 | ```custom-frames 22 | frame: YOUR FRAME'S NAME 23 | ``` 24 | ~~~ 25 | 26 | Optionally, you can also pass custom style settings to the embed, which allows you to change things like the embed's height, as well as an additional suffix that will be appended to the frame's regular URL, which can be useful for things like displaying a specific note in Google Keep. 27 | 28 | Here's an example using the [Google Keep preset](#-presets): 29 | ~~~ 30 | ```custom-frames 31 | frame: Google Keep 32 | style: height: 1000px; 33 | urlSuffix: #reminders 34 | ``` 35 | ~~~ 36 | 37 | ### 📱 On Obsidian Mobile 38 | Unfortunately, Obsidian Mobile does not run on [Electron](https://www.electronjs.org/), which is what allows iframes and [webviews](https://www.electronjs.org/docs/latest/api/webview-tag) to be displayed with very few restrictions related to cookies, cross-origin resource sharing, and so on. This means that a lot of sites won't work there, especially ones that you have to log in to. However, when you create a frame, you can toggle the "Disable on Mobile" option to hide a Desktop-only frame in Obsidian mobile. 39 | 40 | Need help using the plugin? Feel free to join the Discord server! 41 | 42 | [![Join the Discord server](https://ellpeck.de/res/discord-wide.png)](https://link.ellpeck.de/discordweb) 43 | 44 | ## 📦 Presets 45 | By default, Custom Frames comes with a few presets that allow you to get new panes for popular sites up and running quickly. 46 | - [Obsidian Forum](https://forum.obsidian.md/) 47 | - [Google Keep](https://keep.google.com), optimized for a narrow pane on the side 48 | - [Google Calendar](https://calendar.google.com/calendar/u/0/r/day), optimized by removing some buttons. Close side panel with top-left button. 49 | - [Todoist](https://todoist.com), optimized for a narrow (half-height) side panel by removing some buttons and slimming margins. 50 | - [Notion](https://www.notion.so/) (it's recommended to close Notion's sidebar if used as a side pane) 51 | - [Twitter](https://twitter.com) 52 | - [Readwise Daily Review](https://readwise.io/dailyreview) 53 | 54 | If you create a frame that you think other people would like, don't hesitate to create a pull request with [a new preset](https://github.com/Ellpeck/ObsidianCustomFrames/blob/master/src/settings.ts#L5). 55 | 56 | ## 🛣️ Roadmap 57 | - Allow creating links outside of Obsidian that open in a custom frame 58 | - Add more options to Markdown mode, like allowing for back and forward buttons 59 | - Possibly allow extracting selected text into a note similar to how the Note composer plugin works, and potentially allow using a note template that includes the link to the site extracted from 60 | - ~~Allow setting a custom icon for each pane~~ 61 | - ~~Allow displaying custom frames in Markdown code blocks~~ 62 | - ~~Add the ability to add a ribbon button for a frame that opens it in the main view~~ 63 | - ~~Possibly allow executing custom JavaScript in iframes (though security implications still need to be explored)~~ 64 | - ~~Add a global setting that causes popups to be opened in a new Obsidian window rather than the default browser~~ (See the [web viewer core plugin](https://help.obsidian.md/plugins/web-viewer)) 65 | 66 | ## ⚠️ Known Issues 67 | There are a few known issues with Custom Frames. If you encounter any of these, please **don't** report it on the issue tracker. 68 | - Popups and new tabs are opened in the default browser rather than the custom frame by default, which can cause issues logging in to websites that use external logins. To circumvent this issue, enable the [web viewer core plugin](https://help.obsidian.md/plugins/web-viewer), which shares its session information with Custom Frames, to open popups within Obsidian. 69 | - Some links refuse to open from within custom frames, especially before Obsidian 1.3.7. You can find more info in [this issue](https://github.com/Ellpeck/ObsidianCustomFrames/issues/76). 70 | 71 | ## 🙏 Acknowledgements 72 | Thanks to [lishid](https://github.com/lishid) for their help with making iframes work in Obsidian for a purpose like this. Also thanks to them for *motivating* me to turn Obsidian Keep into a more versatile plugin, which is how Custom Frames was born. 73 | 74 | If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image! 75 | 76 | [![Support me (if you want), via Patreon, Ko-fi or GitHub Sponsors](https://ellpeck.de/res/generalsupport-wide.png)](https://ellpeck.de/support) 77 | -------------------------------------------------------------------------------- /esbuild.config.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild"; 2 | import process from "process"; 3 | import builtins from 'builtin-modules'; 4 | import {copy} from 'esbuild-plugin-copy'; 5 | 6 | const banner = `/* 7 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 8 | if you want to view the source, please visit the github repository of this plugin 9 | */`; 10 | 11 | const prod = (process.argv[2] === 'production'); 12 | 13 | esbuild.build({ 14 | banner: { 15 | js: banner, 16 | }, 17 | entryPoints: ['src/main.ts'], 18 | bundle: true, 19 | external: [ 20 | 'obsidian', 21 | 'electron', 22 | '@codemirror/autocomplete', 23 | '@codemirror/closebrackets', 24 | '@codemirror/collab', 25 | '@codemirror/commands', 26 | '@codemirror/comment', 27 | '@codemirror/fold', 28 | '@codemirror/gutter', 29 | '@codemirror/highlight', 30 | '@codemirror/history', 31 | '@codemirror/language', 32 | '@codemirror/lint', 33 | '@codemirror/matchbrackets', 34 | '@codemirror/panel', 35 | '@codemirror/rangeset', 36 | '@codemirror/rectangular-selection', 37 | '@codemirror/search', 38 | '@codemirror/state', 39 | '@codemirror/stream-parser', 40 | '@codemirror/text', 41 | '@codemirror/tooltip', 42 | '@codemirror/view', 43 | ...builtins 44 | ], 45 | plugins: [ 46 | copy({ 47 | assets: [{ 48 | from: ["./manifest.json", "./main.js", "./styles.css"], 49 | to: ["./test-vault/.obsidian/plugins/obsidian-custom-frames/."] 50 | }] 51 | }), 52 | ], 53 | format: 'cjs', 54 | watch: !prod, 55 | target: 'es2016', 56 | logLevel: "info", 57 | sourcemap: prod ? false : 'inline', 58 | treeShaking: true, 59 | outfile: 'main.js', 60 | }).catch(() => process.exit(1)); 61 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-custom-frames", 3 | "name": "Custom Frames", 4 | "version": "2.5.0", 5 | "minAppVersion": "1.2.0", 6 | "description": "A plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.", 7 | "author": "Ellpeck", 8 | "authorUrl": "https://ellpeck.de", 9 | "fundingUrl": "https://ellpeck.de/support", 10 | "isDesktopOnly": false 11 | } 12 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-custom-frames", 3 | "version": "2.4.7", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "obsidian-custom-frames", 9 | "version": "2.4.7", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@types/node": "^16.11.6", 13 | "builtin-modules": "^3.2.0", 14 | "electron": "^20.3.9", 15 | "esbuild": "0.14.0", 16 | "esbuild-plugin-copy": "^1.3.0", 17 | "obsidian": "latest", 18 | "tslib": "2.3.1", 19 | "typescript": "4.4.4" 20 | } 21 | }, 22 | "node_modules/@codemirror/state": { 23 | "version": "6.2.0", 24 | "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz", 25 | "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==", 26 | "dev": true, 27 | "peer": true 28 | }, 29 | "node_modules/@codemirror/view": { 30 | "version": "6.7.3", 31 | "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.7.3.tgz", 32 | "integrity": "sha512-Lt+4POnhXrZFfHOdPzXEHxrzwdy7cjqYlMkOWvoFGi6/bAsjzlFfr0NY3B15B/PGx+cDFgM1hlc12wvYeZbGLw==", 33 | "dev": true, 34 | "peer": true, 35 | "dependencies": { 36 | "@codemirror/state": "^6.1.4", 37 | "style-mod": "^4.0.0", 38 | "w3c-keyname": "^2.2.4" 39 | } 40 | }, 41 | "node_modules/@electron/get": { 42 | "version": "1.14.1", 43 | "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.14.1.tgz", 44 | "integrity": "sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==", 45 | "dev": true, 46 | "dependencies": { 47 | "debug": "^4.1.1", 48 | "env-paths": "^2.2.0", 49 | "fs-extra": "^8.1.0", 50 | "got": "^9.6.0", 51 | "progress": "^2.0.3", 52 | "semver": "^6.2.0", 53 | "sumchecker": "^3.0.1" 54 | }, 55 | "engines": { 56 | "node": ">=8.6" 57 | }, 58 | "optionalDependencies": { 59 | "global-agent": "^3.0.0", 60 | "global-tunnel-ng": "^2.7.1" 61 | } 62 | }, 63 | "node_modules/@nodelib/fs.scandir": { 64 | "version": "2.1.5", 65 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 66 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 67 | "dev": true, 68 | "dependencies": { 69 | "@nodelib/fs.stat": "2.0.5", 70 | "run-parallel": "^1.1.9" 71 | }, 72 | "engines": { 73 | "node": ">= 8" 74 | } 75 | }, 76 | "node_modules/@nodelib/fs.stat": { 77 | "version": "2.0.5", 78 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 79 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 80 | "dev": true, 81 | "engines": { 82 | "node": ">= 8" 83 | } 84 | }, 85 | "node_modules/@nodelib/fs.walk": { 86 | "version": "1.2.8", 87 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 88 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 89 | "dev": true, 90 | "dependencies": { 91 | "@nodelib/fs.scandir": "2.1.5", 92 | "fastq": "^1.6.0" 93 | }, 94 | "engines": { 95 | "node": ">= 8" 96 | } 97 | }, 98 | "node_modules/@sindresorhus/is": { 99 | "version": "0.14.0", 100 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", 101 | "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", 102 | "dev": true, 103 | "engines": { 104 | "node": ">=6" 105 | } 106 | }, 107 | "node_modules/@szmarczak/http-timer": { 108 | "version": "1.1.2", 109 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", 110 | "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", 111 | "dev": true, 112 | "dependencies": { 113 | "defer-to-connect": "^1.0.1" 114 | }, 115 | "engines": { 116 | "node": ">=6" 117 | } 118 | }, 119 | "node_modules/@types/codemirror": { 120 | "version": "0.0.108", 121 | "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", 122 | "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==", 123 | "dev": true, 124 | "dependencies": { 125 | "@types/tern": "*" 126 | } 127 | }, 128 | "node_modules/@types/estree": { 129 | "version": "1.0.0", 130 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", 131 | "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", 132 | "dev": true 133 | }, 134 | "node_modules/@types/node": { 135 | "version": "16.18.11", 136 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", 137 | "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", 138 | "dev": true 139 | }, 140 | "node_modules/@types/tern": { 141 | "version": "0.23.4", 142 | "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", 143 | "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", 144 | "dev": true, 145 | "dependencies": { 146 | "@types/estree": "*" 147 | } 148 | }, 149 | "node_modules/@types/yauzl": { 150 | "version": "2.10.0", 151 | "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", 152 | "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", 153 | "dev": true, 154 | "optional": true, 155 | "dependencies": { 156 | "@types/node": "*" 157 | } 158 | }, 159 | "node_modules/ansi-styles": { 160 | "version": "4.3.0", 161 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 162 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 163 | "dev": true, 164 | "dependencies": { 165 | "color-convert": "^2.0.1" 166 | }, 167 | "engines": { 168 | "node": ">=8" 169 | }, 170 | "funding": { 171 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 172 | } 173 | }, 174 | "node_modules/array-union": { 175 | "version": "2.1.0", 176 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 177 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 178 | "dev": true, 179 | "engines": { 180 | "node": ">=8" 181 | } 182 | }, 183 | "node_modules/boolean": { 184 | "version": "3.2.0", 185 | "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", 186 | "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", 187 | "dev": true, 188 | "optional": true 189 | }, 190 | "node_modules/braces": { 191 | "version": "3.0.2", 192 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 193 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 194 | "dev": true, 195 | "dependencies": { 196 | "fill-range": "^7.0.1" 197 | }, 198 | "engines": { 199 | "node": ">=8" 200 | } 201 | }, 202 | "node_modules/buffer-crc32": { 203 | "version": "0.2.13", 204 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 205 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 206 | "dev": true, 207 | "engines": { 208 | "node": "*" 209 | } 210 | }, 211 | "node_modules/builtin-modules": { 212 | "version": "3.3.0", 213 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", 214 | "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", 215 | "dev": true, 216 | "engines": { 217 | "node": ">=6" 218 | }, 219 | "funding": { 220 | "url": "https://github.com/sponsors/sindresorhus" 221 | } 222 | }, 223 | "node_modules/cacheable-request": { 224 | "version": "6.1.0", 225 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", 226 | "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", 227 | "dev": true, 228 | "dependencies": { 229 | "clone-response": "^1.0.2", 230 | "get-stream": "^5.1.0", 231 | "http-cache-semantics": "^4.0.0", 232 | "keyv": "^3.0.0", 233 | "lowercase-keys": "^2.0.0", 234 | "normalize-url": "^4.1.0", 235 | "responselike": "^1.0.2" 236 | }, 237 | "engines": { 238 | "node": ">=8" 239 | } 240 | }, 241 | "node_modules/cacheable-request/node_modules/get-stream": { 242 | "version": "5.2.0", 243 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 244 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 245 | "dev": true, 246 | "dependencies": { 247 | "pump": "^3.0.0" 248 | }, 249 | "engines": { 250 | "node": ">=8" 251 | }, 252 | "funding": { 253 | "url": "https://github.com/sponsors/sindresorhus" 254 | } 255 | }, 256 | "node_modules/cacheable-request/node_modules/lowercase-keys": { 257 | "version": "2.0.0", 258 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", 259 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", 260 | "dev": true, 261 | "engines": { 262 | "node": ">=8" 263 | } 264 | }, 265 | "node_modules/chalk": { 266 | "version": "4.1.2", 267 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 268 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 269 | "dev": true, 270 | "dependencies": { 271 | "ansi-styles": "^4.1.0", 272 | "supports-color": "^7.1.0" 273 | }, 274 | "engines": { 275 | "node": ">=10" 276 | }, 277 | "funding": { 278 | "url": "https://github.com/chalk/chalk?sponsor=1" 279 | } 280 | }, 281 | "node_modules/clone-response": { 282 | "version": "1.0.3", 283 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", 284 | "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", 285 | "dev": true, 286 | "dependencies": { 287 | "mimic-response": "^1.0.0" 288 | }, 289 | "funding": { 290 | "url": "https://github.com/sponsors/sindresorhus" 291 | } 292 | }, 293 | "node_modules/color-convert": { 294 | "version": "2.0.1", 295 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 296 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 297 | "dev": true, 298 | "dependencies": { 299 | "color-name": "~1.1.4" 300 | }, 301 | "engines": { 302 | "node": ">=7.0.0" 303 | } 304 | }, 305 | "node_modules/color-name": { 306 | "version": "1.1.4", 307 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 308 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 309 | "dev": true 310 | }, 311 | "node_modules/config-chain": { 312 | "version": "1.1.13", 313 | "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", 314 | "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", 315 | "dev": true, 316 | "optional": true, 317 | "dependencies": { 318 | "ini": "^1.3.4", 319 | "proto-list": "~1.2.1" 320 | } 321 | }, 322 | "node_modules/debug": { 323 | "version": "4.3.4", 324 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 325 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 326 | "dev": true, 327 | "dependencies": { 328 | "ms": "2.1.2" 329 | }, 330 | "engines": { 331 | "node": ">=6.0" 332 | }, 333 | "peerDependenciesMeta": { 334 | "supports-color": { 335 | "optional": true 336 | } 337 | } 338 | }, 339 | "node_modules/decompress-response": { 340 | "version": "3.3.0", 341 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", 342 | "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", 343 | "dev": true, 344 | "dependencies": { 345 | "mimic-response": "^1.0.0" 346 | }, 347 | "engines": { 348 | "node": ">=4" 349 | } 350 | }, 351 | "node_modules/defer-to-connect": { 352 | "version": "1.1.3", 353 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", 354 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", 355 | "dev": true 356 | }, 357 | "node_modules/define-properties": { 358 | "version": "1.1.4", 359 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", 360 | "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", 361 | "dev": true, 362 | "optional": true, 363 | "dependencies": { 364 | "has-property-descriptors": "^1.0.0", 365 | "object-keys": "^1.1.1" 366 | }, 367 | "engines": { 368 | "node": ">= 0.4" 369 | }, 370 | "funding": { 371 | "url": "https://github.com/sponsors/ljharb" 372 | } 373 | }, 374 | "node_modules/detect-node": { 375 | "version": "2.1.0", 376 | "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", 377 | "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", 378 | "dev": true, 379 | "optional": true 380 | }, 381 | "node_modules/dir-glob": { 382 | "version": "3.0.1", 383 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 384 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 385 | "dev": true, 386 | "dependencies": { 387 | "path-type": "^4.0.0" 388 | }, 389 | "engines": { 390 | "node": ">=8" 391 | } 392 | }, 393 | "node_modules/duplexer3": { 394 | "version": "0.1.5", 395 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", 396 | "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", 397 | "dev": true 398 | }, 399 | "node_modules/electron": { 400 | "version": "20.3.12", 401 | "resolved": "https://registry.npmjs.org/electron/-/electron-20.3.12.tgz", 402 | "integrity": "sha512-CuCZKhwdSXaUNIoEuPVZ25YH18zmox3wEM8Acwcy9tlpD8Jiuq3ji3RZ98eVWJalrpqbdE9LtTD/sLC86GIkLg==", 403 | "dev": true, 404 | "hasInstallScript": true, 405 | "dependencies": { 406 | "@electron/get": "^1.14.1", 407 | "@types/node": "^16.11.26", 408 | "extract-zip": "^2.0.1" 409 | }, 410 | "bin": { 411 | "electron": "cli.js" 412 | }, 413 | "engines": { 414 | "node": ">= 10.17.0" 415 | } 416 | }, 417 | "node_modules/encodeurl": { 418 | "version": "1.0.2", 419 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 420 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 421 | "dev": true, 422 | "optional": true, 423 | "engines": { 424 | "node": ">= 0.8" 425 | } 426 | }, 427 | "node_modules/end-of-stream": { 428 | "version": "1.4.4", 429 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 430 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 431 | "dev": true, 432 | "dependencies": { 433 | "once": "^1.4.0" 434 | } 435 | }, 436 | "node_modules/env-paths": { 437 | "version": "2.2.1", 438 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", 439 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", 440 | "dev": true, 441 | "engines": { 442 | "node": ">=6" 443 | } 444 | }, 445 | "node_modules/es6-error": { 446 | "version": "4.1.1", 447 | "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", 448 | "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", 449 | "dev": true, 450 | "optional": true 451 | }, 452 | "node_modules/esbuild": { 453 | "version": "0.14.0", 454 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.0.tgz", 455 | "integrity": "sha512-UOnSKRAyZondxdLrOXnI/mesUmU/GvDTcajCvxoIaObzMeQcn0HyoGtvbfATnazlx799ZqFSyIZGLXFszkjy3A==", 456 | "dev": true, 457 | "hasInstallScript": true, 458 | "bin": { 459 | "esbuild": "bin/esbuild" 460 | }, 461 | "optionalDependencies": { 462 | "esbuild-android-arm64": "0.14.0", 463 | "esbuild-darwin-64": "0.14.0", 464 | "esbuild-darwin-arm64": "0.14.0", 465 | "esbuild-freebsd-64": "0.14.0", 466 | "esbuild-freebsd-arm64": "0.14.0", 467 | "esbuild-linux-32": "0.14.0", 468 | "esbuild-linux-64": "0.14.0", 469 | "esbuild-linux-arm": "0.14.0", 470 | "esbuild-linux-arm64": "0.14.0", 471 | "esbuild-linux-mips64le": "0.14.0", 472 | "esbuild-linux-ppc64le": "0.14.0", 473 | "esbuild-netbsd-64": "0.14.0", 474 | "esbuild-openbsd-64": "0.14.0", 475 | "esbuild-sunos-64": "0.14.0", 476 | "esbuild-windows-32": "0.14.0", 477 | "esbuild-windows-64": "0.14.0", 478 | "esbuild-windows-arm64": "0.14.0" 479 | } 480 | }, 481 | "node_modules/esbuild-android-arm64": { 482 | "version": "0.14.0", 483 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.0.tgz", 484 | "integrity": "sha512-X7BjFiRRNfxPNg1aT5zw4xK1vbvX2IvDPcEp4bv0CEXgR39UzuOMUsQoG92aZgj8JGs8jxQAZc8k9dVJ1WL2BA==", 485 | "cpu": [ 486 | "arm64" 487 | ], 488 | "dev": true, 489 | "optional": true, 490 | "os": [ 491 | "android" 492 | ] 493 | }, 494 | "node_modules/esbuild-darwin-64": { 495 | "version": "0.14.0", 496 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.0.tgz", 497 | "integrity": "sha512-43vtt407jMp1kEXiaY0dEIGjOREax9F1+qMI0+F9tJyr06EHAofnbLL6cTmLgdPy/pMhltSvOJ8EddJrrOBgpQ==", 498 | "cpu": [ 499 | "x64" 500 | ], 501 | "dev": true, 502 | "optional": true, 503 | "os": [ 504 | "darwin" 505 | ] 506 | }, 507 | "node_modules/esbuild-darwin-arm64": { 508 | "version": "0.14.0", 509 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.0.tgz", 510 | "integrity": "sha512-hMbT5YiBrFL763mnwR9BqNtq9XtJgJRxYs7Ad++KUd+ZhMoVE0Rs/YLe1oor9uBGhHLqQsZuJ2dUHjCsfT/iDg==", 511 | "cpu": [ 512 | "arm64" 513 | ], 514 | "dev": true, 515 | "optional": true, 516 | "os": [ 517 | "darwin" 518 | ] 519 | }, 520 | "node_modules/esbuild-freebsd-64": { 521 | "version": "0.14.0", 522 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.0.tgz", 523 | "integrity": "sha512-mx68HRYIZo6ZiHbWk5Md+mDJoDw779yWkJQAaBnXwOkGbDeA3JmPZjp6IPfy2P+n3emK9z6g4pKiebp1tQGVoQ==", 524 | "cpu": [ 525 | "x64" 526 | ], 527 | "dev": true, 528 | "optional": true, 529 | "os": [ 530 | "freebsd" 531 | ] 532 | }, 533 | "node_modules/esbuild-freebsd-arm64": { 534 | "version": "0.14.0", 535 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.0.tgz", 536 | "integrity": "sha512-iM8u+zTagh0WGn2FTTxi7DII/ycVzYyuf2Df6eP2ZX+vlx2FjaduhagRkpyhjfmEyhfJOrYSAR5R1biNPcA+VA==", 537 | "cpu": [ 538 | "arm64" 539 | ], 540 | "dev": true, 541 | "optional": true, 542 | "os": [ 543 | "freebsd" 544 | ] 545 | }, 546 | "node_modules/esbuild-linux-32": { 547 | "version": "0.14.0", 548 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.0.tgz", 549 | "integrity": "sha512-dWHotI2qlXWZyza7n85UubBj0asjpM7FTtQYDaRQKxoCJpCnSzq3aD55IJthiggZHXj2tAML9Bc5xjVLsBJR0w==", 550 | "cpu": [ 551 | "ia32" 552 | ], 553 | "dev": true, 554 | "optional": true, 555 | "os": [ 556 | "linux" 557 | ] 558 | }, 559 | "node_modules/esbuild-linux-64": { 560 | "version": "0.14.0", 561 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.0.tgz", 562 | "integrity": "sha512-7buo31kp1/yKWPm9vU44FEUwkeIROrIgnCDV9KLMLSbOjGEHBZXYJ2L0p4ZnB7Z+m5YiW7F/AfJu0/1E87nOeQ==", 563 | "cpu": [ 564 | "x64" 565 | ], 566 | "dev": true, 567 | "optional": true, 568 | "os": [ 569 | "linux" 570 | ] 571 | }, 572 | "node_modules/esbuild-linux-arm": { 573 | "version": "0.14.0", 574 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.0.tgz", 575 | "integrity": "sha512-fgybXQwPRT4Io01+aD+yphcLOLRVGqbSdhvaDK3qBwqUvspFsq4QkI7PeeYpuQdBZWiRKLoi9v5r90l7JO/s+g==", 576 | "cpu": [ 577 | "arm" 578 | ], 579 | "dev": true, 580 | "optional": true, 581 | "os": [ 582 | "linux" 583 | ] 584 | }, 585 | "node_modules/esbuild-linux-arm64": { 586 | "version": "0.14.0", 587 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.0.tgz", 588 | "integrity": "sha512-9LBtCH2RkhDBwoAYksTtXljN6hlxxoL6a3ymNfXJG9JxFUQddOfhajXZdObFn/hgGkAFwx8dXqw+FnPm0FCzSg==", 589 | "cpu": [ 590 | "arm64" 591 | ], 592 | "dev": true, 593 | "optional": true, 594 | "os": [ 595 | "linux" 596 | ] 597 | }, 598 | "node_modules/esbuild-linux-mips64le": { 599 | "version": "0.14.0", 600 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.0.tgz", 601 | "integrity": "sha512-Xz7soOqWeCWcLp15biPM08To+s0k1E/2q0pQZNQ+SY9S5H2vU4ujDXqKjxFc24G9CrOeUNEOXTkh+JldBGbTCA==", 602 | "cpu": [ 603 | "mips64el" 604 | ], 605 | "dev": true, 606 | "optional": true, 607 | "os": [ 608 | "linux" 609 | ] 610 | }, 611 | "node_modules/esbuild-linux-ppc64le": { 612 | "version": "0.14.0", 613 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.0.tgz", 614 | "integrity": "sha512-fuBXTyUaZKxpmp43Nf0M1uI1OmZv/COcME9PG7NQ/EniwC680Xj5xQFhEBDVnvQQ+6xOnXdfPSojJq7gQxrORQ==", 615 | "cpu": [ 616 | "ppc64" 617 | ], 618 | "dev": true, 619 | "optional": true, 620 | "os": [ 621 | "linux" 622 | ] 623 | }, 624 | "node_modules/esbuild-netbsd-64": { 625 | "version": "0.14.0", 626 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.0.tgz", 627 | "integrity": "sha512-pQaECTKr/iCXtn1qjwih+cvoZzbZ+P3NwLQo4uo/IesklbPTR5eF4d85L1vPFVgff+itBMxbbB7aoRznSglN3A==", 628 | "cpu": [ 629 | "x64" 630 | ], 631 | "dev": true, 632 | "optional": true, 633 | "os": [ 634 | "netbsd" 635 | ] 636 | }, 637 | "node_modules/esbuild-openbsd-64": { 638 | "version": "0.14.0", 639 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.0.tgz", 640 | "integrity": "sha512-HiaqQX9HMb9u3eYvKZ86+m/paQwASJSIjXiRTFpFusypjtU2NJqWb/LiRvhfmwC6rb7YHwCSPx+juSM7M+20bA==", 641 | "cpu": [ 642 | "x64" 643 | ], 644 | "dev": true, 645 | "optional": true, 646 | "os": [ 647 | "openbsd" 648 | ] 649 | }, 650 | "node_modules/esbuild-plugin-copy": { 651 | "version": "1.6.0", 652 | "resolved": "https://registry.npmjs.org/esbuild-plugin-copy/-/esbuild-plugin-copy-1.6.0.tgz", 653 | "integrity": "sha512-wN1paBCoE0yRBl9ZY3ZSD6SxGE4Yfr0Em7zh2yTbJv1JaHEIR3FYYN7HU6F+j/peSaGZJNSORSGxJ5QX1a1Sgg==", 654 | "dev": true, 655 | "dependencies": { 656 | "chalk": "^4.1.2", 657 | "fs-extra": "^10.0.1", 658 | "globby": "^11.0.3" 659 | }, 660 | "peerDependencies": { 661 | "esbuild": ">= 0.14.0" 662 | } 663 | }, 664 | "node_modules/esbuild-plugin-copy/node_modules/fs-extra": { 665 | "version": "10.1.0", 666 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 667 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 668 | "dev": true, 669 | "dependencies": { 670 | "graceful-fs": "^4.2.0", 671 | "jsonfile": "^6.0.1", 672 | "universalify": "^2.0.0" 673 | }, 674 | "engines": { 675 | "node": ">=12" 676 | } 677 | }, 678 | "node_modules/esbuild-plugin-copy/node_modules/jsonfile": { 679 | "version": "6.1.0", 680 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 681 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 682 | "dev": true, 683 | "dependencies": { 684 | "universalify": "^2.0.0" 685 | }, 686 | "optionalDependencies": { 687 | "graceful-fs": "^4.1.6" 688 | } 689 | }, 690 | "node_modules/esbuild-plugin-copy/node_modules/universalify": { 691 | "version": "2.0.0", 692 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 693 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", 694 | "dev": true, 695 | "engines": { 696 | "node": ">= 10.0.0" 697 | } 698 | }, 699 | "node_modules/esbuild-sunos-64": { 700 | "version": "0.14.0", 701 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.0.tgz", 702 | "integrity": "sha512-TkMQOSiSU3fHLV3M+OKUgLZt5L7TpcBcMRvtFw1cTxAnX8eT+1qkWVLiDM8ow1C3P7PW3bkGY3LW8vOs8o/jBA==", 703 | "cpu": [ 704 | "x64" 705 | ], 706 | "dev": true, 707 | "optional": true, 708 | "os": [ 709 | "sunos" 710 | ] 711 | }, 712 | "node_modules/esbuild-windows-32": { 713 | "version": "0.14.0", 714 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.0.tgz", 715 | "integrity": "sha512-0h7E50JHgyLd7TkqSIH0VzBhngWspxPHuq/crDAMnh4s4tW8zWCMLIz2c1HVwHfZsh7d5+C4/yBaQeJTHXGvIA==", 716 | "cpu": [ 717 | "ia32" 718 | ], 719 | "dev": true, 720 | "optional": true, 721 | "os": [ 722 | "win32" 723 | ] 724 | }, 725 | "node_modules/esbuild-windows-64": { 726 | "version": "0.14.0", 727 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.0.tgz", 728 | "integrity": "sha512-RxnovPOoQS5Id4mbdIUm96L0GIg+ZME4FthbErw1kZZabLi9eLp1gR3vSwkZXKbK8Z76uDkSW0EN74i1XWVpiQ==", 729 | "cpu": [ 730 | "x64" 731 | ], 732 | "dev": true, 733 | "optional": true, 734 | "os": [ 735 | "win32" 736 | ] 737 | }, 738 | "node_modules/esbuild-windows-arm64": { 739 | "version": "0.14.0", 740 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.0.tgz", 741 | "integrity": "sha512-66KsVlT6lGDWgDKQsAlojxgUhZkkjVeosMVRdb913OwtcOjszceg6zFD748jzp9CUgAseHCNJqFmYOyBzneSEQ==", 742 | "cpu": [ 743 | "arm64" 744 | ], 745 | "dev": true, 746 | "optional": true, 747 | "os": [ 748 | "win32" 749 | ] 750 | }, 751 | "node_modules/escape-string-regexp": { 752 | "version": "4.0.0", 753 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 754 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 755 | "dev": true, 756 | "optional": true, 757 | "engines": { 758 | "node": ">=10" 759 | }, 760 | "funding": { 761 | "url": "https://github.com/sponsors/sindresorhus" 762 | } 763 | }, 764 | "node_modules/extract-zip": { 765 | "version": "2.0.1", 766 | "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", 767 | "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", 768 | "dev": true, 769 | "dependencies": { 770 | "debug": "^4.1.1", 771 | "get-stream": "^5.1.0", 772 | "yauzl": "^2.10.0" 773 | }, 774 | "bin": { 775 | "extract-zip": "cli.js" 776 | }, 777 | "engines": { 778 | "node": ">= 10.17.0" 779 | }, 780 | "optionalDependencies": { 781 | "@types/yauzl": "^2.9.1" 782 | } 783 | }, 784 | "node_modules/extract-zip/node_modules/get-stream": { 785 | "version": "5.2.0", 786 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 787 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 788 | "dev": true, 789 | "dependencies": { 790 | "pump": "^3.0.0" 791 | }, 792 | "engines": { 793 | "node": ">=8" 794 | }, 795 | "funding": { 796 | "url": "https://github.com/sponsors/sindresorhus" 797 | } 798 | }, 799 | "node_modules/fast-glob": { 800 | "version": "3.2.12", 801 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", 802 | "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", 803 | "dev": true, 804 | "dependencies": { 805 | "@nodelib/fs.stat": "^2.0.2", 806 | "@nodelib/fs.walk": "^1.2.3", 807 | "glob-parent": "^5.1.2", 808 | "merge2": "^1.3.0", 809 | "micromatch": "^4.0.4" 810 | }, 811 | "engines": { 812 | "node": ">=8.6.0" 813 | } 814 | }, 815 | "node_modules/fastq": { 816 | "version": "1.15.0", 817 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 818 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 819 | "dev": true, 820 | "dependencies": { 821 | "reusify": "^1.0.4" 822 | } 823 | }, 824 | "node_modules/fd-slicer": { 825 | "version": "1.1.0", 826 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", 827 | "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", 828 | "dev": true, 829 | "dependencies": { 830 | "pend": "~1.2.0" 831 | } 832 | }, 833 | "node_modules/fill-range": { 834 | "version": "7.0.1", 835 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 836 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 837 | "dev": true, 838 | "dependencies": { 839 | "to-regex-range": "^5.0.1" 840 | }, 841 | "engines": { 842 | "node": ">=8" 843 | } 844 | }, 845 | "node_modules/fs-extra": { 846 | "version": "8.1.0", 847 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 848 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 849 | "dev": true, 850 | "dependencies": { 851 | "graceful-fs": "^4.2.0", 852 | "jsonfile": "^4.0.0", 853 | "universalify": "^0.1.0" 854 | }, 855 | "engines": { 856 | "node": ">=6 <7 || >=8" 857 | } 858 | }, 859 | "node_modules/function-bind": { 860 | "version": "1.1.1", 861 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 862 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 863 | "dev": true, 864 | "optional": true 865 | }, 866 | "node_modules/get-intrinsic": { 867 | "version": "1.2.0", 868 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", 869 | "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", 870 | "dev": true, 871 | "optional": true, 872 | "dependencies": { 873 | "function-bind": "^1.1.1", 874 | "has": "^1.0.3", 875 | "has-symbols": "^1.0.3" 876 | }, 877 | "funding": { 878 | "url": "https://github.com/sponsors/ljharb" 879 | } 880 | }, 881 | "node_modules/get-stream": { 882 | "version": "4.1.0", 883 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 884 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 885 | "dev": true, 886 | "dependencies": { 887 | "pump": "^3.0.0" 888 | }, 889 | "engines": { 890 | "node": ">=6" 891 | } 892 | }, 893 | "node_modules/glob-parent": { 894 | "version": "5.1.2", 895 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 896 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 897 | "dev": true, 898 | "dependencies": { 899 | "is-glob": "^4.0.1" 900 | }, 901 | "engines": { 902 | "node": ">= 6" 903 | } 904 | }, 905 | "node_modules/global-agent": { 906 | "version": "3.0.0", 907 | "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", 908 | "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", 909 | "dev": true, 910 | "optional": true, 911 | "dependencies": { 912 | "boolean": "^3.0.1", 913 | "es6-error": "^4.1.1", 914 | "matcher": "^3.0.0", 915 | "roarr": "^2.15.3", 916 | "semver": "^7.3.2", 917 | "serialize-error": "^7.0.1" 918 | }, 919 | "engines": { 920 | "node": ">=10.0" 921 | } 922 | }, 923 | "node_modules/global-agent/node_modules/semver": { 924 | "version": "7.3.8", 925 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", 926 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", 927 | "dev": true, 928 | "optional": true, 929 | "dependencies": { 930 | "lru-cache": "^6.0.0" 931 | }, 932 | "bin": { 933 | "semver": "bin/semver.js" 934 | }, 935 | "engines": { 936 | "node": ">=10" 937 | } 938 | }, 939 | "node_modules/global-tunnel-ng": { 940 | "version": "2.7.1", 941 | "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", 942 | "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", 943 | "dev": true, 944 | "optional": true, 945 | "dependencies": { 946 | "encodeurl": "^1.0.2", 947 | "lodash": "^4.17.10", 948 | "npm-conf": "^1.1.3", 949 | "tunnel": "^0.0.6" 950 | }, 951 | "engines": { 952 | "node": ">=0.10" 953 | } 954 | }, 955 | "node_modules/globalthis": { 956 | "version": "1.0.3", 957 | "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", 958 | "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", 959 | "dev": true, 960 | "optional": true, 961 | "dependencies": { 962 | "define-properties": "^1.1.3" 963 | }, 964 | "engines": { 965 | "node": ">= 0.4" 966 | }, 967 | "funding": { 968 | "url": "https://github.com/sponsors/ljharb" 969 | } 970 | }, 971 | "node_modules/globby": { 972 | "version": "11.1.0", 973 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", 974 | "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", 975 | "dev": true, 976 | "dependencies": { 977 | "array-union": "^2.1.0", 978 | "dir-glob": "^3.0.1", 979 | "fast-glob": "^3.2.9", 980 | "ignore": "^5.2.0", 981 | "merge2": "^1.4.1", 982 | "slash": "^3.0.0" 983 | }, 984 | "engines": { 985 | "node": ">=10" 986 | }, 987 | "funding": { 988 | "url": "https://github.com/sponsors/sindresorhus" 989 | } 990 | }, 991 | "node_modules/got": { 992 | "version": "9.6.0", 993 | "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", 994 | "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", 995 | "dev": true, 996 | "dependencies": { 997 | "@sindresorhus/is": "^0.14.0", 998 | "@szmarczak/http-timer": "^1.1.2", 999 | "cacheable-request": "^6.0.0", 1000 | "decompress-response": "^3.3.0", 1001 | "duplexer3": "^0.1.4", 1002 | "get-stream": "^4.1.0", 1003 | "lowercase-keys": "^1.0.1", 1004 | "mimic-response": "^1.0.1", 1005 | "p-cancelable": "^1.0.0", 1006 | "to-readable-stream": "^1.0.0", 1007 | "url-parse-lax": "^3.0.0" 1008 | }, 1009 | "engines": { 1010 | "node": ">=8.6" 1011 | } 1012 | }, 1013 | "node_modules/graceful-fs": { 1014 | "version": "4.2.10", 1015 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", 1016 | "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", 1017 | "dev": true 1018 | }, 1019 | "node_modules/has": { 1020 | "version": "1.0.3", 1021 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1022 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1023 | "dev": true, 1024 | "optional": true, 1025 | "dependencies": { 1026 | "function-bind": "^1.1.1" 1027 | }, 1028 | "engines": { 1029 | "node": ">= 0.4.0" 1030 | } 1031 | }, 1032 | "node_modules/has-flag": { 1033 | "version": "4.0.0", 1034 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1035 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1036 | "dev": true, 1037 | "engines": { 1038 | "node": ">=8" 1039 | } 1040 | }, 1041 | "node_modules/has-property-descriptors": { 1042 | "version": "1.0.0", 1043 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 1044 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 1045 | "dev": true, 1046 | "optional": true, 1047 | "dependencies": { 1048 | "get-intrinsic": "^1.1.1" 1049 | }, 1050 | "funding": { 1051 | "url": "https://github.com/sponsors/ljharb" 1052 | } 1053 | }, 1054 | "node_modules/has-symbols": { 1055 | "version": "1.0.3", 1056 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1057 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 1058 | "dev": true, 1059 | "optional": true, 1060 | "engines": { 1061 | "node": ">= 0.4" 1062 | }, 1063 | "funding": { 1064 | "url": "https://github.com/sponsors/ljharb" 1065 | } 1066 | }, 1067 | "node_modules/http-cache-semantics": { 1068 | "version": "4.1.1", 1069 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", 1070 | "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", 1071 | "dev": true 1072 | }, 1073 | "node_modules/ignore": { 1074 | "version": "5.2.4", 1075 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", 1076 | "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", 1077 | "dev": true, 1078 | "engines": { 1079 | "node": ">= 4" 1080 | } 1081 | }, 1082 | "node_modules/ini": { 1083 | "version": "1.3.8", 1084 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 1085 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 1086 | "dev": true, 1087 | "optional": true 1088 | }, 1089 | "node_modules/is-extglob": { 1090 | "version": "2.1.1", 1091 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1092 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1093 | "dev": true, 1094 | "engines": { 1095 | "node": ">=0.10.0" 1096 | } 1097 | }, 1098 | "node_modules/is-glob": { 1099 | "version": "4.0.3", 1100 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1101 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1102 | "dev": true, 1103 | "dependencies": { 1104 | "is-extglob": "^2.1.1" 1105 | }, 1106 | "engines": { 1107 | "node": ">=0.10.0" 1108 | } 1109 | }, 1110 | "node_modules/is-number": { 1111 | "version": "7.0.0", 1112 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1113 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1114 | "dev": true, 1115 | "engines": { 1116 | "node": ">=0.12.0" 1117 | } 1118 | }, 1119 | "node_modules/json-buffer": { 1120 | "version": "3.0.0", 1121 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", 1122 | "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", 1123 | "dev": true 1124 | }, 1125 | "node_modules/json-stringify-safe": { 1126 | "version": "5.0.1", 1127 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 1128 | "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", 1129 | "dev": true, 1130 | "optional": true 1131 | }, 1132 | "node_modules/jsonfile": { 1133 | "version": "4.0.0", 1134 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 1135 | "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", 1136 | "dev": true, 1137 | "optionalDependencies": { 1138 | "graceful-fs": "^4.1.6" 1139 | } 1140 | }, 1141 | "node_modules/keyv": { 1142 | "version": "3.1.0", 1143 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", 1144 | "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", 1145 | "dev": true, 1146 | "dependencies": { 1147 | "json-buffer": "3.0.0" 1148 | } 1149 | }, 1150 | "node_modules/lodash": { 1151 | "version": "4.17.21", 1152 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1153 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1154 | "dev": true, 1155 | "optional": true 1156 | }, 1157 | "node_modules/lowercase-keys": { 1158 | "version": "1.0.1", 1159 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 1160 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", 1161 | "dev": true, 1162 | "engines": { 1163 | "node": ">=0.10.0" 1164 | } 1165 | }, 1166 | "node_modules/lru-cache": { 1167 | "version": "6.0.0", 1168 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1169 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1170 | "dev": true, 1171 | "optional": true, 1172 | "dependencies": { 1173 | "yallist": "^4.0.0" 1174 | }, 1175 | "engines": { 1176 | "node": ">=10" 1177 | } 1178 | }, 1179 | "node_modules/matcher": { 1180 | "version": "3.0.0", 1181 | "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", 1182 | "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", 1183 | "dev": true, 1184 | "optional": true, 1185 | "dependencies": { 1186 | "escape-string-regexp": "^4.0.0" 1187 | }, 1188 | "engines": { 1189 | "node": ">=10" 1190 | } 1191 | }, 1192 | "node_modules/merge2": { 1193 | "version": "1.4.1", 1194 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1195 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1196 | "dev": true, 1197 | "engines": { 1198 | "node": ">= 8" 1199 | } 1200 | }, 1201 | "node_modules/micromatch": { 1202 | "version": "4.0.5", 1203 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1204 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1205 | "dev": true, 1206 | "dependencies": { 1207 | "braces": "^3.0.2", 1208 | "picomatch": "^2.3.1" 1209 | }, 1210 | "engines": { 1211 | "node": ">=8.6" 1212 | } 1213 | }, 1214 | "node_modules/mimic-response": { 1215 | "version": "1.0.1", 1216 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 1217 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", 1218 | "dev": true, 1219 | "engines": { 1220 | "node": ">=4" 1221 | } 1222 | }, 1223 | "node_modules/moment": { 1224 | "version": "2.29.4", 1225 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", 1226 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", 1227 | "dev": true, 1228 | "engines": { 1229 | "node": "*" 1230 | } 1231 | }, 1232 | "node_modules/ms": { 1233 | "version": "2.1.2", 1234 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1235 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1236 | "dev": true 1237 | }, 1238 | "node_modules/normalize-url": { 1239 | "version": "4.5.1", 1240 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", 1241 | "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", 1242 | "dev": true, 1243 | "engines": { 1244 | "node": ">=8" 1245 | } 1246 | }, 1247 | "node_modules/npm-conf": { 1248 | "version": "1.1.3", 1249 | "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", 1250 | "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", 1251 | "dev": true, 1252 | "optional": true, 1253 | "dependencies": { 1254 | "config-chain": "^1.1.11", 1255 | "pify": "^3.0.0" 1256 | }, 1257 | "engines": { 1258 | "node": ">=4" 1259 | } 1260 | }, 1261 | "node_modules/object-keys": { 1262 | "version": "1.1.1", 1263 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1264 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 1265 | "dev": true, 1266 | "optional": true, 1267 | "engines": { 1268 | "node": ">= 0.4" 1269 | } 1270 | }, 1271 | "node_modules/obsidian": { 1272 | "version": "1.1.1", 1273 | "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.1.1.tgz", 1274 | "integrity": "sha512-GcxhsHNkPEkwHEjeyitfYNBcQuYGeAHFs1pEpZIv0CnzSfui8p8bPLm2YKLgcg20B764770B1sYGtxCvk9ptxg==", 1275 | "dev": true, 1276 | "dependencies": { 1277 | "@types/codemirror": "0.0.108", 1278 | "moment": "2.29.4" 1279 | }, 1280 | "peerDependencies": { 1281 | "@codemirror/state": "^6.0.0", 1282 | "@codemirror/view": "^6.0.0" 1283 | } 1284 | }, 1285 | "node_modules/once": { 1286 | "version": "1.4.0", 1287 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1288 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1289 | "dev": true, 1290 | "dependencies": { 1291 | "wrappy": "1" 1292 | } 1293 | }, 1294 | "node_modules/p-cancelable": { 1295 | "version": "1.1.0", 1296 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", 1297 | "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", 1298 | "dev": true, 1299 | "engines": { 1300 | "node": ">=6" 1301 | } 1302 | }, 1303 | "node_modules/path-type": { 1304 | "version": "4.0.0", 1305 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1306 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1307 | "dev": true, 1308 | "engines": { 1309 | "node": ">=8" 1310 | } 1311 | }, 1312 | "node_modules/pend": { 1313 | "version": "1.2.0", 1314 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", 1315 | "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", 1316 | "dev": true 1317 | }, 1318 | "node_modules/picomatch": { 1319 | "version": "2.3.1", 1320 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1321 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1322 | "dev": true, 1323 | "engines": { 1324 | "node": ">=8.6" 1325 | }, 1326 | "funding": { 1327 | "url": "https://github.com/sponsors/jonschlinkert" 1328 | } 1329 | }, 1330 | "node_modules/pify": { 1331 | "version": "3.0.0", 1332 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 1333 | "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", 1334 | "dev": true, 1335 | "optional": true, 1336 | "engines": { 1337 | "node": ">=4" 1338 | } 1339 | }, 1340 | "node_modules/prepend-http": { 1341 | "version": "2.0.0", 1342 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", 1343 | "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", 1344 | "dev": true, 1345 | "engines": { 1346 | "node": ">=4" 1347 | } 1348 | }, 1349 | "node_modules/progress": { 1350 | "version": "2.0.3", 1351 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1352 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1353 | "dev": true, 1354 | "engines": { 1355 | "node": ">=0.4.0" 1356 | } 1357 | }, 1358 | "node_modules/proto-list": { 1359 | "version": "1.2.4", 1360 | "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", 1361 | "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", 1362 | "dev": true, 1363 | "optional": true 1364 | }, 1365 | "node_modules/pump": { 1366 | "version": "3.0.0", 1367 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1368 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1369 | "dev": true, 1370 | "dependencies": { 1371 | "end-of-stream": "^1.1.0", 1372 | "once": "^1.3.1" 1373 | } 1374 | }, 1375 | "node_modules/queue-microtask": { 1376 | "version": "1.2.3", 1377 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1378 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1379 | "dev": true, 1380 | "funding": [ 1381 | { 1382 | "type": "github", 1383 | "url": "https://github.com/sponsors/feross" 1384 | }, 1385 | { 1386 | "type": "patreon", 1387 | "url": "https://www.patreon.com/feross" 1388 | }, 1389 | { 1390 | "type": "consulting", 1391 | "url": "https://feross.org/support" 1392 | } 1393 | ] 1394 | }, 1395 | "node_modules/responselike": { 1396 | "version": "1.0.2", 1397 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", 1398 | "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", 1399 | "dev": true, 1400 | "dependencies": { 1401 | "lowercase-keys": "^1.0.0" 1402 | } 1403 | }, 1404 | "node_modules/reusify": { 1405 | "version": "1.0.4", 1406 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1407 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1408 | "dev": true, 1409 | "engines": { 1410 | "iojs": ">=1.0.0", 1411 | "node": ">=0.10.0" 1412 | } 1413 | }, 1414 | "node_modules/roarr": { 1415 | "version": "2.15.4", 1416 | "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", 1417 | "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", 1418 | "dev": true, 1419 | "optional": true, 1420 | "dependencies": { 1421 | "boolean": "^3.0.1", 1422 | "detect-node": "^2.0.4", 1423 | "globalthis": "^1.0.1", 1424 | "json-stringify-safe": "^5.0.1", 1425 | "semver-compare": "^1.0.0", 1426 | "sprintf-js": "^1.1.2" 1427 | }, 1428 | "engines": { 1429 | "node": ">=8.0" 1430 | } 1431 | }, 1432 | "node_modules/run-parallel": { 1433 | "version": "1.2.0", 1434 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1435 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1436 | "dev": true, 1437 | "funding": [ 1438 | { 1439 | "type": "github", 1440 | "url": "https://github.com/sponsors/feross" 1441 | }, 1442 | { 1443 | "type": "patreon", 1444 | "url": "https://www.patreon.com/feross" 1445 | }, 1446 | { 1447 | "type": "consulting", 1448 | "url": "https://feross.org/support" 1449 | } 1450 | ], 1451 | "dependencies": { 1452 | "queue-microtask": "^1.2.2" 1453 | } 1454 | }, 1455 | "node_modules/semver": { 1456 | "version": "6.3.0", 1457 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1458 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1459 | "dev": true, 1460 | "bin": { 1461 | "semver": "bin/semver.js" 1462 | } 1463 | }, 1464 | "node_modules/semver-compare": { 1465 | "version": "1.0.0", 1466 | "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", 1467 | "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", 1468 | "dev": true, 1469 | "optional": true 1470 | }, 1471 | "node_modules/serialize-error": { 1472 | "version": "7.0.1", 1473 | "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", 1474 | "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", 1475 | "dev": true, 1476 | "optional": true, 1477 | "dependencies": { 1478 | "type-fest": "^0.13.1" 1479 | }, 1480 | "engines": { 1481 | "node": ">=10" 1482 | }, 1483 | "funding": { 1484 | "url": "https://github.com/sponsors/sindresorhus" 1485 | } 1486 | }, 1487 | "node_modules/slash": { 1488 | "version": "3.0.0", 1489 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1490 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1491 | "dev": true, 1492 | "engines": { 1493 | "node": ">=8" 1494 | } 1495 | }, 1496 | "node_modules/sprintf-js": { 1497 | "version": "1.1.2", 1498 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", 1499 | "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", 1500 | "dev": true, 1501 | "optional": true 1502 | }, 1503 | "node_modules/style-mod": { 1504 | "version": "4.0.0", 1505 | "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", 1506 | "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", 1507 | "dev": true, 1508 | "peer": true 1509 | }, 1510 | "node_modules/sumchecker": { 1511 | "version": "3.0.1", 1512 | "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", 1513 | "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", 1514 | "dev": true, 1515 | "dependencies": { 1516 | "debug": "^4.1.0" 1517 | }, 1518 | "engines": { 1519 | "node": ">= 8.0" 1520 | } 1521 | }, 1522 | "node_modules/supports-color": { 1523 | "version": "7.2.0", 1524 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1525 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1526 | "dev": true, 1527 | "dependencies": { 1528 | "has-flag": "^4.0.0" 1529 | }, 1530 | "engines": { 1531 | "node": ">=8" 1532 | } 1533 | }, 1534 | "node_modules/to-readable-stream": { 1535 | "version": "1.0.0", 1536 | "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", 1537 | "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", 1538 | "dev": true, 1539 | "engines": { 1540 | "node": ">=6" 1541 | } 1542 | }, 1543 | "node_modules/to-regex-range": { 1544 | "version": "5.0.1", 1545 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1546 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1547 | "dev": true, 1548 | "dependencies": { 1549 | "is-number": "^7.0.0" 1550 | }, 1551 | "engines": { 1552 | "node": ">=8.0" 1553 | } 1554 | }, 1555 | "node_modules/tslib": { 1556 | "version": "2.3.1", 1557 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", 1558 | "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", 1559 | "dev": true 1560 | }, 1561 | "node_modules/tunnel": { 1562 | "version": "0.0.6", 1563 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 1564 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 1565 | "dev": true, 1566 | "optional": true, 1567 | "engines": { 1568 | "node": ">=0.6.11 <=0.7.0 || >=0.7.3" 1569 | } 1570 | }, 1571 | "node_modules/type-fest": { 1572 | "version": "0.13.1", 1573 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", 1574 | "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", 1575 | "dev": true, 1576 | "optional": true, 1577 | "engines": { 1578 | "node": ">=10" 1579 | }, 1580 | "funding": { 1581 | "url": "https://github.com/sponsors/sindresorhus" 1582 | } 1583 | }, 1584 | "node_modules/typescript": { 1585 | "version": "4.4.4", 1586 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", 1587 | "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", 1588 | "dev": true, 1589 | "bin": { 1590 | "tsc": "bin/tsc", 1591 | "tsserver": "bin/tsserver" 1592 | }, 1593 | "engines": { 1594 | "node": ">=4.2.0" 1595 | } 1596 | }, 1597 | "node_modules/universalify": { 1598 | "version": "0.1.2", 1599 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 1600 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 1601 | "dev": true, 1602 | "engines": { 1603 | "node": ">= 4.0.0" 1604 | } 1605 | }, 1606 | "node_modules/url-parse-lax": { 1607 | "version": "3.0.0", 1608 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", 1609 | "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", 1610 | "dev": true, 1611 | "dependencies": { 1612 | "prepend-http": "^2.0.0" 1613 | }, 1614 | "engines": { 1615 | "node": ">=4" 1616 | } 1617 | }, 1618 | "node_modules/w3c-keyname": { 1619 | "version": "2.2.6", 1620 | "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", 1621 | "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", 1622 | "dev": true, 1623 | "peer": true 1624 | }, 1625 | "node_modules/wrappy": { 1626 | "version": "1.0.2", 1627 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1628 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1629 | "dev": true 1630 | }, 1631 | "node_modules/yallist": { 1632 | "version": "4.0.0", 1633 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1634 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1635 | "dev": true, 1636 | "optional": true 1637 | }, 1638 | "node_modules/yauzl": { 1639 | "version": "2.10.0", 1640 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", 1641 | "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", 1642 | "dev": true, 1643 | "dependencies": { 1644 | "buffer-crc32": "~0.2.3", 1645 | "fd-slicer": "~1.1.0" 1646 | } 1647 | } 1648 | } 1649 | } 1650 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-custom-frames", 3 | "version": "2.5.0", 4 | "description": "An Obsidian plugin that turns web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "node esbuild.config.mjs", 8 | "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", 9 | "version": "node version-bump.mjs && git add manifest.json versions.json" 10 | }, 11 | "keywords": [], 12 | "author": "Ellpeck", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@types/node": "^16.11.6", 16 | "builtin-modules": "^3.2.0", 17 | "electron": "^20.3.9", 18 | "esbuild": "0.14.0", 19 | "esbuild-plugin-copy": "^1.3.0", 20 | "obsidian": "latest", 21 | "tslib": "2.3.1", 22 | "typescript": "4.4.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /screenshot-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/be1c5c1610b0d11d85e8160a4ca7b0178e84b0ee/screenshot-big.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/be1c5c1610b0d11d85e8160a4ca7b0178e84b0ee/screenshot.png -------------------------------------------------------------------------------- /settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/be1c5c1610b0d11d85e8160a4ca7b0178e84b0ee/settings.png -------------------------------------------------------------------------------- /src/frame.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from "obsidian"; 2 | import { CustomFrameSettings, CustomFramesSettings, getId } from "./settings"; 3 | 4 | export class CustomFrame { 5 | private readonly settings: CustomFramesSettings; 6 | private readonly data: CustomFrameSettings; 7 | private frame: HTMLIFrameElement | any; 8 | 9 | constructor(settings: CustomFramesSettings, data: CustomFrameSettings) { 10 | this.settings = settings; 11 | this.data = data; 12 | } 13 | 14 | create(parent: HTMLElement, additionalStyle: string = undefined, urlSuffix: string = undefined): void { 15 | let style = `padding: ${this.settings.padding}px;`; 16 | if (additionalStyle) style += additionalStyle; 17 | if (Platform.isDesktopApp && !this.data.forceIframe) { 18 | let frameDoc = parent.doc; 19 | this.frame = frameDoc.createElement("webview"); 20 | // @ts-ignore - share sessions with the built-in web viewer, see https://github.com/Ellpeck/ObsidianCustomFrames/issues/136#issuecomment-2584116803 21 | this.frame.partition = "persist:vault-" + app.appId; 22 | parent.appendChild(this.frame); 23 | this.frame.setAttribute("allowpopups", ""); 24 | this.frame.addEventListener("dom-ready", () => { 25 | this.frame.setZoomFactor(this.data.zoomLevel); 26 | this.frame.insertCSS(this.data.customCss); 27 | this.frame.executeJavaScript(this.data.customJs); 28 | }); 29 | this.frame.addEventListener("destroyed", () => { 30 | // recreate the webview if it was moved to a new window 31 | if (frameDoc != parent.doc) { 32 | this.frame.detach(); 33 | this.create(parent, additionalStyle, urlSuffix); 34 | } 35 | }); 36 | } else { 37 | this.frame = parent.doc.createElement("iframe"); 38 | parent.appendChild(this.frame); 39 | this.frame.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads"); 40 | this.frame.setAttribute("allow", "encrypted-media; fullscreen; oversized-images; picture-in-picture; sync-xhr; geolocation;"); 41 | style += `transform: scale(${this.data.zoomLevel}); transform-origin: 0 0;`; 42 | } 43 | this.frame.addClass("custom-frames-frame"); 44 | this.frame.addClass(`custom-frames-${getId(this.data)}`); 45 | this.frame.setAttribute("style", style); 46 | 47 | let src = new URL(this.data.url); 48 | 49 | if (urlSuffix) { 50 | let suffix = new URL(urlSuffix, src.origin); 51 | 52 | suffix.searchParams.forEach((value, key) => { 53 | src.searchParams.set(key, value); 54 | }); 55 | 56 | if (suffix.pathname !== "/") { 57 | src.pathname += suffix.pathname; 58 | } 59 | 60 | src.hash = suffix.hash || src.hash; 61 | } 62 | 63 | this.frame.setAttribute("src", src.toString()); 64 | } 65 | 66 | refresh(): void { 67 | if (this.frame instanceof HTMLIFrameElement) { 68 | this.frame.contentWindow.location.reload(); 69 | } else { 70 | this.frame.reload(); 71 | } 72 | } 73 | 74 | return(): void { 75 | if (this.frame instanceof HTMLIFrameElement) { 76 | this.frame.contentWindow.open(this.data.url); 77 | } else { 78 | this.frame.loadURL(this.data.url); 79 | } 80 | } 81 | 82 | goBack(): void { 83 | if (this.frame instanceof HTMLIFrameElement) { 84 | this.frame.contentWindow.history.back(); 85 | } else { 86 | this.frame.goBack(); 87 | } 88 | } 89 | 90 | goForward(): void { 91 | if (this.frame instanceof HTMLIFrameElement) { 92 | this.frame.contentWindow.history.forward(); 93 | } else { 94 | this.frame.goForward(); 95 | } 96 | } 97 | 98 | toggleDevTools(): void { 99 | if (!(this.frame instanceof HTMLIFrameElement)) { 100 | if (!this.frame.isDevToolsOpened()) { 101 | this.frame.openDevTools(); 102 | } else { 103 | this.frame.closeDevTools(); 104 | } 105 | } 106 | } 107 | 108 | getCurrentUrl(): string { 109 | return this.frame instanceof HTMLIFrameElement ? this.frame.contentWindow.location.href : this.frame.getURL(); 110 | } 111 | 112 | focus(): void { 113 | if (this.frame instanceof HTMLIFrameElement) { 114 | this.frame.contentWindow.focus(); 115 | } else { 116 | this.frame.focus(); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { Plugin, Platform, WorkspaceLeaf } from "obsidian"; 2 | import { CustomFrame } from "./frame"; 3 | import { CustomFramesSettings, defaultSettings, getIcon, getId } from "./settings"; 4 | import { CustomFramesSettingTab } from "./settings-tab"; 5 | import { CustomFrameView } from "./view"; 6 | 7 | export default class CustomFramesPlugin extends Plugin { 8 | 9 | settings: CustomFramesSettings; 10 | 11 | async onload(): Promise { 12 | await this.loadSettings(); 13 | 14 | for (let frame of this.settings.frames) { 15 | if (!frame.url || !frame.displayName) 16 | continue; 17 | let name = `custom-frames-${getId(frame)}`; 18 | if (Platform.isMobileApp && frame.hideOnMobile) { 19 | console.log(`Skipping frame ${name} which is hidden on mobile`); 20 | continue; 21 | } 22 | try { 23 | console.log(`Registering frame ${name} for URL ${frame.url}`); 24 | 25 | this.registerView(name, l => new CustomFrameView(l, this.settings, frame, name)); 26 | this.addCommand({ 27 | id: `open-${name}`, 28 | name: `Open ${frame.displayName}`, 29 | callback: () => this.openLeaf(name, frame.openInCenter, false), 30 | }); 31 | 32 | if (frame.addRibbonIcon) 33 | this.addRibbonIcon(getIcon(frame), `Open ${frame.displayName}`, 34 | e => this.openLeaf(name, frame.openInCenter, Platform.isMacOS ? e.metaKey : e.ctrlKey)); 35 | } catch { 36 | console.error(`Couldn't register frame ${name}, is there already one with the same name?`); 37 | } 38 | } 39 | 40 | this.addSettingTab(new CustomFramesSettingTab(this.app, this)); 41 | 42 | this.registerMarkdownCodeBlockProcessor("custom-frames", (s, e) => { 43 | e.empty(); 44 | e.addClass("custom-frames-view-file"); 45 | 46 | let frameMatch = /frame:([^\n]+)/gi.exec(s); 47 | let frameName = frameMatch && frameMatch[1].trim(); 48 | if (!frameName) { 49 | e.createSpan({ text: "Couldn't parse frame name" }); 50 | return; 51 | } 52 | let data = this.settings.frames.find(f => f.displayName == frameName); 53 | if (!data) { 54 | e.createSpan({ text: `Couldn't find a frame with name ${frameName}` }); 55 | return; 56 | } 57 | if (Platform.isMobileApp && data.hideOnMobile) { 58 | e.createSpan({ text: `${frameName} is hidden on mobile` }); 59 | return; 60 | } 61 | 62 | let styleMatch = /style:([^\n]+)/gi.exec(s); 63 | let style = styleMatch && styleMatch[1].trim(); 64 | style ||= "height: 600px;"; 65 | 66 | let urlSuffixMatch = /urlsuffix:([^\n]+)/gi.exec(s); 67 | let urlSuffix = urlSuffixMatch && urlSuffixMatch[1].trim(); 68 | urlSuffix ||= ""; 69 | 70 | let frame = new CustomFrame(this.settings, data); 71 | frame.create(e, style, urlSuffix); 72 | }); 73 | } 74 | 75 | async loadSettings() { 76 | this.settings = Object.assign({}, defaultSettings, await this.loadData()); 77 | } 78 | 79 | async saveSettings() { 80 | await this.saveData(this.settings); 81 | } 82 | 83 | private async openLeaf(name: string, center: boolean, split: boolean): Promise { 84 | let leaf: WorkspaceLeaf; 85 | if (center) { 86 | leaf = this.app.workspace.getLeaf(split); 87 | await leaf.setViewState({ type: name, active: true }); 88 | } else { 89 | if (!this.app.workspace.getLeavesOfType(name).length) 90 | await this.app.workspace.getRightLeaf(false).setViewState({ type: name, active: true }); 91 | leaf = this.app.workspace.getLeavesOfType(name)[0]; 92 | this.app.workspace.revealLeaf(leaf); 93 | } 94 | if (leaf.view instanceof CustomFrameView) 95 | leaf.view.focus(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/settings-tab.ts: -------------------------------------------------------------------------------- 1 | import { App, ButtonComponent, DropdownComponent, PluginSettingTab, Setting } from "obsidian"; 2 | import { defaultSettings, presets } from "./settings"; 3 | import CustomFramesPlugin from "./main"; 4 | 5 | export class CustomFramesSettingTab extends PluginSettingTab { 6 | 7 | plugin: CustomFramesPlugin; 8 | 9 | constructor(app: App, plugin: CustomFramesPlugin) { 10 | super(app, plugin); 11 | this.plugin = plugin; 12 | } 13 | 14 | display(): void { 15 | this.containerEl.empty(); 16 | this.containerEl.createEl("h2", { text: "Custom Frames Settings" }); 17 | this.containerEl.createEl("p", { 18 | text: "Please note that Obsidian has to be restarted or reloaded for most of these settings to take effect.", 19 | cls: "mod-warning" 20 | }); 21 | 22 | new Setting(this.containerEl) 23 | .setName("Frame Padding") 24 | .setDesc("The padding that should be left around the inside of custom frame panes, in pixels.") 25 | .addText(t => { 26 | t.inputEl.type = "number"; 27 | t.setValue(String(this.plugin.settings.padding)); 28 | t.onChange(async v => { 29 | this.plugin.settings.padding = v.length ? Number(v) : defaultSettings.padding; 30 | await this.plugin.saveSettings(); 31 | }); 32 | }); 33 | 34 | for (let frame of this.plugin.settings.frames) { 35 | let heading = this.containerEl.createEl("h3", { text: frame.displayName || "Unnamed Frame" }); 36 | let toggle = new ButtonComponent(this.containerEl) 37 | .setButtonText("Show Settings") 38 | .setClass("custom-frames-show") 39 | .onClick(async () => { 40 | content.hidden = !content.hidden; 41 | toggle.setButtonText(content.hidden ? "Show Settings" : "Hide Settings"); 42 | }); 43 | let content = this.containerEl.createDiv(); 44 | content.hidden = true; 45 | 46 | new Setting(content) 47 | .setName("Display Name") 48 | .setDesc("The display name that this frame should have.") 49 | .addText(t => { 50 | t.setValue(frame.displayName); 51 | t.onChange(async v => { 52 | frame.displayName = v; 53 | heading.setText(frame.displayName || "Unnamed Frame"); 54 | await this.plugin.saveSettings(); 55 | }); 56 | }); 57 | new Setting(content) 58 | .setName("Icon") 59 | .setDesc(createFragment(f => { 60 | f.createSpan({ text: "The icon that this frame's pane should have. The names of any " }); 61 | f.createEl("a", { text: "Lucide icons", href: "https://lucide.dev/" }); 62 | f.createSpan({ text: " can be used." }); 63 | })) 64 | .addText(t => { 65 | t.setValue(frame.icon); 66 | t.onChange(async v => { 67 | frame.icon = v; 68 | await this.plugin.saveSettings(); 69 | }); 70 | }); 71 | new Setting(content) 72 | .setName("URL") 73 | .setDesc("The URL that should be opened in this frame.") 74 | .addText(t => { 75 | t.setValue(frame.url); 76 | t.onChange(async v => { 77 | frame.url = v; 78 | await this.plugin.saveSettings(); 79 | }); 80 | }); 81 | new Setting(content) 82 | .setName("Disable on Mobile") 83 | .setDesc("Custom Frames is a lot more restricted on mobile devices and doesn't allow for the same types of content to be displayed. If a frame doesn't work as expected on mobile, it can be disabled.") 84 | .addToggle(t => { 85 | t.setValue(frame.hideOnMobile); 86 | t.onChange(async v => { 87 | frame.hideOnMobile = v; 88 | await this.plugin.saveSettings(); 89 | }); 90 | }); 91 | new Setting(content) 92 | .setName("Add Ribbon Icon") 93 | .setDesc("Whether a button to open this frame should be added to the ribbon.") 94 | .addToggle(t => { 95 | t.setValue(frame.addRibbonIcon); 96 | t.onChange(async v => { 97 | frame.addRibbonIcon = v; 98 | await this.plugin.saveSettings(); 99 | }); 100 | }); 101 | new Setting(content) 102 | .setName("Open in Center") 103 | .setDesc("Whether this frame should be opened in the unpinned center editor rather than one of the panes on the side. This is useful for sites that don't work well in a narrow view, or sites that don't require a note to be open when viewed.") 104 | .addToggle(t => { 105 | t.setValue(frame.openInCenter); 106 | t.onChange(async v => { 107 | frame.openInCenter = v; 108 | await this.plugin.saveSettings(); 109 | }); 110 | }); 111 | new Setting(content) 112 | .setName("Force iframe") 113 | .setDesc(createFragment(f => { 114 | f.createSpan({ text: "Whether this frame should use iframes on desktop as opposed to Electron webviews." }); 115 | f.createEl("br"); 116 | f.createEl("em", { text: "Only enable this setting if the frame is causing issues or frequent crashes. This setting causes all Desktop-only settings to be ignored." }); 117 | })) 118 | .addToggle(t => { 119 | t.setValue(frame.forceIframe); 120 | t.onChange(async v => { 121 | frame.forceIframe = v; 122 | await this.plugin.saveSettings(); 123 | }); 124 | }); 125 | new Setting(content) 126 | .setName("Page Zoom") 127 | .setDesc("The zoom that this frame's page should be displayed with, as a percentage.") 128 | .addText(t => { 129 | t.inputEl.type = "number"; 130 | t.setValue(String(frame.zoomLevel * 100)); 131 | t.onChange(async v => { 132 | frame.zoomLevel = v.length ? Number(v) / 100 : 1; 133 | await this.plugin.saveSettings(); 134 | }); 135 | }); 136 | new Setting(content) 137 | .setName("Additional CSS") 138 | .setDesc(createFragment(f => { 139 | f.createSpan({ text: "A snippet of additional CSS that should be applied to this frame." }); 140 | f.createEl("br"); 141 | f.createEl("em", { text: "Note that this is only applied on Desktop." }); 142 | })) 143 | .addTextArea(t => { 144 | t.inputEl.rows = 5; 145 | t.inputEl.cols = 50; 146 | t.setValue(frame.customCss); 147 | t.onChange(async v => { 148 | frame.customCss = v; 149 | await this.plugin.saveSettings(); 150 | }); 151 | }); 152 | new Setting(content) 153 | .setName("Additional JavaScript") 154 | .setDesc(createFragment(f => { 155 | f.createSpan({ text: "A snippet of additional JavaScript that should be applied to this frame." }); 156 | f.createEl("br"); 157 | f.createEl("em", { text: "Note that this is only applied on Desktop." }); 158 | })) 159 | .addTextArea(t => { 160 | t.inputEl.rows = 5; 161 | t.inputEl.cols = 50; 162 | t.setValue(frame.customJs); 163 | t.onChange(async v => { 164 | frame.customJs = v; 165 | await this.plugin.saveSettings(); 166 | }); 167 | }); 168 | new ButtonComponent(content) 169 | .setButtonText("Remove Frame") 170 | .onClick(async () => { 171 | this.plugin.settings.frames.remove(frame); 172 | await this.plugin.saveSettings(); 173 | this.display(); 174 | }); 175 | } 176 | 177 | this.containerEl.createEl("hr"); 178 | this.containerEl.createEl("p", { text: "Create a new frame, either from a preset shipped with the plugin, or a custom one that you can edit yourself. Each frame's pane can be opened using the \"Custom Frames: Open\" command." }); 179 | 180 | let addDiv = this.containerEl.createDiv(); 181 | let dropdown = new DropdownComponent(addDiv); 182 | dropdown.addOption("new", "Custom"); 183 | for (let [key, value] of Object.entries(presets).sort((a, b) => a[1].displayName.localeCompare(b[1].displayName))) 184 | dropdown.addOption(key, value.displayName); 185 | new ButtonComponent(addDiv) 186 | .setButtonText("Add Frame") 187 | .setClass("custom-frames-add") 188 | .onClick(async () => { 189 | let option = dropdown.getValue(); 190 | if (option == "new") { 191 | this.plugin.settings.frames.push({ 192 | url: "", 193 | displayName: "New Frame", 194 | icon: "", 195 | hideOnMobile: true, 196 | addRibbonIcon: false, 197 | openInCenter: false, 198 | zoomLevel: 1, 199 | forceIframe: false, 200 | customCss: "", 201 | customJs: "" 202 | }); 203 | } else { 204 | this.plugin.settings.frames.push(presets[option]); 205 | } 206 | await this.plugin.saveSettings(); 207 | this.display(); 208 | }); 209 | 210 | let disclaimer = this.containerEl.createEl("p", { cls: "mod-warning" }); 211 | disclaimer.createSpan({ text: "Please be advised that, when adding a site as a custom frame, you potentially expose personal information you enter to other plugins you have installed. For more information, see " }); 212 | disclaimer.createEl("a", { 213 | text: "this discussion", 214 | href: "https://github.com/Ellpeck/ObsidianCustomFrames/issues/54#issuecomment-1210879685", 215 | cls: "mod-warning" 216 | }); 217 | disclaimer.createSpan({ text: "." }); 218 | 219 | this.containerEl.createEl("hr"); 220 | this.containerEl.createEl("p", { text: "Need help using the plugin? Feel free to join the Discord server!" }); 221 | this.containerEl.createEl("a", { href: "https://link.ellpeck.de/discordweb" }).createEl("img", { 222 | attr: { src: "https://ellpeck.de/res/discord-wide.png" }, 223 | cls: "custom-frames-support" 224 | }); 225 | this.containerEl.createEl("p", { text: "If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!" }); 226 | this.containerEl.createEl("a", { href: "https://ellpeck.de/support" }).createEl("img", { 227 | attr: { src: "https://ellpeck.de/res/generalsupport-wide.png" }, 228 | cls: "custom-frames-support" 229 | }); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/settings.ts: -------------------------------------------------------------------------------- 1 | export const defaultSettings: CustomFramesSettings = { 2 | frames: [], 3 | padding: 5 4 | }; 5 | export const presets: Record = { 6 | "obsidian": { 7 | url: "https://forum.obsidian.md/", 8 | displayName: "Obsidian Forum", 9 | icon: "edit", 10 | hideOnMobile: true, 11 | addRibbonIcon: true, 12 | openInCenter: true, 13 | zoomLevel: 1, 14 | forceIframe: false, 15 | customCss: "", 16 | customJs: "" 17 | }, 18 | "detexify": { 19 | url: "https://detexify.kirelabs.org/classify.html", 20 | displayName: "Detexify", 21 | icon: "type", 22 | hideOnMobile: true, 23 | addRibbonIcon: true, 24 | openInCenter: false, 25 | zoomLevel: .95, 26 | forceIframe: false, 27 | customCss: `/* hide info clutter and ad banner */ 28 | #classify--info-area, 29 | .adsbygoogle { 30 | display: none !important 31 | }`, 32 | customJs: "" 33 | }, 34 | "calendar": { 35 | url: "https://calendar.google.com/calendar", 36 | displayName: "Google Calendar", 37 | icon: "calendar", 38 | hideOnMobile: true, 39 | addRibbonIcon: true, 40 | openInCenter: true, 41 | zoomLevel: 1, 42 | forceIframe: false, 43 | customCss: `/* hide the menu bar "Calendar" text and remove minimum width */ 44 | div[style*="min-width: 238px"] { 45 | min-width: 0 !important; 46 | padding-right: 0 !important; 47 | } 48 | div[style*="min-width: 238px"] span[role*="heading"] { 49 | display: none !important; 50 | }`, 51 | customJs: "" 52 | }, 53 | "keep": { 54 | url: "https://keep.google.com", 55 | displayName: "Google Keep", 56 | icon: "files", 57 | hideOnMobile: true, 58 | addRibbonIcon: false, 59 | openInCenter: false, 60 | zoomLevel: 1, 61 | forceIframe: false, 62 | customCss: `/* hide the menu bar, the "Keep" text and the Google Apps button */ 63 | html > body > div:nth-child(2) > div:nth-child(2) > div:first-child, 64 | html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child > span, 65 | html > body > div:first-child > header:first-child > div:nth-child(2) > div:first-child > div:first-child, 66 | html > body > div:first-child > header:first-child > div:nth-child(2) > div:nth-child(3) > div:first-child > div:first-child > div:first-child { 67 | display: none !important; 68 | } 69 | html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child { 70 | cursor: default; 71 | }`, 72 | customJs: "" 73 | }, 74 | "todoist": { 75 | url: "https://todoist.com", 76 | displayName: "Todoist", 77 | icon: "list-checks", 78 | hideOnMobile: true, 79 | addRibbonIcon: false, 80 | openInCenter: false, 81 | zoomLevel: 1, 82 | forceIframe: false, 83 | customCss: `/* hide the help, home, search, and productivity overview buttons, create extra space, and prevent toast pop-up from acting weird */ 84 | [aria-label="Go to Home view"], #quick_find, [aria-label="Productivity"], [aria-label="Help & Feedback"] { 85 | display: none !important; 86 | } 87 | 88 | .view_content { 89 | padding-left: 15px; 90 | } 91 | 92 | .view_header { 93 | padding-left: 15px; 94 | padding-top: 10px; 95 | } 96 | 97 | .undo_toast { 98 | width: 95%; 99 | }`, 100 | customJs: "" 101 | }, 102 | "notion": { 103 | url: "https://www.notion.so/", 104 | displayName: "Notion", 105 | icon: "box", 106 | hideOnMobile: true, 107 | addRibbonIcon: true, 108 | openInCenter: true, 109 | zoomLevel: 1, 110 | forceIframe: false, 111 | customCss: "", 112 | customJs: "" 113 | }, 114 | "twitter": { 115 | url: "https://twitter.com", 116 | displayName: "Twitter", 117 | icon: "twitter", 118 | hideOnMobile: true, 119 | addRibbonIcon: false, 120 | openInCenter: false, 121 | zoomLevel: 1, 122 | forceIframe: false, 123 | customCss: "", 124 | customJs: "" 125 | }, 126 | "tasks": { 127 | url: "https://tasks.google.com/embed/?origin=https://calendar.google.com&fullWidth=1", 128 | displayName: "Google Tasks", 129 | icon: "list-checks", 130 | hideOnMobile: true, 131 | addRibbonIcon: false, 132 | openInCenter: false, 133 | zoomLevel: 1, 134 | forceIframe: false, 135 | customCss: "", 136 | customJs: "" 137 | }, 138 | "readwise-daily-review": { 139 | "url": "https://readwise.io/dailyreview", 140 | "displayName": "Readwise Daily Review", 141 | "icon": "highlighter", 142 | "hideOnMobile": true, 143 | "addRibbonIcon": false, 144 | "openInCenter": false, 145 | "zoomLevel": 1, 146 | "forceIframe": false, 147 | "customCss": ".fixed-nav {\n display: none !important;\n}", 148 | "customJs": "" 149 | }, 150 | }; 151 | 152 | export interface CustomFramesSettings { 153 | frames: CustomFrameSettings[]; 154 | padding: number; 155 | } 156 | 157 | export interface CustomFrameSettings { 158 | url: string; 159 | displayName: string; 160 | icon: string; 161 | hideOnMobile: boolean; 162 | addRibbonIcon: boolean; 163 | openInCenter: boolean; 164 | zoomLevel: number; 165 | forceIframe: boolean; 166 | customCss: string; 167 | customJs: string; 168 | } 169 | 170 | export function getIcon(settings: CustomFrameSettings) { 171 | return settings.icon ? `lucide-${settings.icon}` : "documents"; 172 | } 173 | 174 | export function getId(settings: CustomFrameSettings) { 175 | return settings.displayName.toLowerCase().replace(/\s/g, "-"); 176 | } 177 | -------------------------------------------------------------------------------- /src/view.ts: -------------------------------------------------------------------------------- 1 | import { ItemView, WorkspaceLeaf, Menu } from "obsidian"; 2 | import { CustomFrame } from "./frame"; 3 | import { CustomFrameSettings, CustomFramesSettings, getIcon } from "./settings"; 4 | 5 | export class CustomFrameView extends ItemView { 6 | 7 | private static readonly actions: Action[] = [ 8 | { 9 | name: "Return to original page", 10 | icon: "home", 11 | action: v => v.frame.return() 12 | }, { 13 | name: "Open dev tools", 14 | icon: "binary", 15 | action: v => v.frame.toggleDevTools() 16 | }, { 17 | name: "Copy link", 18 | icon: "link", 19 | action: v => navigator.clipboard.writeText(v.frame.getCurrentUrl()) 20 | }, { 21 | name: "Open in browser", 22 | icon: "globe", 23 | action: v => open(v.frame.getCurrentUrl()) 24 | }, { 25 | name: "Refresh", 26 | icon: "refresh-cw", 27 | action: v => v.frame.refresh() 28 | }, { 29 | name: "Go forward", 30 | icon: "arrow-right", 31 | action: v => v.frame.goForward() 32 | }, { 33 | name: "Go back", 34 | icon: "arrow-left", 35 | action: v => v.frame.goBack() 36 | } 37 | ]; 38 | 39 | private readonly data: CustomFrameSettings; 40 | private readonly name: string; 41 | private frame: CustomFrame; 42 | 43 | constructor(leaf: WorkspaceLeaf, settings: CustomFramesSettings, data: CustomFrameSettings, name: string) { 44 | super(leaf); 45 | this.data = data; 46 | this.name = name; 47 | this.frame = new CustomFrame(settings, data); 48 | this.navigation = data.openInCenter; 49 | 50 | for (let action of CustomFrameView.actions) 51 | this.addAction(action.icon, action.name, () => action.action(this)); 52 | } 53 | 54 | onload(): void { 55 | this.contentEl.empty(); 56 | this.contentEl.addClass("custom-frames-view"); 57 | this.frame.create(this.contentEl); 58 | } 59 | 60 | onPaneMenu(menu: Menu, source: string): void { 61 | super.onPaneMenu(menu, source); 62 | for (let action of CustomFrameView.actions) { 63 | menu.addItem(i => { 64 | i.setTitle(action.name); 65 | i.setIcon(action.icon); 66 | i.onClick(() => action.action(this)); 67 | }); 68 | } 69 | } 70 | 71 | getViewType(): string { 72 | return this.name; 73 | } 74 | 75 | getDisplayText(): string { 76 | return this.data.displayName; 77 | } 78 | 79 | getIcon(): string { 80 | return getIcon(this.data); 81 | } 82 | 83 | focus(): void { 84 | this.frame.focus(); 85 | } 86 | } 87 | 88 | interface Action { 89 | name: string; 90 | icon: string; 91 | action: (view: CustomFrameView) => any; 92 | } 93 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .custom-frames-view { 2 | padding: 0 !important; 3 | overflow: hidden !important; 4 | } 5 | 6 | .custom-frames-view-file { 7 | padding: 0; 8 | overflow: auto; 9 | } 10 | 11 | .custom-frames-frame { 12 | width: 100%; 13 | height: 100%; 14 | border: none; 15 | background-color: white; 16 | background-clip: content-box; 17 | } 18 | 19 | .custom-frames-add { 20 | margin-left: 10px; 21 | } 22 | 23 | .custom-frames-show { 24 | margin-bottom: 18px; 25 | } 26 | 27 | .custom-frames-support { 28 | width: 100%; 29 | height: auto; 30 | } 31 | -------------------------------------------------------------------------------- /test-vault/.obsidian/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "promptDelete": false 3 | } -------------------------------------------------------------------------------- /test-vault/.obsidian/appearance.json: -------------------------------------------------------------------------------- 1 | { 2 | "accentColor": "" 3 | } -------------------------------------------------------------------------------- /test-vault/.obsidian/community-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "obsidian-custom-frames" 3 | ] -------------------------------------------------------------------------------- /test-vault/.obsidian/core-plugins-migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "file-explorer": true, 3 | "global-search": true, 4 | "switcher": true, 5 | "graph": true, 6 | "backlink": true, 7 | "outgoing-link": true, 8 | "tag-pane": true, 9 | "page-preview": true, 10 | "daily-notes": true, 11 | "templates": true, 12 | "note-composer": true, 13 | "command-palette": true, 14 | "slash-command": false, 15 | "editor-status": true, 16 | "starred": true, 17 | "markdown-importer": false, 18 | "zk-prefixer": false, 19 | "random-note": false, 20 | "outline": true, 21 | "word-count": true, 22 | "slides": false, 23 | "audio-recorder": false, 24 | "workspaces": false, 25 | "file-recovery": true, 26 | "publish": false, 27 | "sync": false, 28 | "canvas": true, 29 | "bookmarks": true 30 | } -------------------------------------------------------------------------------- /test-vault/.obsidian/core-plugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "file-explorer": true, 3 | "global-search": true, 4 | "switcher": true, 5 | "graph": true, 6 | "backlink": true, 7 | "outgoing-link": true, 8 | "tag-pane": true, 9 | "page-preview": true, 10 | "daily-notes": true, 11 | "templates": true, 12 | "note-composer": true, 13 | "command-palette": true, 14 | "slash-command": false, 15 | "editor-status": true, 16 | "starred": true, 17 | "markdown-importer": false, 18 | "zk-prefixer": false, 19 | "random-note": false, 20 | "outline": true, 21 | "word-count": true, 22 | "slides": false, 23 | "audio-recorder": false, 24 | "workspaces": false, 25 | "file-recovery": true, 26 | "publish": false, 27 | "sync": false, 28 | "canvas": true, 29 | "bookmarks": true, 30 | "properties": false, 31 | "webviewer": true 32 | } -------------------------------------------------------------------------------- /test-vault/.obsidian/graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "collapse-filter": true, 3 | "search": "", 4 | "showTags": false, 5 | "showAttachments": false, 6 | "hideUnresolved": false, 7 | "showOrphans": true, 8 | "collapse-color-groups": true, 9 | "colorGroups": [], 10 | "collapse-display": true, 11 | "showArrow": false, 12 | "textFadeMultiplier": 0, 13 | "nodeSizeMultiplier": 1, 14 | "lineSizeMultiplier": 1, 15 | "collapse-forces": true, 16 | "centerStrength": 0.518713248970312, 17 | "repelStrength": 10, 18 | "linkStrength": 1, 19 | "linkDistance": 250, 20 | "scale": 1, 21 | "close": false 22 | } -------------------------------------------------------------------------------- /test-vault/.obsidian/hotkeys.json: -------------------------------------------------------------------------------- 1 | { 2 | "app:reload": [ 3 | { 4 | "modifiers": [ 5 | "Mod", 6 | "Shift" 7 | ], 8 | "key": "R" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /test-vault/.obsidian/plugins/obsidian-custom-frames/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !data.json 4 | -------------------------------------------------------------------------------- /test-vault/.obsidian/plugins/obsidian-custom-frames/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "frames": [ 3 | { 4 | "url": "https://forum.obsidian.md/", 5 | "displayName": "Obsidian Forum", 6 | "icon": "edit", 7 | "hideOnMobile": true, 8 | "addRibbonIcon": true, 9 | "openInCenter": true, 10 | "zoomLevel": 1, 11 | "forceIframe": false, 12 | "customCss": "" 13 | }, 14 | { 15 | "url": "https://keep.google.com", 16 | "displayName": "Google Keep", 17 | "icon": "files", 18 | "hideOnMobile": true, 19 | "addRibbonIcon": false, 20 | "openInCenter": false, 21 | "zoomLevel": 1, 22 | "forceIframe": false, 23 | "customCss": "/* hide the menu bar, the \"Keep\" text and the Google Apps button */\nhtml > body > div:nth-child(2) > div:nth-child(2) > div:first-child, \nhtml > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child > span, \nhtml > body > div:first-child > header:first-child > div:nth-child(2) > div:first-child > div:first-child, \nhtml > body > div:first-child > header:first-child > div:nth-child(2) > div:nth-child(3) > div:first-child > div:first-child > div:first-child { \n\tdisplay: none !important; \n}\nhtml > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child {\n\tcursor: default; \n}" 24 | }, 25 | { 26 | "url": "https://calendar.google.com/calendar", 27 | "displayName": "Google Calendar", 28 | "icon": "calendar", 29 | "hideOnMobile": true, 30 | "addRibbonIcon": true, 31 | "openInCenter": true, 32 | "zoomLevel": 1, 33 | "forceIframe": false, 34 | "customCss": "/* hide the menu bar, \"Keep\" text, and logo */\nhtml > body > div:nth-child(2) > div:nth-child(2) > div:first-child[class*=\" \"],\nhtml > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child,\nhtml > body > div:nth-child(2) > div:nth-child(2) > div:first-child > div:first-child {\ndisplay: none !important;\n}" 35 | }, 36 | { 37 | "url": "https://scholar.google.com", 38 | "displayName": "Scholar", 39 | "icon": "book", 40 | "hideOnMobile": false, 41 | "addRibbonIcon": true, 42 | "openInCenter": false, 43 | "zoomLevel": 1, 44 | "forceIframe": false, 45 | "customCss": "" 46 | } 47 | ], 48 | "padding": 5 49 | } 50 | -------------------------------------------------------------------------------- /test-vault/Untitled.canvas: -------------------------------------------------------------------------------- 1 | { 2 | "nodes":[ 3 | {"id":"98d23d47aafe2b68","x":-480,"y":-360,"width":795,"height":535,"type":"link","url":"https://calendar.google.com"} 4 | ], 5 | "edges":[] 6 | } -------------------------------------------------------------------------------- /test-vault/note.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/ObsidianCustomFrames/be1c5c1610b0d11d85e8160a4ca7b0178e84b0ee/test-vault/note.md -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "ES6", 8 | "allowJs": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "isolatedModules": true, 13 | "lib": [ 14 | "DOM", 15 | "ES5", 16 | "ES6", 17 | "ES7" 18 | ] 19 | }, 20 | "include": [ 21 | "**/*.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "2.0.0": "0.13.33", 3 | "2.0.1": "0.13.33", 4 | "2.1.0": "0.13.33", 5 | "2.2.0": "0.14.3", 6 | "2.2.1": "0.14.3", 7 | "2.2.2": "0.14.3", 8 | "2.3.0": "0.14.5", 9 | "2.4.0": "0.14.5", 10 | "2.4.1": "0.14.5", 11 | "2.4.2": "0.14.5", 12 | "2.4.3": "0.15.5", 13 | "2.4.4": "0.16.0", 14 | "2.4.5": "1.1.0", 15 | "2.4.6": "1.2.0", 16 | "2.4.7": "1.2.0", 17 | "2.5.0": "1.2.0" 18 | } 19 | --------------------------------------------------------------------------------