├── .gitignore ├── .node-version ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── cosense.ts ├── index.ts ├── routes │ ├── handlers │ │ ├── create-page.ts │ │ ├── get-page.ts │ │ ├── list-pages.ts │ │ └── search-pages.ts │ └── index.ts ├── types │ ├── api.ts │ ├── common.ts │ ├── config.ts │ ├── error.ts │ └── handlers.ts └── utils │ ├── format.ts │ ├── markdown-converter.ts │ └── sort.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | memory-bank/ 2 | 3 | .github/ 4 | .vscode/ 5 | .cursorrules 6 | .clinerules 7 | node_modules/ 8 | build/ 9 | *.log 10 | .env* 11 | .DS_Store 12 | .vscode/ -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 20.11.1 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 worldnine 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 | # scrapbox-cosense-mcp 2 | 3 | [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/worldnine-scrapbox-cosense-mcp-badge.png)](https://mseep.ai/app/worldnine-scrapbox-cosense-mcp) 4 | 5 | Scrapbox Cosense Server MCP server 6 | 7 | 8 | [English](#english) | [日本語](#日本語) 9 | 10 | ## English 11 | 12 | MCP server for [cosense/scrapbox](https://cosen.se). 13 | 14 | ### Features 15 | 16 | - `get_page` 17 | - Get page content from cosense/Scrapbox 18 | - Input: Page title 19 | - Output: Page content, metadata, links, and editor information 20 | - `list_pages` 21 | - Get a list of pages in the project (max 1000 pages) 22 | - Output: List of page titles in the project 23 | - `search_pages` 24 | - Full-text search across all pages in the project (max 100 pages) 25 | - Supports basic search, AND search, OR search, and NOT search 26 | - Output: List of page titles in search results 27 | - `create_pages` 28 | - Generate page URLs 29 | - Input: Page title and optional body text 30 | - Output: URL that can be opened in a browser 31 | 32 | ### Development 33 | 34 | Install dependencies: 35 | 36 | ```bash 37 | npm install 38 | ``` 39 | 40 | Build the server: 41 | 42 | ```bash 43 | npm run build 44 | ``` 45 | 46 | Auto-rebuild during development: 47 | 48 | ```bash 49 | npm run watch 50 | ``` 51 | 52 | ### Installation 53 | 54 | ```bash 55 | git clone https://github.com/worldnine/scrapbox-cosense-mcp.git 56 | cd scrapbox-cosense-mcp 57 | npm install 58 | npm run build 59 | ``` 60 | 61 | To use with Claude Desktop, add the server configuration as follows: 62 | 63 | For MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json` 64 | For Windows: `%APPDATA%/Claude/claude_desktop_config.json` 65 | 66 | ```json 67 | { 68 | "mcpServers": { 69 | "scrapbox-cosense-mcp": { 70 | "command": "npx", 71 | "args": ["github:worldnine/scrapbox-cosense-mcp"], 72 | "env": { 73 | "COSENSE_PROJECT_NAME": "your_project_name", 74 | "COSENSE_SID": "your_sid", // Required for private projects 75 | "COSENSE_PAGE_LIMIT": "25", // Optional (default: 100) 76 | "COSENSE_SORT_METHOD": "created", // Optional (default: "updated") 77 | "SERVICE_LABEL": "scrapbox(cosense)" // Optional (default: "cosense(scrapbox)") 78 | } 79 | } 80 | } 81 | } 82 | ``` 83 | 84 | ### Environment Variables 85 | 86 | This server uses the following environment variables: 87 | 88 | #### Required Environment Variables 89 | 90 | - `COSENSE_PROJECT_NAME`: Project name 91 | - `COSENSE_SID`: Session ID for Scrapbox/Cosense authentication (required for private projects) 92 | 93 | #### Optional Environment Variables 94 | 95 | - `API_DOMAIN`: API domain (default: "scrapbox.io") 96 | - `SERVICE_LABEL`: Service identifier (default: "cosense (scrapbox)") 97 | - `COSENSE_PAGE_LIMIT`: Initial page fetch limit (1-1000, default: 100) 98 | - `COSENSE_SORT_METHOD`: Initial page fetch order (updated/created/accessed/linked/views/title, default: updated) 99 | 100 | #### Environment Variable Behavior 101 | 102 | - **COSENSE_PROJECT_NAME**: Required environment variable. Server will exit with an error if not set. 103 | - **COSENSE_SID**: Required for accessing private projects. If not set, only public projects are accessible. 104 | - **API_DOMAIN**: 105 | - Uses "scrapbox.io" if not set 106 | - While unverified with domains other than "scrapbox.io" in the author's environment, this option exists in case some environments require "cosen.se" 107 | - **COSENSE_PAGE_LIMIT**: 108 | - Uses 100 if not set 109 | - Uses 100 if value is invalid (non-numeric or out of range) 110 | - Valid range: 1-1000 111 | - **COSENSE_SORT_METHOD**: 112 | - Uses 'updated' if not set 113 | - Uses 'updated' if value is invalid 114 | - Does not affect list_pages tool behavior (only used for initial resource fetch) 115 | 116 | ### Debugging 117 | 118 | Since MCP servers communicate via stdio, debugging can be challenging. Using [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is recommended. You can run it with: 119 | 120 | ```bash 121 | npm run inspector 122 | ``` 123 | 124 | The Inspector provides a URL to access debugging tools in the browser. 125 | 126 | ## 日本語 127 | 128 | [cosense/scrapbox](https://cosen.se) 用のMCPサーバーです。 129 | 130 | ## 機能 131 | 132 | - `get_page` 133 | - cosense/Scrapboxからページコンテンツを取得 134 | - 入力: ページタイトル 135 | - 出力: ページコンテンツ、メタデータ、リンク、編集者の情報 136 | - `list_pages` 137 | - プロジェクト内のページ一覧を取得(最大1000件) 138 | - 出力: プロジェクト内のページタイトル一覧 139 | - `search_pages` 140 | - プロジェクト内のページ全体を対象とした全文検索(最大100件) 141 | - 基本検索、AND検索、OR検索、NOT検索をサポート 142 | - 出力: 検索結果のページタイトル一覧 143 | - `create_pages` 144 | - ページのURLを生成 145 | - 入力: ページタイトルとオプションの本文テキスト 146 | - 出力: ブラウザで開くことができるURL 147 | 148 | ## 開発方法 149 | 150 | 依存関係のインストール: 151 | 152 | ```bash 153 | npm install 154 | ``` 155 | 156 | サーバーのビルド: 157 | 158 | ```bash 159 | npm run build 160 | ``` 161 | 162 | 開発時の自動リビルド: 163 | 164 | ```bash 165 | npm run watch 166 | ``` 167 | 168 | ## インストール方法 169 | 170 | ```bash 171 | git clone https://github.com/worldnine/scrapbox-cosense-mcp.git 172 | cd scrapbox-cosense-mcp 173 | npm install 174 | npm run build 175 | ``` 176 | 177 | Claude Desktopで使用するには、以下のようにサーバー設定を追加してください: 178 | 179 | MacOSの場合: `~/Library/Application\ Support/Claude/claude_desktop_config.json` 180 | Windowsの場合: `%APPDATA%/Claude/claude_desktop_config.json` 181 | 182 | ```json 183 | { 184 | "mcpServers": { 185 | "scrapbox-cosense-mcp": { 186 | "command": "npx", 187 | "args": ["github:worldnine/scrapbox-cosense-mcp"], 188 | "env": { 189 | "COSENSE_PROJECT_NAME": "your_project_name", 190 | "COSENSE_SID": "your_sid", // プライベートプロジェクトの場合は必須 191 | "COSENSE_PAGE_LIMIT": "25", // オプション(デフォルト: 100) 192 | "COSENSE_SORT_METHOD": "created", // オプション(デフォルト: "updated") 193 | "SERVICE_LABEL": "scrapbox(cosense)" // オプション(デフォルト: "cosense(scrapbox)") 194 | } 195 | } 196 | } 197 | } 198 | ``` 199 | 200 | ## 環境変数 201 | 202 | このサーバーは以下の環境変数を使用します: 203 | 204 | ### 必須の環境変数 205 | 206 | - `COSENSE_PROJECT_NAME`: プロジェクト名 207 | - `COSENSE_SID`: Scrapbox/Cosenseの認証用セッションID(プライベートプロジェクトの場合は必須) 208 | 209 | ### オプションの環境変数 210 | 211 | - `API_DOMAIN`: APIドメイン(デフォルト: "scrapbox.io") 212 | - `SERVICE_LABEL`: サービスの識別名(デフォルト: "cosense (scrapbox)") 213 | - `COSENSE_PAGE_LIMIT`: 初期取得時のページ数(1-1000、デフォルト: 100) 214 | - `COSENSE_SORT_METHOD`: 初期取得時の取得ページ順(updated/created/accessed/linked/views/title、デフォルト: updated) 215 | 216 | ### 環境変数の挙動について 217 | 218 | - **COSENSE_PROJECT_NAME**: 必須の環境変数です。未設定の場合、サーバーは起動時にエラーで終了します。 219 | - **COSENSE_SID**: プライベートプロジェクトへのアクセスに必要です。未設定の場合、パブリックプロジェクトのみアクセス可能です。 220 | - **API_DOMAIN**: 221 | - 未設定時は"scrapbox.io"を使用 222 | - 作者の環境では"scrapbox.io"以外の値は未検証ですが、"cosen.se"でないと動作しない環境が存在する可能性があるため念のためのオプションです。 223 | - **COSENSE_PAGE_LIMIT**: 224 | - 未設定時は100を使用 225 | - 無効な値(数値以外や範囲外)の場合は100を使用 226 | - 有効範囲: 1-1000 227 | - **COSENSE_SORT_METHOD**: 228 | - 未設定時は'updated'を使用 229 | - 無効な値の場合は'updated'を使用 230 | - list_pagesツールの動作には影響しません(初期リソース取得時のみ使用) 231 | 232 | ### デバッグ方法 233 | 234 | MCPサーバーはstdioを介して通信を行うため、デバッグが難しい場合があります。[MCP Inspector](https://github.com/modelcontextprotocol/inspector)の使用を推奨します。以下のコマンドで実行できます: 235 | 236 | ```bash 237 | npm run inspector 238 | ``` 239 | 240 | InspectorはブラウザでデバッグツールにアクセスするためのURLを提供します。 241 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrapbox-cosense-mcp", 3 | "version": "0.1.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "scrapbox-cosense-mcp", 9 | "version": "0.1.0", 10 | "dependencies": { 11 | "@modelcontextprotocol/sdk": "0.6.0", 12 | "@whatwg-node/fetch": "^0.10.1", 13 | "md2sb": "^5.1.2" 14 | }, 15 | "bin": { 16 | "cosense-mcp-server": "build/index.js" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20.11.24", 20 | "typescript": "^5.3.3" 21 | } 22 | }, 23 | "node_modules/@modelcontextprotocol/sdk": { 24 | "version": "0.6.0", 25 | "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.6.0.tgz", 26 | "integrity": "sha512-9rsDudGhDtMbvxohPoMMyAUOmEzQsOK+XFchh6gZGqo8sx9sBuZQs+CUttXqa8RZXKDaJRCN2tUtgGof7jRkkw==", 27 | "license": "MIT", 28 | "dependencies": { 29 | "content-type": "^1.0.5", 30 | "raw-body": "^3.0.0", 31 | "zod": "^3.23.8" 32 | } 33 | }, 34 | "node_modules/@types/mdast": { 35 | "version": "3.0.15", 36 | "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", 37 | "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", 38 | "license": "MIT", 39 | "dependencies": { 40 | "@types/unist": "^2" 41 | } 42 | }, 43 | "node_modules/@types/node": { 44 | "version": "20.17.12", 45 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz", 46 | "integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==", 47 | "dev": true, 48 | "license": "MIT", 49 | "dependencies": { 50 | "undici-types": "~6.19.2" 51 | } 52 | }, 53 | "node_modules/@types/unist": { 54 | "version": "2.0.11", 55 | "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", 56 | "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", 57 | "license": "MIT" 58 | }, 59 | "node_modules/@whatwg-node/disposablestack": { 60 | "version": "0.0.5", 61 | "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.5.tgz", 62 | "integrity": "sha512-9lXugdknoIequO4OYvIjhygvfSEgnO8oASLqLelnDhkRjgBZhc39shC3QSlZuyDO9bgYSIVa2cHAiN+St3ty4w==", 63 | "license": "MIT", 64 | "dependencies": { 65 | "tslib": "^2.6.3" 66 | }, 67 | "engines": { 68 | "node": ">=18.0.0" 69 | } 70 | }, 71 | "node_modules/@whatwg-node/fetch": { 72 | "version": "0.10.3", 73 | "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.3.tgz", 74 | "integrity": "sha512-jCTL/qYcIW2GihbBRHypQ/Us7saWMNZ5fsumsta+qPY0Pmi1ccba/KRQvgctmQsbP69FWemJSs8zVcFaNwdL0w==", 75 | "license": "MIT", 76 | "dependencies": { 77 | "@whatwg-node/node-fetch": "^0.7.7", 78 | "urlpattern-polyfill": "^10.0.0" 79 | }, 80 | "engines": { 81 | "node": ">=18.0.0" 82 | } 83 | }, 84 | "node_modules/@whatwg-node/node-fetch": { 85 | "version": "0.7.7", 86 | "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.7.tgz", 87 | "integrity": "sha512-BDbIMOenThOTFDBLh1WscgBNAxfDAdAdd9sMG8Ff83hYxApJVbqEct38bUAj+zn8bTsfBx/lyfnVOTyq5xUlvg==", 88 | "license": "MIT", 89 | "dependencies": { 90 | "@whatwg-node/disposablestack": "^0.0.5", 91 | "busboy": "^1.6.0", 92 | "tslib": "^2.6.3" 93 | }, 94 | "engines": { 95 | "node": ">=18.0.0" 96 | } 97 | }, 98 | "node_modules/ajv": { 99 | "version": "6.12.6", 100 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 101 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 102 | "license": "MIT", 103 | "dependencies": { 104 | "fast-deep-equal": "^3.1.1", 105 | "fast-json-stable-stringify": "^2.0.0", 106 | "json-schema-traverse": "^0.4.1", 107 | "uri-js": "^4.2.2" 108 | }, 109 | "funding": { 110 | "type": "github", 111 | "url": "https://github.com/sponsors/epoberezkin" 112 | } 113 | }, 114 | "node_modules/arg": { 115 | "version": "4.1.3", 116 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 117 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 118 | "license": "MIT" 119 | }, 120 | "node_modules/asn1": { 121 | "version": "0.2.6", 122 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", 123 | "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", 124 | "license": "MIT", 125 | "dependencies": { 126 | "safer-buffer": "~2.1.0" 127 | } 128 | }, 129 | "node_modules/assert-plus": { 130 | "version": "1.0.0", 131 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 132 | "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", 133 | "license": "MIT", 134 | "engines": { 135 | "node": ">=0.8" 136 | } 137 | }, 138 | "node_modules/asynckit": { 139 | "version": "0.4.0", 140 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 141 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 142 | "license": "MIT" 143 | }, 144 | "node_modules/aws-sign2": { 145 | "version": "0.7.0", 146 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 147 | "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", 148 | "license": "Apache-2.0", 149 | "engines": { 150 | "node": "*" 151 | } 152 | }, 153 | "node_modules/aws4": { 154 | "version": "1.13.2", 155 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", 156 | "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", 157 | "license": "MIT" 158 | }, 159 | "node_modules/bail": { 160 | "version": "1.0.5", 161 | "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", 162 | "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", 163 | "license": "MIT", 164 | "funding": { 165 | "type": "github", 166 | "url": "https://github.com/sponsors/wooorm" 167 | } 168 | }, 169 | "node_modules/bcrypt-pbkdf": { 170 | "version": "1.0.2", 171 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 172 | "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", 173 | "license": "BSD-3-Clause", 174 | "dependencies": { 175 | "tweetnacl": "^0.14.3" 176 | } 177 | }, 178 | "node_modules/buffer-from": { 179 | "version": "1.1.2", 180 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 181 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 182 | "license": "MIT" 183 | }, 184 | "node_modules/busboy": { 185 | "version": "1.6.0", 186 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", 187 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", 188 | "dependencies": { 189 | "streamsearch": "^1.1.0" 190 | }, 191 | "engines": { 192 | "node": ">=10.16.0" 193 | } 194 | }, 195 | "node_modules/bytes": { 196 | "version": "3.1.2", 197 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 198 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 199 | "license": "MIT", 200 | "engines": { 201 | "node": ">= 0.8" 202 | } 203 | }, 204 | "node_modules/caseless": { 205 | "version": "0.12.0", 206 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 207 | "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", 208 | "license": "Apache-2.0" 209 | }, 210 | "node_modules/ccount": { 211 | "version": "1.1.0", 212 | "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", 213 | "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", 214 | "license": "MIT", 215 | "funding": { 216 | "type": "github", 217 | "url": "https://github.com/sponsors/wooorm" 218 | } 219 | }, 220 | "node_modules/character-entities": { 221 | "version": "1.2.4", 222 | "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", 223 | "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", 224 | "license": "MIT", 225 | "funding": { 226 | "type": "github", 227 | "url": "https://github.com/sponsors/wooorm" 228 | } 229 | }, 230 | "node_modules/character-entities-legacy": { 231 | "version": "1.1.4", 232 | "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", 233 | "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", 234 | "license": "MIT", 235 | "funding": { 236 | "type": "github", 237 | "url": "https://github.com/sponsors/wooorm" 238 | } 239 | }, 240 | "node_modules/character-reference-invalid": { 241 | "version": "1.1.4", 242 | "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", 243 | "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", 244 | "license": "MIT", 245 | "funding": { 246 | "type": "github", 247 | "url": "https://github.com/sponsors/wooorm" 248 | } 249 | }, 250 | "node_modules/combined-stream": { 251 | "version": "1.0.8", 252 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 253 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 254 | "license": "MIT", 255 | "dependencies": { 256 | "delayed-stream": "~1.0.0" 257 | }, 258 | "engines": { 259 | "node": ">= 0.8" 260 | } 261 | }, 262 | "node_modules/commander": { 263 | "version": "5.1.0", 264 | "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", 265 | "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", 266 | "license": "MIT", 267 | "engines": { 268 | "node": ">= 6" 269 | } 270 | }, 271 | "node_modules/component-emitter": { 272 | "version": "1.3.1", 273 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", 274 | "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", 275 | "license": "MIT", 276 | "funding": { 277 | "url": "https://github.com/sponsors/sindresorhus" 278 | } 279 | }, 280 | "node_modules/content-type": { 281 | "version": "1.0.5", 282 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 283 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 284 | "license": "MIT", 285 | "engines": { 286 | "node": ">= 0.6" 287 | } 288 | }, 289 | "node_modules/cookiejar": { 290 | "version": "2.1.4", 291 | "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", 292 | "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", 293 | "license": "MIT" 294 | }, 295 | "node_modules/core-util-is": { 296 | "version": "1.0.3", 297 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 298 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 299 | "license": "MIT" 300 | }, 301 | "node_modules/dashdash": { 302 | "version": "1.14.1", 303 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 304 | "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", 305 | "license": "MIT", 306 | "dependencies": { 307 | "assert-plus": "^1.0.0" 308 | }, 309 | "engines": { 310 | "node": ">=0.10" 311 | } 312 | }, 313 | "node_modules/debug": { 314 | "version": "4.4.0", 315 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 316 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 317 | "license": "MIT", 318 | "dependencies": { 319 | "ms": "^2.1.3" 320 | }, 321 | "engines": { 322 | "node": ">=6.0" 323 | }, 324 | "peerDependenciesMeta": { 325 | "supports-color": { 326 | "optional": true 327 | } 328 | } 329 | }, 330 | "node_modules/delayed-stream": { 331 | "version": "1.0.0", 332 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 333 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 334 | "license": "MIT", 335 | "engines": { 336 | "node": ">=0.4.0" 337 | } 338 | }, 339 | "node_modules/depd": { 340 | "version": "2.0.0", 341 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 342 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 343 | "license": "MIT", 344 | "engines": { 345 | "node": ">= 0.8" 346 | } 347 | }, 348 | "node_modules/diff": { 349 | "version": "4.0.2", 350 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 351 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 352 | "license": "BSD-3-Clause", 353 | "engines": { 354 | "node": ">=0.3.1" 355 | } 356 | }, 357 | "node_modules/dom-serializer": { 358 | "version": "1.4.1", 359 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", 360 | "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", 361 | "license": "MIT", 362 | "dependencies": { 363 | "domelementtype": "^2.0.1", 364 | "domhandler": "^4.2.0", 365 | "entities": "^2.0.0" 366 | }, 367 | "funding": { 368 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" 369 | } 370 | }, 371 | "node_modules/dom-serializer/node_modules/domhandler": { 372 | "version": "4.3.1", 373 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", 374 | "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", 375 | "license": "BSD-2-Clause", 376 | "dependencies": { 377 | "domelementtype": "^2.2.0" 378 | }, 379 | "engines": { 380 | "node": ">= 4" 381 | }, 382 | "funding": { 383 | "url": "https://github.com/fb55/domhandler?sponsor=1" 384 | } 385 | }, 386 | "node_modules/domelementtype": { 387 | "version": "2.3.0", 388 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", 389 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", 390 | "funding": [ 391 | { 392 | "type": "github", 393 | "url": "https://github.com/sponsors/fb55" 394 | } 395 | ], 396 | "license": "BSD-2-Clause" 397 | }, 398 | "node_modules/domhandler": { 399 | "version": "3.3.0", 400 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", 401 | "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", 402 | "license": "BSD-2-Clause", 403 | "dependencies": { 404 | "domelementtype": "^2.0.1" 405 | }, 406 | "engines": { 407 | "node": ">= 4" 408 | }, 409 | "funding": { 410 | "url": "https://github.com/fb55/domhandler?sponsor=1" 411 | } 412 | }, 413 | "node_modules/domutils": { 414 | "version": "2.8.0", 415 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", 416 | "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", 417 | "license": "BSD-2-Clause", 418 | "dependencies": { 419 | "dom-serializer": "^1.0.1", 420 | "domelementtype": "^2.2.0", 421 | "domhandler": "^4.2.0" 422 | }, 423 | "funding": { 424 | "url": "https://github.com/fb55/domutils?sponsor=1" 425 | } 426 | }, 427 | "node_modules/domutils/node_modules/domhandler": { 428 | "version": "4.3.1", 429 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", 430 | "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", 431 | "license": "BSD-2-Clause", 432 | "dependencies": { 433 | "domelementtype": "^2.2.0" 434 | }, 435 | "engines": { 436 | "node": ">= 4" 437 | }, 438 | "funding": { 439 | "url": "https://github.com/fb55/domhandler?sponsor=1" 440 | } 441 | }, 442 | "node_modules/ecc-jsbn": { 443 | "version": "0.1.2", 444 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 445 | "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", 446 | "license": "MIT", 447 | "dependencies": { 448 | "jsbn": "~0.1.0", 449 | "safer-buffer": "^2.1.0" 450 | } 451 | }, 452 | "node_modules/enex2sb": { 453 | "version": "5.1.2", 454 | "resolved": "https://registry.npmjs.org/enex2sb/-/enex2sb-5.1.2.tgz", 455 | "integrity": "sha512-+tf/RHSjKUuW3x5W2aHaueou05EnhbAE0VYkrfE6mFh98mJU3nARFH26oyT9RJU3pbz1TOGYLT67ADgiB2yYPw==", 456 | "license": "MIT", 457 | "dependencies": { 458 | "commander": "^5.1.0", 459 | "gyazo-api": "^0.3.1", 460 | "gyazo-browser-upload": "^1.0.0", 461 | "html2sb-compiler": "^5.1.2", 462 | "into-stream": "^3.1.0", 463 | "ts-node": "^8.10.1" 464 | }, 465 | "bin": { 466 | "enex2sb": "dist/command/index.js" 467 | } 468 | }, 469 | "node_modules/entities": { 470 | "version": "2.2.0", 471 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", 472 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", 473 | "license": "BSD-2-Clause", 474 | "funding": { 475 | "url": "https://github.com/fb55/entities?sponsor=1" 476 | } 477 | }, 478 | "node_modules/escape-string-regexp": { 479 | "version": "4.0.0", 480 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 481 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 482 | "license": "MIT", 483 | "engines": { 484 | "node": ">=10" 485 | }, 486 | "funding": { 487 | "url": "https://github.com/sponsors/sindresorhus" 488 | } 489 | }, 490 | "node_modules/extend": { 491 | "version": "3.0.2", 492 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 493 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", 494 | "license": "MIT" 495 | }, 496 | "node_modules/extsprintf": { 497 | "version": "1.3.0", 498 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 499 | "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", 500 | "engines": [ 501 | "node >=0.6.0" 502 | ], 503 | "license": "MIT" 504 | }, 505 | "node_modules/fast-deep-equal": { 506 | "version": "3.1.3", 507 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 508 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 509 | "license": "MIT" 510 | }, 511 | "node_modules/fast-json-stable-stringify": { 512 | "version": "2.1.0", 513 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 514 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 515 | "license": "MIT" 516 | }, 517 | "node_modules/forever-agent": { 518 | "version": "0.6.1", 519 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 520 | "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", 521 | "license": "Apache-2.0", 522 | "engines": { 523 | "node": "*" 524 | } 525 | }, 526 | "node_modules/form-data": { 527 | "version": "2.3.3", 528 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 529 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 530 | "license": "MIT", 531 | "dependencies": { 532 | "asynckit": "^0.4.0", 533 | "combined-stream": "^1.0.6", 534 | "mime-types": "^2.1.12" 535 | }, 536 | "engines": { 537 | "node": ">= 0.12" 538 | } 539 | }, 540 | "node_modules/formidable": { 541 | "version": "1.2.6", 542 | "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", 543 | "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", 544 | "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", 545 | "license": "MIT", 546 | "funding": { 547 | "url": "https://ko-fi.com/tunnckoCore/commissions" 548 | } 549 | }, 550 | "node_modules/from2": { 551 | "version": "2.3.0", 552 | "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", 553 | "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", 554 | "license": "MIT", 555 | "dependencies": { 556 | "inherits": "^2.0.1", 557 | "readable-stream": "^2.0.0" 558 | } 559 | }, 560 | "node_modules/getpass": { 561 | "version": "0.1.7", 562 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 563 | "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", 564 | "license": "MIT", 565 | "dependencies": { 566 | "assert-plus": "^1.0.0" 567 | } 568 | }, 569 | "node_modules/gyazo-api": { 570 | "version": "0.3.1", 571 | "resolved": "https://registry.npmjs.org/gyazo-api/-/gyazo-api-0.3.1.tgz", 572 | "integrity": "sha512-vsLi6R4Gtvm5li9u9ducUiJo60NqFzeCyRZBkzOdqtuKzfsBNovIzaM7+fqpuQP7EyJElxkLXE4yme/InXydNg==", 573 | "license": "MIT", 574 | "dependencies": { 575 | "request": "*" 576 | } 577 | }, 578 | "node_modules/gyazo-browser-upload": { 579 | "version": "1.0.0", 580 | "resolved": "https://registry.npmjs.org/gyazo-browser-upload/-/gyazo-browser-upload-1.0.0.tgz", 581 | "integrity": "sha512-UgwthfiMzH2RsYH5trAk0WdqxjmRQiHWgfz14ezf044H4PSuRwLEgc5XmsFo4Ob/h9pRq8oBeVvheqb9Fx/CUA==", 582 | "license": "MIT", 583 | "dependencies": { 584 | "superagent": "^3.5.2" 585 | } 586 | }, 587 | "node_modules/har-schema": { 588 | "version": "2.0.0", 589 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 590 | "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", 591 | "license": "ISC", 592 | "engines": { 593 | "node": ">=4" 594 | } 595 | }, 596 | "node_modules/har-validator": { 597 | "version": "5.1.5", 598 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", 599 | "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", 600 | "deprecated": "this library is no longer supported", 601 | "license": "MIT", 602 | "dependencies": { 603 | "ajv": "^6.12.3", 604 | "har-schema": "^2.0.0" 605 | }, 606 | "engines": { 607 | "node": ">=6" 608 | } 609 | }, 610 | "node_modules/html2sb-compiler": { 611 | "version": "5.1.2", 612 | "resolved": "https://registry.npmjs.org/html2sb-compiler/-/html2sb-compiler-5.1.2.tgz", 613 | "integrity": "sha512-FhcN/5RWY5+oAJvnXDj9Hzvm1ed4QdhhG53XUbzBBgnJJsesrqsxgqf3+v3R5GOo8XYz742RwIVsRBoAWBFKFQ==", 614 | "license": "MIT", 615 | "dependencies": { 616 | "htmlparser2": "^4.0.0", 617 | "lodash.trim": "^4.5.1", 618 | "nano-md5": "^1.0.3", 619 | "style-parser": "^1.1.1" 620 | } 621 | }, 622 | "node_modules/htmlparser2": { 623 | "version": "4.1.0", 624 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", 625 | "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", 626 | "license": "MIT", 627 | "dependencies": { 628 | "domelementtype": "^2.0.1", 629 | "domhandler": "^3.0.0", 630 | "domutils": "^2.0.0", 631 | "entities": "^2.0.0" 632 | } 633 | }, 634 | "node_modules/http-errors": { 635 | "version": "2.0.0", 636 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 637 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 638 | "license": "MIT", 639 | "dependencies": { 640 | "depd": "2.0.0", 641 | "inherits": "2.0.4", 642 | "setprototypeof": "1.2.0", 643 | "statuses": "2.0.1", 644 | "toidentifier": "1.0.1" 645 | }, 646 | "engines": { 647 | "node": ">= 0.8" 648 | } 649 | }, 650 | "node_modules/http-signature": { 651 | "version": "1.2.0", 652 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 653 | "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", 654 | "license": "MIT", 655 | "dependencies": { 656 | "assert-plus": "^1.0.0", 657 | "jsprim": "^1.2.2", 658 | "sshpk": "^1.7.0" 659 | }, 660 | "engines": { 661 | "node": ">=0.8", 662 | "npm": ">=1.3.7" 663 | } 664 | }, 665 | "node_modules/iconv-lite": { 666 | "version": "0.6.3", 667 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 668 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 669 | "license": "MIT", 670 | "dependencies": { 671 | "safer-buffer": ">= 2.1.2 < 3.0.0" 672 | }, 673 | "engines": { 674 | "node": ">=0.10.0" 675 | } 676 | }, 677 | "node_modules/inherits": { 678 | "version": "2.0.4", 679 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 680 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 681 | "license": "ISC" 682 | }, 683 | "node_modules/into-stream": { 684 | "version": "3.1.0", 685 | "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", 686 | "integrity": "sha512-TcdjPibTksa1NQximqep2r17ISRiNE9fwlfbg3F8ANdvP5/yrFTew86VcO//jk4QTaMlbjypPBq76HN2zaKfZQ==", 687 | "license": "MIT", 688 | "dependencies": { 689 | "from2": "^2.1.1", 690 | "p-is-promise": "^1.1.0" 691 | }, 692 | "engines": { 693 | "node": ">=4" 694 | } 695 | }, 696 | "node_modules/is-alphabetical": { 697 | "version": "1.0.4", 698 | "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", 699 | "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", 700 | "license": "MIT", 701 | "funding": { 702 | "type": "github", 703 | "url": "https://github.com/sponsors/wooorm" 704 | } 705 | }, 706 | "node_modules/is-alphanumerical": { 707 | "version": "1.0.4", 708 | "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", 709 | "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", 710 | "license": "MIT", 711 | "dependencies": { 712 | "is-alphabetical": "^1.0.0", 713 | "is-decimal": "^1.0.0" 714 | }, 715 | "funding": { 716 | "type": "github", 717 | "url": "https://github.com/sponsors/wooorm" 718 | } 719 | }, 720 | "node_modules/is-buffer": { 721 | "version": "2.0.5", 722 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", 723 | "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", 724 | "funding": [ 725 | { 726 | "type": "github", 727 | "url": "https://github.com/sponsors/feross" 728 | }, 729 | { 730 | "type": "patreon", 731 | "url": "https://www.patreon.com/feross" 732 | }, 733 | { 734 | "type": "consulting", 735 | "url": "https://feross.org/support" 736 | } 737 | ], 738 | "license": "MIT", 739 | "engines": { 740 | "node": ">=4" 741 | } 742 | }, 743 | "node_modules/is-decimal": { 744 | "version": "1.0.4", 745 | "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", 746 | "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", 747 | "license": "MIT", 748 | "funding": { 749 | "type": "github", 750 | "url": "https://github.com/sponsors/wooorm" 751 | } 752 | }, 753 | "node_modules/is-hexadecimal": { 754 | "version": "1.0.4", 755 | "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", 756 | "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", 757 | "license": "MIT", 758 | "funding": { 759 | "type": "github", 760 | "url": "https://github.com/sponsors/wooorm" 761 | } 762 | }, 763 | "node_modules/is-plain-obj": { 764 | "version": "2.1.0", 765 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 766 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 767 | "license": "MIT", 768 | "engines": { 769 | "node": ">=8" 770 | } 771 | }, 772 | "node_modules/is-typedarray": { 773 | "version": "1.0.0", 774 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 775 | "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", 776 | "license": "MIT" 777 | }, 778 | "node_modules/isarray": { 779 | "version": "1.0.0", 780 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 781 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 782 | "license": "MIT" 783 | }, 784 | "node_modules/isstream": { 785 | "version": "0.1.2", 786 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 787 | "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", 788 | "license": "MIT" 789 | }, 790 | "node_modules/jsbn": { 791 | "version": "0.1.1", 792 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 793 | "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", 794 | "license": "MIT" 795 | }, 796 | "node_modules/json-schema": { 797 | "version": "0.4.0", 798 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", 799 | "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", 800 | "license": "(AFL-2.1 OR BSD-3-Clause)" 801 | }, 802 | "node_modules/json-schema-traverse": { 803 | "version": "0.4.1", 804 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 805 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 806 | "license": "MIT" 807 | }, 808 | "node_modules/json-stringify-safe": { 809 | "version": "5.0.1", 810 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 811 | "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", 812 | "license": "ISC" 813 | }, 814 | "node_modules/jsprim": { 815 | "version": "1.4.2", 816 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", 817 | "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", 818 | "license": "MIT", 819 | "dependencies": { 820 | "assert-plus": "1.0.0", 821 | "extsprintf": "1.3.0", 822 | "json-schema": "0.4.0", 823 | "verror": "1.10.0" 824 | }, 825 | "engines": { 826 | "node": ">=0.6.0" 827 | } 828 | }, 829 | "node_modules/lodash.trim": { 830 | "version": "4.5.1", 831 | "resolved": "https://registry.npmjs.org/lodash.trim/-/lodash.trim-4.5.1.tgz", 832 | "integrity": "sha512-nJAlRl/K+eiOehWKDzoBVrSMhK0K3A3YQsUNXHQa5yIrKBAhsZgSu3KoAFoFT+mEgiyBHddZ0pRk1ITpIp90Wg==", 833 | "license": "MIT" 834 | }, 835 | "node_modules/longest-streak": { 836 | "version": "2.0.4", 837 | "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", 838 | "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", 839 | "license": "MIT", 840 | "funding": { 841 | "type": "github", 842 | "url": "https://github.com/sponsors/wooorm" 843 | } 844 | }, 845 | "node_modules/make-error": { 846 | "version": "1.3.6", 847 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 848 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 849 | "license": "ISC" 850 | }, 851 | "node_modules/markdown-table": { 852 | "version": "2.0.0", 853 | "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", 854 | "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", 855 | "license": "MIT", 856 | "dependencies": { 857 | "repeat-string": "^1.0.0" 858 | }, 859 | "funding": { 860 | "type": "github", 861 | "url": "https://github.com/sponsors/wooorm" 862 | } 863 | }, 864 | "node_modules/md2sb": { 865 | "version": "5.1.2", 866 | "resolved": "https://registry.npmjs.org/md2sb/-/md2sb-5.1.2.tgz", 867 | "integrity": "sha512-OsolRcgJiv3i6BLXJgQwEsBznkLur8BmZ53h5fKFoq51rIgCRLXRcbQs3gBeCpfcPvS5zkgFGgiNPv+yz1juRQ==", 868 | "license": "MIT", 869 | "dependencies": { 870 | "@types/node": "^13.13.4", 871 | "commander": "^5.1.0", 872 | "enex2sb": "^5.1.2", 873 | "remark": "^13.0.0", 874 | "remark-gfm": "^1.0.0" 875 | }, 876 | "bin": { 877 | "md2sb": "dist/command/index.js" 878 | } 879 | }, 880 | "node_modules/md2sb/node_modules/@types/node": { 881 | "version": "13.13.52", 882 | "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", 883 | "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==", 884 | "license": "MIT" 885 | }, 886 | "node_modules/mdast-util-find-and-replace": { 887 | "version": "1.1.1", 888 | "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz", 889 | "integrity": "sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA==", 890 | "license": "MIT", 891 | "dependencies": { 892 | "escape-string-regexp": "^4.0.0", 893 | "unist-util-is": "^4.0.0", 894 | "unist-util-visit-parents": "^3.0.0" 895 | }, 896 | "funding": { 897 | "type": "opencollective", 898 | "url": "https://opencollective.com/unified" 899 | } 900 | }, 901 | "node_modules/mdast-util-from-markdown": { 902 | "version": "0.8.5", 903 | "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", 904 | "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", 905 | "license": "MIT", 906 | "dependencies": { 907 | "@types/mdast": "^3.0.0", 908 | "mdast-util-to-string": "^2.0.0", 909 | "micromark": "~2.11.0", 910 | "parse-entities": "^2.0.0", 911 | "unist-util-stringify-position": "^2.0.0" 912 | }, 913 | "funding": { 914 | "type": "opencollective", 915 | "url": "https://opencollective.com/unified" 916 | } 917 | }, 918 | "node_modules/mdast-util-gfm": { 919 | "version": "0.1.2", 920 | "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz", 921 | "integrity": "sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==", 922 | "license": "MIT", 923 | "dependencies": { 924 | "mdast-util-gfm-autolink-literal": "^0.1.0", 925 | "mdast-util-gfm-strikethrough": "^0.2.0", 926 | "mdast-util-gfm-table": "^0.1.0", 927 | "mdast-util-gfm-task-list-item": "^0.1.0", 928 | "mdast-util-to-markdown": "^0.6.1" 929 | }, 930 | "funding": { 931 | "type": "opencollective", 932 | "url": "https://opencollective.com/unified" 933 | } 934 | }, 935 | "node_modules/mdast-util-gfm-autolink-literal": { 936 | "version": "0.1.3", 937 | "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz", 938 | "integrity": "sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A==", 939 | "license": "MIT", 940 | "dependencies": { 941 | "ccount": "^1.0.0", 942 | "mdast-util-find-and-replace": "^1.1.0", 943 | "micromark": "^2.11.3" 944 | }, 945 | "funding": { 946 | "type": "opencollective", 947 | "url": "https://opencollective.com/unified" 948 | } 949 | }, 950 | "node_modules/mdast-util-gfm-strikethrough": { 951 | "version": "0.2.3", 952 | "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz", 953 | "integrity": "sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==", 954 | "license": "MIT", 955 | "dependencies": { 956 | "mdast-util-to-markdown": "^0.6.0" 957 | }, 958 | "funding": { 959 | "type": "opencollective", 960 | "url": "https://opencollective.com/unified" 961 | } 962 | }, 963 | "node_modules/mdast-util-gfm-table": { 964 | "version": "0.1.6", 965 | "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz", 966 | "integrity": "sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==", 967 | "license": "MIT", 968 | "dependencies": { 969 | "markdown-table": "^2.0.0", 970 | "mdast-util-to-markdown": "~0.6.0" 971 | }, 972 | "funding": { 973 | "type": "opencollective", 974 | "url": "https://opencollective.com/unified" 975 | } 976 | }, 977 | "node_modules/mdast-util-gfm-task-list-item": { 978 | "version": "0.1.6", 979 | "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz", 980 | "integrity": "sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==", 981 | "license": "MIT", 982 | "dependencies": { 983 | "mdast-util-to-markdown": "~0.6.0" 984 | }, 985 | "funding": { 986 | "type": "opencollective", 987 | "url": "https://opencollective.com/unified" 988 | } 989 | }, 990 | "node_modules/mdast-util-to-markdown": { 991 | "version": "0.6.5", 992 | "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", 993 | "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", 994 | "license": "MIT", 995 | "dependencies": { 996 | "@types/unist": "^2.0.0", 997 | "longest-streak": "^2.0.0", 998 | "mdast-util-to-string": "^2.0.0", 999 | "parse-entities": "^2.0.0", 1000 | "repeat-string": "^1.0.0", 1001 | "zwitch": "^1.0.0" 1002 | }, 1003 | "funding": { 1004 | "type": "opencollective", 1005 | "url": "https://opencollective.com/unified" 1006 | } 1007 | }, 1008 | "node_modules/mdast-util-to-string": { 1009 | "version": "2.0.0", 1010 | "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", 1011 | "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", 1012 | "license": "MIT", 1013 | "funding": { 1014 | "type": "opencollective", 1015 | "url": "https://opencollective.com/unified" 1016 | } 1017 | }, 1018 | "node_modules/methods": { 1019 | "version": "1.1.2", 1020 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1021 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 1022 | "license": "MIT", 1023 | "engines": { 1024 | "node": ">= 0.6" 1025 | } 1026 | }, 1027 | "node_modules/micromark": { 1028 | "version": "2.11.4", 1029 | "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", 1030 | "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", 1031 | "funding": [ 1032 | { 1033 | "type": "GitHub Sponsors", 1034 | "url": "https://github.com/sponsors/unifiedjs" 1035 | }, 1036 | { 1037 | "type": "OpenCollective", 1038 | "url": "https://opencollective.com/unified" 1039 | } 1040 | ], 1041 | "license": "MIT", 1042 | "dependencies": { 1043 | "debug": "^4.0.0", 1044 | "parse-entities": "^2.0.0" 1045 | } 1046 | }, 1047 | "node_modules/micromark-extension-gfm": { 1048 | "version": "0.3.3", 1049 | "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz", 1050 | "integrity": "sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A==", 1051 | "license": "MIT", 1052 | "dependencies": { 1053 | "micromark": "~2.11.0", 1054 | "micromark-extension-gfm-autolink-literal": "~0.5.0", 1055 | "micromark-extension-gfm-strikethrough": "~0.6.5", 1056 | "micromark-extension-gfm-table": "~0.4.0", 1057 | "micromark-extension-gfm-tagfilter": "~0.3.0", 1058 | "micromark-extension-gfm-task-list-item": "~0.3.0" 1059 | }, 1060 | "funding": { 1061 | "type": "opencollective", 1062 | "url": "https://opencollective.com/unified" 1063 | } 1064 | }, 1065 | "node_modules/micromark-extension-gfm-autolink-literal": { 1066 | "version": "0.5.7", 1067 | "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz", 1068 | "integrity": "sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw==", 1069 | "license": "MIT", 1070 | "dependencies": { 1071 | "micromark": "~2.11.3" 1072 | }, 1073 | "funding": { 1074 | "type": "opencollective", 1075 | "url": "https://opencollective.com/unified" 1076 | } 1077 | }, 1078 | "node_modules/micromark-extension-gfm-strikethrough": { 1079 | "version": "0.6.5", 1080 | "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz", 1081 | "integrity": "sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw==", 1082 | "license": "MIT", 1083 | "dependencies": { 1084 | "micromark": "~2.11.0" 1085 | }, 1086 | "funding": { 1087 | "type": "opencollective", 1088 | "url": "https://opencollective.com/unified" 1089 | } 1090 | }, 1091 | "node_modules/micromark-extension-gfm-table": { 1092 | "version": "0.4.3", 1093 | "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz", 1094 | "integrity": "sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA==", 1095 | "license": "MIT", 1096 | "dependencies": { 1097 | "micromark": "~2.11.0" 1098 | }, 1099 | "funding": { 1100 | "type": "opencollective", 1101 | "url": "https://opencollective.com/unified" 1102 | } 1103 | }, 1104 | "node_modules/micromark-extension-gfm-tagfilter": { 1105 | "version": "0.3.0", 1106 | "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", 1107 | "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", 1108 | "license": "MIT", 1109 | "funding": { 1110 | "type": "opencollective", 1111 | "url": "https://opencollective.com/unified" 1112 | } 1113 | }, 1114 | "node_modules/micromark-extension-gfm-task-list-item": { 1115 | "version": "0.3.3", 1116 | "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz", 1117 | "integrity": "sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ==", 1118 | "license": "MIT", 1119 | "dependencies": { 1120 | "micromark": "~2.11.0" 1121 | }, 1122 | "funding": { 1123 | "type": "opencollective", 1124 | "url": "https://opencollective.com/unified" 1125 | } 1126 | }, 1127 | "node_modules/mime": { 1128 | "version": "1.6.0", 1129 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1130 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 1131 | "license": "MIT", 1132 | "bin": { 1133 | "mime": "cli.js" 1134 | }, 1135 | "engines": { 1136 | "node": ">=4" 1137 | } 1138 | }, 1139 | "node_modules/mime-db": { 1140 | "version": "1.52.0", 1141 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1142 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1143 | "license": "MIT", 1144 | "engines": { 1145 | "node": ">= 0.6" 1146 | } 1147 | }, 1148 | "node_modules/mime-types": { 1149 | "version": "2.1.35", 1150 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1151 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1152 | "license": "MIT", 1153 | "dependencies": { 1154 | "mime-db": "1.52.0" 1155 | }, 1156 | "engines": { 1157 | "node": ">= 0.6" 1158 | } 1159 | }, 1160 | "node_modules/ms": { 1161 | "version": "2.1.3", 1162 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1163 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1164 | "license": "MIT" 1165 | }, 1166 | "node_modules/nano-md5": { 1167 | "version": "1.0.5", 1168 | "resolved": "https://registry.npmjs.org/nano-md5/-/nano-md5-1.0.5.tgz", 1169 | "integrity": "sha512-1VAOX0EiuwAdCMGpnglxp9r6ylm+gXwQi+UPAnc/Oj1tLLJ8D1I8rLZeiO4MWsUAqH8tuBAHweT1LYSrDfJlPg==", 1170 | "license": "MIT" 1171 | }, 1172 | "node_modules/oauth-sign": { 1173 | "version": "0.9.0", 1174 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 1175 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", 1176 | "license": "Apache-2.0", 1177 | "engines": { 1178 | "node": "*" 1179 | } 1180 | }, 1181 | "node_modules/p-is-promise": { 1182 | "version": "1.1.0", 1183 | "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", 1184 | "integrity": "sha512-zL7VE4JVS2IFSkR2GQKDSPEVxkoH43/p7oEnwpdCndKYJO0HVeRB7fA8TJwuLOTBREtK0ea8eHaxdwcpob5dmg==", 1185 | "license": "MIT", 1186 | "engines": { 1187 | "node": ">=4" 1188 | } 1189 | }, 1190 | "node_modules/parse-entities": { 1191 | "version": "2.0.0", 1192 | "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", 1193 | "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", 1194 | "license": "MIT", 1195 | "dependencies": { 1196 | "character-entities": "^1.0.0", 1197 | "character-entities-legacy": "^1.0.0", 1198 | "character-reference-invalid": "^1.0.0", 1199 | "is-alphanumerical": "^1.0.0", 1200 | "is-decimal": "^1.0.0", 1201 | "is-hexadecimal": "^1.0.0" 1202 | }, 1203 | "funding": { 1204 | "type": "github", 1205 | "url": "https://github.com/sponsors/wooorm" 1206 | } 1207 | }, 1208 | "node_modules/parsimmon": { 1209 | "version": "0.7.2", 1210 | "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-0.7.2.tgz", 1211 | "integrity": "sha512-vKcCxdVqkWH5vDUlPGKBhNJrsmP5EBXAFEDal4Qe1cNlBRPwOedAQ8Fj8BGyddHCGI+Zw58dztJc15VXHfwYRg==", 1212 | "license": "MIT" 1213 | }, 1214 | "node_modules/performance-now": { 1215 | "version": "2.1.0", 1216 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 1217 | "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", 1218 | "license": "MIT" 1219 | }, 1220 | "node_modules/process-nextick-args": { 1221 | "version": "2.0.1", 1222 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1223 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 1224 | "license": "MIT" 1225 | }, 1226 | "node_modules/psl": { 1227 | "version": "1.15.0", 1228 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", 1229 | "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", 1230 | "license": "MIT", 1231 | "dependencies": { 1232 | "punycode": "^2.3.1" 1233 | }, 1234 | "funding": { 1235 | "url": "https://github.com/sponsors/lupomontero" 1236 | } 1237 | }, 1238 | "node_modules/punycode": { 1239 | "version": "2.3.1", 1240 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 1241 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 1242 | "license": "MIT", 1243 | "engines": { 1244 | "node": ">=6" 1245 | } 1246 | }, 1247 | "node_modules/qs": { 1248 | "version": "6.5.3", 1249 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", 1250 | "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", 1251 | "license": "BSD-3-Clause", 1252 | "engines": { 1253 | "node": ">=0.6" 1254 | } 1255 | }, 1256 | "node_modules/raw-body": { 1257 | "version": "3.0.0", 1258 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", 1259 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", 1260 | "license": "MIT", 1261 | "dependencies": { 1262 | "bytes": "3.1.2", 1263 | "http-errors": "2.0.0", 1264 | "iconv-lite": "0.6.3", 1265 | "unpipe": "1.0.0" 1266 | }, 1267 | "engines": { 1268 | "node": ">= 0.8" 1269 | } 1270 | }, 1271 | "node_modules/readable-stream": { 1272 | "version": "2.3.8", 1273 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", 1274 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", 1275 | "license": "MIT", 1276 | "dependencies": { 1277 | "core-util-is": "~1.0.0", 1278 | "inherits": "~2.0.3", 1279 | "isarray": "~1.0.0", 1280 | "process-nextick-args": "~2.0.0", 1281 | "safe-buffer": "~5.1.1", 1282 | "string_decoder": "~1.1.1", 1283 | "util-deprecate": "~1.0.1" 1284 | } 1285 | }, 1286 | "node_modules/remark": { 1287 | "version": "13.0.0", 1288 | "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", 1289 | "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==", 1290 | "license": "MIT", 1291 | "dependencies": { 1292 | "remark-parse": "^9.0.0", 1293 | "remark-stringify": "^9.0.0", 1294 | "unified": "^9.1.0" 1295 | }, 1296 | "funding": { 1297 | "type": "opencollective", 1298 | "url": "https://opencollective.com/unified" 1299 | } 1300 | }, 1301 | "node_modules/remark-gfm": { 1302 | "version": "1.0.0", 1303 | "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", 1304 | "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", 1305 | "license": "MIT", 1306 | "dependencies": { 1307 | "mdast-util-gfm": "^0.1.0", 1308 | "micromark-extension-gfm": "^0.3.0" 1309 | }, 1310 | "funding": { 1311 | "type": "opencollective", 1312 | "url": "https://opencollective.com/unified" 1313 | } 1314 | }, 1315 | "node_modules/remark-parse": { 1316 | "version": "9.0.0", 1317 | "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", 1318 | "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", 1319 | "license": "MIT", 1320 | "dependencies": { 1321 | "mdast-util-from-markdown": "^0.8.0" 1322 | }, 1323 | "funding": { 1324 | "type": "opencollective", 1325 | "url": "https://opencollective.com/unified" 1326 | } 1327 | }, 1328 | "node_modules/remark-stringify": { 1329 | "version": "9.0.1", 1330 | "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz", 1331 | "integrity": "sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg==", 1332 | "license": "MIT", 1333 | "dependencies": { 1334 | "mdast-util-to-markdown": "^0.6.0" 1335 | }, 1336 | "funding": { 1337 | "type": "opencollective", 1338 | "url": "https://opencollective.com/unified" 1339 | } 1340 | }, 1341 | "node_modules/repeat-string": { 1342 | "version": "1.6.1", 1343 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1344 | "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", 1345 | "license": "MIT", 1346 | "engines": { 1347 | "node": ">=0.10" 1348 | } 1349 | }, 1350 | "node_modules/request": { 1351 | "version": "2.88.2", 1352 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", 1353 | "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", 1354 | "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", 1355 | "license": "Apache-2.0", 1356 | "dependencies": { 1357 | "aws-sign2": "~0.7.0", 1358 | "aws4": "^1.8.0", 1359 | "caseless": "~0.12.0", 1360 | "combined-stream": "~1.0.6", 1361 | "extend": "~3.0.2", 1362 | "forever-agent": "~0.6.1", 1363 | "form-data": "~2.3.2", 1364 | "har-validator": "~5.1.3", 1365 | "http-signature": "~1.2.0", 1366 | "is-typedarray": "~1.0.0", 1367 | "isstream": "~0.1.2", 1368 | "json-stringify-safe": "~5.0.1", 1369 | "mime-types": "~2.1.19", 1370 | "oauth-sign": "~0.9.0", 1371 | "performance-now": "^2.1.0", 1372 | "qs": "~6.5.2", 1373 | "safe-buffer": "^5.1.2", 1374 | "tough-cookie": "~2.5.0", 1375 | "tunnel-agent": "^0.6.0", 1376 | "uuid": "^3.3.2" 1377 | }, 1378 | "engines": { 1379 | "node": ">= 6" 1380 | } 1381 | }, 1382 | "node_modules/safe-buffer": { 1383 | "version": "5.1.2", 1384 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1385 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1386 | "license": "MIT" 1387 | }, 1388 | "node_modules/safer-buffer": { 1389 | "version": "2.1.2", 1390 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1391 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1392 | "license": "MIT" 1393 | }, 1394 | "node_modules/setprototypeof": { 1395 | "version": "1.2.0", 1396 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1397 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 1398 | "license": "ISC" 1399 | }, 1400 | "node_modules/source-map": { 1401 | "version": "0.6.1", 1402 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1403 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1404 | "license": "BSD-3-Clause", 1405 | "engines": { 1406 | "node": ">=0.10.0" 1407 | } 1408 | }, 1409 | "node_modules/source-map-support": { 1410 | "version": "0.5.21", 1411 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1412 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1413 | "license": "MIT", 1414 | "dependencies": { 1415 | "buffer-from": "^1.0.0", 1416 | "source-map": "^0.6.0" 1417 | } 1418 | }, 1419 | "node_modules/sshpk": { 1420 | "version": "1.18.0", 1421 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", 1422 | "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", 1423 | "license": "MIT", 1424 | "dependencies": { 1425 | "asn1": "~0.2.3", 1426 | "assert-plus": "^1.0.0", 1427 | "bcrypt-pbkdf": "^1.0.0", 1428 | "dashdash": "^1.12.0", 1429 | "ecc-jsbn": "~0.1.1", 1430 | "getpass": "^0.1.1", 1431 | "jsbn": "~0.1.0", 1432 | "safer-buffer": "^2.0.2", 1433 | "tweetnacl": "~0.14.0" 1434 | }, 1435 | "bin": { 1436 | "sshpk-conv": "bin/sshpk-conv", 1437 | "sshpk-sign": "bin/sshpk-sign", 1438 | "sshpk-verify": "bin/sshpk-verify" 1439 | }, 1440 | "engines": { 1441 | "node": ">=0.10.0" 1442 | } 1443 | }, 1444 | "node_modules/statuses": { 1445 | "version": "2.0.1", 1446 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1447 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 1448 | "license": "MIT", 1449 | "engines": { 1450 | "node": ">= 0.8" 1451 | } 1452 | }, 1453 | "node_modules/streamsearch": { 1454 | "version": "1.1.0", 1455 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", 1456 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", 1457 | "engines": { 1458 | "node": ">=10.0.0" 1459 | } 1460 | }, 1461 | "node_modules/string_decoder": { 1462 | "version": "1.1.1", 1463 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1464 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1465 | "license": "MIT", 1466 | "dependencies": { 1467 | "safe-buffer": "~5.1.0" 1468 | } 1469 | }, 1470 | "node_modules/style-parser": { 1471 | "version": "1.1.1", 1472 | "resolved": "https://registry.npmjs.org/style-parser/-/style-parser-1.1.1.tgz", 1473 | "integrity": "sha512-a2B7DBdEe52VwmbIhPK2XoEqMo4MIpZON5tr5q/Ca8MZf/T+TczfQr5knhoYBPNmQpaocjKwtNyOiRWrxT+wxg==", 1474 | "license": "MIT", 1475 | "dependencies": { 1476 | "parsimmon": "^0.7.0" 1477 | } 1478 | }, 1479 | "node_modules/superagent": { 1480 | "version": "3.8.3", 1481 | "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", 1482 | "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", 1483 | "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", 1484 | "license": "MIT", 1485 | "dependencies": { 1486 | "component-emitter": "^1.2.0", 1487 | "cookiejar": "^2.1.0", 1488 | "debug": "^3.1.0", 1489 | "extend": "^3.0.0", 1490 | "form-data": "^2.3.1", 1491 | "formidable": "^1.2.0", 1492 | "methods": "^1.1.1", 1493 | "mime": "^1.4.1", 1494 | "qs": "^6.5.1", 1495 | "readable-stream": "^2.3.5" 1496 | }, 1497 | "engines": { 1498 | "node": ">= 4.0" 1499 | } 1500 | }, 1501 | "node_modules/superagent/node_modules/debug": { 1502 | "version": "3.2.7", 1503 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 1504 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 1505 | "license": "MIT", 1506 | "dependencies": { 1507 | "ms": "^2.1.1" 1508 | } 1509 | }, 1510 | "node_modules/toidentifier": { 1511 | "version": "1.0.1", 1512 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1513 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 1514 | "license": "MIT", 1515 | "engines": { 1516 | "node": ">=0.6" 1517 | } 1518 | }, 1519 | "node_modules/tough-cookie": { 1520 | "version": "2.5.0", 1521 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", 1522 | "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", 1523 | "license": "BSD-3-Clause", 1524 | "dependencies": { 1525 | "psl": "^1.1.28", 1526 | "punycode": "^2.1.1" 1527 | }, 1528 | "engines": { 1529 | "node": ">=0.8" 1530 | } 1531 | }, 1532 | "node_modules/trough": { 1533 | "version": "1.0.5", 1534 | "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", 1535 | "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", 1536 | "license": "MIT", 1537 | "funding": { 1538 | "type": "github", 1539 | "url": "https://github.com/sponsors/wooorm" 1540 | } 1541 | }, 1542 | "node_modules/ts-node": { 1543 | "version": "8.10.2", 1544 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", 1545 | "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", 1546 | "license": "MIT", 1547 | "dependencies": { 1548 | "arg": "^4.1.0", 1549 | "diff": "^4.0.1", 1550 | "make-error": "^1.1.1", 1551 | "source-map-support": "^0.5.17", 1552 | "yn": "3.1.1" 1553 | }, 1554 | "bin": { 1555 | "ts-node": "dist/bin.js", 1556 | "ts-node-script": "dist/bin-script.js", 1557 | "ts-node-transpile-only": "dist/bin-transpile.js", 1558 | "ts-script": "dist/bin-script-deprecated.js" 1559 | }, 1560 | "engines": { 1561 | "node": ">=6.0.0" 1562 | }, 1563 | "peerDependencies": { 1564 | "typescript": ">=2.7" 1565 | } 1566 | }, 1567 | "node_modules/tslib": { 1568 | "version": "2.8.1", 1569 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1570 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1571 | "license": "0BSD" 1572 | }, 1573 | "node_modules/tunnel-agent": { 1574 | "version": "0.6.0", 1575 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1576 | "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", 1577 | "license": "Apache-2.0", 1578 | "dependencies": { 1579 | "safe-buffer": "^5.0.1" 1580 | }, 1581 | "engines": { 1582 | "node": "*" 1583 | } 1584 | }, 1585 | "node_modules/tweetnacl": { 1586 | "version": "0.14.5", 1587 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1588 | "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", 1589 | "license": "Unlicense" 1590 | }, 1591 | "node_modules/typescript": { 1592 | "version": "5.7.3", 1593 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", 1594 | "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", 1595 | "license": "Apache-2.0", 1596 | "bin": { 1597 | "tsc": "bin/tsc", 1598 | "tsserver": "bin/tsserver" 1599 | }, 1600 | "engines": { 1601 | "node": ">=14.17" 1602 | } 1603 | }, 1604 | "node_modules/undici-types": { 1605 | "version": "6.19.8", 1606 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 1607 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", 1608 | "dev": true, 1609 | "license": "MIT" 1610 | }, 1611 | "node_modules/unified": { 1612 | "version": "9.2.2", 1613 | "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", 1614 | "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", 1615 | "license": "MIT", 1616 | "dependencies": { 1617 | "bail": "^1.0.0", 1618 | "extend": "^3.0.0", 1619 | "is-buffer": "^2.0.0", 1620 | "is-plain-obj": "^2.0.0", 1621 | "trough": "^1.0.0", 1622 | "vfile": "^4.0.0" 1623 | }, 1624 | "funding": { 1625 | "type": "opencollective", 1626 | "url": "https://opencollective.com/unified" 1627 | } 1628 | }, 1629 | "node_modules/unist-util-is": { 1630 | "version": "4.1.0", 1631 | "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", 1632 | "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", 1633 | "license": "MIT", 1634 | "funding": { 1635 | "type": "opencollective", 1636 | "url": "https://opencollective.com/unified" 1637 | } 1638 | }, 1639 | "node_modules/unist-util-stringify-position": { 1640 | "version": "2.0.3", 1641 | "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", 1642 | "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", 1643 | "license": "MIT", 1644 | "dependencies": { 1645 | "@types/unist": "^2.0.2" 1646 | }, 1647 | "funding": { 1648 | "type": "opencollective", 1649 | "url": "https://opencollective.com/unified" 1650 | } 1651 | }, 1652 | "node_modules/unist-util-visit-parents": { 1653 | "version": "3.1.1", 1654 | "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", 1655 | "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", 1656 | "license": "MIT", 1657 | "dependencies": { 1658 | "@types/unist": "^2.0.0", 1659 | "unist-util-is": "^4.0.0" 1660 | }, 1661 | "funding": { 1662 | "type": "opencollective", 1663 | "url": "https://opencollective.com/unified" 1664 | } 1665 | }, 1666 | "node_modules/unpipe": { 1667 | "version": "1.0.0", 1668 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1669 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 1670 | "license": "MIT", 1671 | "engines": { 1672 | "node": ">= 0.8" 1673 | } 1674 | }, 1675 | "node_modules/uri-js": { 1676 | "version": "4.4.1", 1677 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1678 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1679 | "license": "BSD-2-Clause", 1680 | "dependencies": { 1681 | "punycode": "^2.1.0" 1682 | } 1683 | }, 1684 | "node_modules/urlpattern-polyfill": { 1685 | "version": "10.0.0", 1686 | "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", 1687 | "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", 1688 | "license": "MIT" 1689 | }, 1690 | "node_modules/util-deprecate": { 1691 | "version": "1.0.2", 1692 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1693 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 1694 | "license": "MIT" 1695 | }, 1696 | "node_modules/uuid": { 1697 | "version": "3.4.0", 1698 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", 1699 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", 1700 | "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", 1701 | "license": "MIT", 1702 | "bin": { 1703 | "uuid": "bin/uuid" 1704 | } 1705 | }, 1706 | "node_modules/verror": { 1707 | "version": "1.10.0", 1708 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1709 | "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", 1710 | "engines": [ 1711 | "node >=0.6.0" 1712 | ], 1713 | "license": "MIT", 1714 | "dependencies": { 1715 | "assert-plus": "^1.0.0", 1716 | "core-util-is": "1.0.2", 1717 | "extsprintf": "^1.2.0" 1718 | } 1719 | }, 1720 | "node_modules/verror/node_modules/core-util-is": { 1721 | "version": "1.0.2", 1722 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 1723 | "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", 1724 | "license": "MIT" 1725 | }, 1726 | "node_modules/vfile": { 1727 | "version": "4.2.1", 1728 | "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", 1729 | "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", 1730 | "license": "MIT", 1731 | "dependencies": { 1732 | "@types/unist": "^2.0.0", 1733 | "is-buffer": "^2.0.0", 1734 | "unist-util-stringify-position": "^2.0.0", 1735 | "vfile-message": "^2.0.0" 1736 | }, 1737 | "funding": { 1738 | "type": "opencollective", 1739 | "url": "https://opencollective.com/unified" 1740 | } 1741 | }, 1742 | "node_modules/vfile-message": { 1743 | "version": "2.0.4", 1744 | "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", 1745 | "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", 1746 | "license": "MIT", 1747 | "dependencies": { 1748 | "@types/unist": "^2.0.0", 1749 | "unist-util-stringify-position": "^2.0.0" 1750 | }, 1751 | "funding": { 1752 | "type": "opencollective", 1753 | "url": "https://opencollective.com/unified" 1754 | } 1755 | }, 1756 | "node_modules/yn": { 1757 | "version": "3.1.1", 1758 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1759 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1760 | "license": "MIT", 1761 | "engines": { 1762 | "node": ">=6" 1763 | } 1764 | }, 1765 | "node_modules/zod": { 1766 | "version": "3.24.1", 1767 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", 1768 | "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", 1769 | "license": "MIT", 1770 | "funding": { 1771 | "url": "https://github.com/sponsors/colinhacks" 1772 | } 1773 | }, 1774 | "node_modules/zwitch": { 1775 | "version": "1.0.5", 1776 | "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", 1777 | "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", 1778 | "license": "MIT", 1779 | "funding": { 1780 | "type": "github", 1781 | "url": "https://github.com/sponsors/wooorm" 1782 | } 1783 | } 1784 | } 1785 | } 1786 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrapbox-cosense-mcp", 3 | "version": "0.1.0", 4 | "description": "MCP server for cosense", 5 | "private": false, 6 | "license": "MIT", 7 | "type": "module", 8 | "bin": { 9 | "scrapbox-cosense-mcp": "./build/index.js" 10 | }, 11 | "files": [ 12 | "build" 13 | ], 14 | "scripts": { 15 | "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", 16 | "prepare": "npm run build", 17 | "watch": "tsc --watch", 18 | "inspector": "npx @modelcontextprotocol/inspector build/index.js" 19 | }, 20 | "dependencies": { 21 | "@modelcontextprotocol/sdk": "0.6.0", 22 | "@whatwg-node/fetch": "^0.10.1", 23 | "md2sb": "^5.1.2" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^20.11.24", 27 | "typescript": "^5.3.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cosense.ts: -------------------------------------------------------------------------------- 1 | import { fetch } from "@whatwg-node/fetch"; 2 | import { sortPages, type SortOptions } from './utils/sort.js'; 3 | const API_DOMAIN = process.env.API_DOMAIN || "scrapbox.io"; 4 | 5 | // /api/pages/:projectname/search/query の型定義 6 | type SearchQueryResponse = { 7 | projectName: string; // data取得先のproject名 8 | searchQuery: string; // 検索語句 9 | query: { 10 | words: string[]; // AND検索に使った語句 11 | excludes: string[]; // NOT検索に使った語句 12 | }; 13 | limit: number; // 検索件数の上限 14 | count: number; // 検索件数 15 | existsExactTitleMatch: boolean; 16 | backend: 'elasticsearch'; 17 | pages: { 18 | id: string; 19 | title: string; 20 | image: string; 21 | words: string[]; 22 | lines: string[]; 23 | created?: number; 24 | updated?: number; 25 | user?: { 26 | id: string; 27 | name: string; 28 | displayName: string; 29 | photo: string; 30 | }; 31 | lastUpdateUser?: { 32 | id: string; 33 | name: string; 34 | displayName: string; 35 | photo: string; 36 | }; 37 | collaborators?: { 38 | id: string; 39 | name: string; 40 | displayName: string; 41 | photo: string; 42 | }[]; 43 | }[]; 44 | debug?: { // デバッグ情報を追加 45 | request_url?: string; 46 | query?: string; 47 | total_results?: number; 48 | error?: string; 49 | }; 50 | }; 51 | 52 | // /api/pages/:projectname/:pagetitle 53 | type GetPageResponse = { 54 | id: string; 55 | title: string; 56 | lines: { 57 | id: string; 58 | text: string; 59 | userId: string; 60 | created: number; 61 | updated: number; 62 | }[]; 63 | created: number; 64 | updated: number; 65 | links: string[]; 66 | relatedPages: { 67 | links1hop: { 68 | title: string; 69 | descriptions: string[]; 70 | }[]; 71 | }; 72 | user: { // 追加: 最新の編集者情報 73 | id: string; 74 | name: string; 75 | displayName: string; 76 | photo: string; 77 | }; 78 | lastUpdateUser?: { 79 | id: string; 80 | name: string; 81 | displayName: string; 82 | photo: string; 83 | }; 84 | collaborators: { 85 | id: string; 86 | name: string; 87 | displayName: string; 88 | photo: string; 89 | }[]; 90 | debug?: { 91 | error?: string; 92 | warning?: string; 93 | }; 94 | }; 95 | 96 | async function getPage( 97 | projectName: string, 98 | pageName: string, 99 | sid?: string, 100 | ): Promise { 101 | try { 102 | const response = sid 103 | ? await fetch(`https://${API_DOMAIN}/api/pages/${projectName}/${encodeURIComponent(pageName)}`, { 104 | headers: { Cookie: `connect.sid=${sid}` }, 105 | }) 106 | : await fetch( 107 | `https://${API_DOMAIN}/api/pages/${projectName}/${encodeURIComponent(pageName)}`, 108 | ); 109 | 110 | if (!response.ok) { 111 | console.error(`API error: ${response.status} ${response.statusText}`); 112 | return null; 113 | } 114 | 115 | const page = await response.json(); 116 | 117 | // レスポンスの型チェック 118 | if (!page || typeof page !== 'object') { 119 | console.error('Invalid page response format: not an object'); 120 | return null; 121 | } 122 | 123 | const typedPage = page as GetPageResponse; 124 | if (!Array.isArray(typedPage.lines)) { 125 | return { 126 | ...typedPage, 127 | debug: { 128 | error: 'Invalid page response format: lines is not an array' 129 | } 130 | }; 131 | } 132 | 133 | // userとlastUpdateUserの整合性チェック 134 | if (!typedPage.user && typedPage.lastUpdateUser) { 135 | // lastUpdateUserが存在するがuserが存在しない場合 136 | return { 137 | ...typedPage, 138 | user: typedPage.lastUpdateUser, 139 | debug: { 140 | warning: `Using lastUpdateUser as fallback for user information on page: ${typedPage.title}` 141 | } 142 | }; 143 | } else if (!typedPage.user) { 144 | // どちらの情報も存在しない場合 145 | return { 146 | ...typedPage, 147 | debug: { 148 | warning: `Missing both user and lastUpdateUser information for page: ${typedPage.title}` 149 | } 150 | }; 151 | } 152 | 153 | return typedPage; 154 | } catch (error) { 155 | console.error('Error fetching page:', error); 156 | return null; 157 | } 158 | } 159 | 160 | function toReadablePage(page: GetPageResponse): { 161 | title: string; 162 | lines: { 163 | id: string; 164 | text: string; 165 | userId: string; 166 | created: number; 167 | updated: number; 168 | }[]; 169 | created: number; 170 | updated: number; 171 | user: { 172 | id: string; 173 | name: string; 174 | displayName: string; 175 | photo: string; 176 | }; 177 | lastUpdateUser?: { 178 | id: string; 179 | name: string; 180 | displayName: string; 181 | photo: string; 182 | }; 183 | collaborators: { 184 | id: string; 185 | name: string; 186 | displayName: string; 187 | photo: string; 188 | }[]; 189 | links: string[]; 190 | } { 191 | return { 192 | title: page.title, 193 | lines: page.lines, 194 | created: page.created, 195 | updated: page.updated, 196 | user: page.user, 197 | lastUpdateUser: page.lastUpdateUser, 198 | collaborators: page.collaborators, 199 | links: page.links, 200 | }; 201 | } 202 | 203 | // Scrapboxのページ型定義 204 | type ScrapboxPage = { 205 | title: string; 206 | lastAccessed?: number; 207 | created?: number; 208 | updated?: number; 209 | accessed?: number; 210 | views?: number; 211 | linked?: number; 212 | pin?: number; 213 | user?: { 214 | id: string; 215 | name: string; 216 | displayName: string; 217 | photo: string; 218 | }; 219 | lastUpdateUser?: { 220 | id: string; 221 | name: string; 222 | displayName: string; 223 | photo: string; 224 | }; 225 | }; 226 | 227 | // /api/pages/:projectname 228 | type ListPagesResponse = { 229 | limit: number; 230 | count: number; 231 | skip: number; 232 | projectName: string; 233 | pages: { 234 | title: string; 235 | lastAccessed?: number; 236 | created?: number; 237 | updated?: number; 238 | accessed?: number; 239 | views?: number; 240 | linked?: number; 241 | pin?: number; 242 | user?: { 243 | id: string; 244 | name: string; 245 | displayName: string; 246 | photo: string; 247 | }; 248 | lastUpdateUser?: { 249 | id: string; 250 | name: string; 251 | displayName: string; 252 | photo: string; 253 | }; 254 | }[]; 255 | }; 256 | 257 | // デバッグ情報の型を拡張 258 | type DebugInfo = { 259 | request_url?: string; 260 | params?: Record; 261 | error?: string; 262 | originalCount?: number; 263 | filteredCount?: number; 264 | appliedSort?: string; 265 | excludedPinned?: boolean; 266 | total_results?: number; 267 | }; 268 | 269 | async function listPages( 270 | projectName: string, 271 | sid?: string, 272 | options: { limit?: number; skip?: number; sort?: string; excludePinned?: boolean } = {} 273 | ): Promise { 274 | try { 275 | const { limit = 1000, skip = 0, sort, excludePinned } = options; 276 | 277 | // クエリパラメータの構築 278 | const sortValue = options.sort || 'created'; 279 | const params = new URLSearchParams({ 280 | limit: (options.limit || 1000).toString(), 281 | skip: (options.skip || 0).toString(), 282 | sort: sortValue 283 | }); 284 | 285 | const url = `https://${API_DOMAIN}/api/pages/${projectName}?${params}`; 286 | 287 | // デバッグ情報を含めるための変数 288 | const debugInfo: DebugInfo = { 289 | request_url: url, 290 | params: Object.fromEntries(params.entries()) 291 | }; 292 | 293 | const response = sid 294 | ? await fetch(url, { 295 | headers: { Cookie: `connect.sid=${sid}` }, 296 | }) 297 | : await fetch(url); 298 | 299 | if (!response.ok) { 300 | return { 301 | limit: 0, 302 | count: 0, 303 | skip: 0, 304 | projectName: projectName, 305 | pages: [], 306 | debug: { 307 | ...debugInfo, 308 | error: `API error: ${response.status} ${response.statusText}` 309 | } 310 | }; 311 | } 312 | 313 | const pages = await response.json(); 314 | const pagesWithDetails = await Promise.all( 315 | (pages as ListPagesResponse).pages.map(async (page) => { 316 | const pageDetails = await getPage(projectName, page.title, sid); 317 | if (pageDetails) { 318 | return { 319 | ...page, 320 | user: pageDetails.user, 321 | lastUpdateUser: pageDetails.lastUpdateUser, 322 | created: pageDetails.created, 323 | updated: pageDetails.updated, 324 | collaborators: pageDetails.collaborators, 325 | descriptions: pageDetails.lines?.slice(0, 5).map(line => line.text) || [] 326 | }; 327 | } 328 | return page; 329 | }) 330 | ); 331 | 332 | // ソートとフィルタリングを適用 333 | const sortedPages = sortPages(pagesWithDetails, { sort, excludePinned }); 334 | 335 | return { 336 | ...(pages as ListPagesResponse), 337 | pages: sortedPages, 338 | debug: { 339 | ...debugInfo, 340 | originalCount: pagesWithDetails.length, 341 | filteredCount: sortedPages.length, 342 | appliedSort: sort || 'created', 343 | excludedPinned: excludePinned || false 344 | } 345 | }; 346 | 347 | } catch (error) { 348 | return { 349 | limit: 0, 350 | count: 0, 351 | skip: 0, 352 | projectName: projectName, 353 | pages: [], 354 | debug: { 355 | error: error instanceof Error ? error.message : '不明なエラー' 356 | } 357 | }; 358 | } 359 | } 360 | 361 | function encodeScrapboxBody(body: string): string { 362 | // Scrapboxの本文用にエンコード 363 | return encodeURIComponent(body); 364 | } 365 | 366 | function createPageUrl(projectName: string, title: string, body?: string): string { 367 | const baseUrl = `https://${API_DOMAIN}/${projectName}/${encodeURIComponent(title)}`; 368 | return body ? `${baseUrl}?body=${encodeScrapboxBody(body)}` : baseUrl; 369 | } 370 | 371 | /** 372 | * プロジェクト内のページを全文検索します 373 | * @param projectName プロジェクト名 374 | * @param query 検索クエリ 375 | * @param sid セッションID(オプション) 376 | * @returns 検索結果 377 | * 378 | * 使用例: 379 | * - 基本的な検索: searchPages("projectname", "検索語句") 380 | * - 複数語句での検索: searchPages("projectname", "word1 word2") 381 | * - 除外検索: searchPages("projectname", "word1 -word2") 382 | * - フレーズ検索: searchPages("projectname", '"exact phrase"') 383 | */ 384 | async function searchPages( 385 | projectName: string, 386 | query: string, 387 | sid?: string 388 | ): Promise { 389 | const encodedQuery = encodeURIComponent(query); 390 | const url = `https://${API_DOMAIN}/api/pages/${projectName}/search/query?q=${encodedQuery}`; 391 | 392 | const debugInfo = { 393 | request_url: url, 394 | searchQuery: query, 395 | }; 396 | 397 | const response = sid 398 | ? await fetch(url, { headers: { Cookie: `connect.sid=${sid}` } }) 399 | : await fetch(url); 400 | 401 | if (!response.ok) { 402 | return { 403 | projectName, 404 | searchQuery: query, 405 | query: { words: [], excludes: [] }, 406 | limit: 0, 407 | count: 0, 408 | existsExactTitleMatch: false, 409 | backend: 'elasticsearch', 410 | pages: [], 411 | debug: { 412 | ...debugInfo, 413 | error: `Search API error: ${response.status} ${response.statusText}` 414 | } 415 | }; 416 | } 417 | 418 | const result = await response.json(); 419 | return { 420 | projectName, 421 | searchQuery: query, 422 | query: result.query, 423 | limit: result.limit, 424 | count: result.count, 425 | existsExactTitleMatch: result.existsExactTitleMatch, 426 | backend: result.backend, 427 | pages: result.pages, 428 | debug: { 429 | ...debugInfo, 430 | total_results: result.pages.length 431 | } 432 | }; 433 | } 434 | 435 | /** 436 | * ピン留めページを考慮してソートされたページリストを取得する 437 | */ 438 | async function listPagesWithSort( 439 | projectName: string, 440 | options: { 441 | limit: number; 442 | skip: number; 443 | sort?: string; 444 | excludePinned?: boolean; 445 | }, 446 | sid?: string 447 | ): Promise { 448 | const skip = options.skip || 0; 449 | const limit = options.limit; 450 | const fetchSize = limit + skip + 100; // skip + limit + 余裕を持って取得 451 | 452 | // 1. より多くのページを一度に取得 453 | const response = await listPages(projectName, sid, { 454 | limit: fetchSize, 455 | skip: 0, // 最初から取得して後でskipを適用 456 | excludePinned: options.excludePinned 457 | }); 458 | 459 | // 2. 取得したページをメモリ上でソート 460 | const sortedPages = sortPages(response.pages, { sort: options.sort, excludePinned: options.excludePinned }); 461 | 462 | // 3. skip位置から必要な件数を切り出し 463 | const resultPages = sortedPages.slice(skip, skip + limit); 464 | 465 | // 4. 結果を返す 466 | return { 467 | ...response, 468 | pages: resultPages, 469 | limit: resultPages.length, 470 | skip: skip 471 | }; 472 | } 473 | 474 | // 型のエクスポート 475 | export type { ListPagesResponse, ScrapboxPage }; 476 | 477 | // 関数のエクスポート 478 | export { getPage, listPages, listPagesWithSort, toReadablePage, createPageUrl, searchPages }; 479 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const API_DOMAIN = process.env.API_DOMAIN || "scrapbox.io"; 4 | const SERVICE_LABEL = process.env.SERVICE_LABEL || "cosense (scrapbox)"; 5 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 6 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 7 | import { 8 | ListResourcesRequestSchema, 9 | ListToolsRequestSchema, 10 | ReadResourceRequestSchema, 11 | CallToolRequestSchema, 12 | } from "@modelcontextprotocol/sdk/types.js"; 13 | import { listPages, getPage, toReadablePage } from "./cosense.js"; 14 | import { formatYmd } from './utils/format.js'; 15 | import { setupRoutes } from './routes/index.js'; 16 | 17 | // 環境変数のデフォルト値と検証用の定数 18 | const FETCH_PAGE_LIMIT = 100; // 固定で100件取得 19 | const DEFAULT_PAGE_LIMIT = FETCH_PAGE_LIMIT; // デフォルトは取得上限と同じ 20 | const DEFAULT_SORT_METHOD = 'updated'; 21 | const MIN_PAGE_LIMIT = 1; 22 | const MAX_PAGE_LIMIT = 1000; 23 | 24 | // 有効なソート方法の定義 25 | const VALID_SORT_METHODS = ['updated', 'created', 'accessed', 'linked', 'views', 'title'] as const; 26 | 27 | // resourcesの初期取得用の設定 28 | const cosenseSid: string | undefined = process.env.COSENSE_SID; 29 | const projectName: string | undefined = process.env.COSENSE_PROJECT_NAME; 30 | const initialPageLimit: number = (() => { 31 | const limit = process.env.COSENSE_PAGE_LIMIT ? 32 | parseInt(process.env.COSENSE_PAGE_LIMIT, 10) : 33 | DEFAULT_PAGE_LIMIT; 34 | 35 | if (isNaN(limit) || limit < MIN_PAGE_LIMIT || limit > MAX_PAGE_LIMIT) { 36 | console.error(`Invalid COSENSE_PAGE_LIMIT: ${process.env.COSENSE_PAGE_LIMIT}, using default: ${DEFAULT_PAGE_LIMIT}`); 37 | return DEFAULT_PAGE_LIMIT; 38 | } 39 | return limit; 40 | })(); 41 | 42 | const initialSortMethod: string = (() => { 43 | const sort = process.env.COSENSE_SORT_METHOD; 44 | 45 | if (!sort) return DEFAULT_SORT_METHOD; 46 | if (!VALID_SORT_METHODS.includes(sort as any)) { 47 | console.error(`Invalid COSENSE_SORT_METHOD: ${sort}, using default: ${DEFAULT_SORT_METHOD}`); 48 | return DEFAULT_SORT_METHOD; 49 | } 50 | return sort; 51 | })(); 52 | 53 | if (!projectName) { 54 | throw new Error("COSENSE_PROJECT_NAME is not set"); 55 | } 56 | 57 | // resourcesの初期化(100件取得してソート) 58 | const resources = await (async () => { 59 | try { 60 | // 常に100件取得 61 | const result = await listPages( 62 | projectName, 63 | cosenseSid, 64 | { 65 | limit: FETCH_PAGE_LIMIT, // 固定で100件 66 | skip: 0, 67 | sort: initialSortMethod, 68 | excludePinned: process.env.COSENSE_EXCLUDE_PINNED === 'true' 69 | } 70 | ); 71 | 72 | // ソート済みのページから必要な件数だけを使用 73 | return result.pages 74 | .slice(0, Math.min(initialPageLimit, FETCH_PAGE_LIMIT)) // 環境変数で指定された件数か100件の小さい方 75 | .map((page) => ({ 76 | uri: `cosense:///${page.title}`, 77 | mimeType: "text/plain", 78 | name: page.title, 79 | description: `A text page: ${page.title}`, 80 | })); 81 | 82 | } catch (error) { 83 | console.error('Failed to initialize resources:', error); 84 | return []; // 空の配列を返してサーバーは起動を継続 85 | } 86 | })(); 87 | 88 | const server = new Server( 89 | { 90 | name: "scrapbox-cosense-mcp", 91 | version: "0.1.0", 92 | }, 93 | { 94 | capabilities: { 95 | resources: {}, 96 | tools: {}, 97 | prompts: {}, 98 | }, 99 | }, 100 | ); 101 | 102 | server.setRequestHandler(ListResourcesRequestSchema, async () => { 103 | return { 104 | resources, 105 | }; 106 | }); 107 | 108 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => { 109 | const url = new URL(request.params.uri); 110 | const title = decodeURIComponent(url.pathname.replace(/^\//, "")); 111 | 112 | const getPageResult = await getPage(projectName, title, cosenseSid); 113 | if (!getPageResult) { 114 | throw new Error(`Page ${title} not found`); 115 | } 116 | const readablePage = toReadablePage(getPageResult); 117 | const formattedText = [ 118 | `Title: ${readablePage.title}`, 119 | `Created: ${formatYmd(new Date(readablePage.created * 1000))}`, 120 | `Updated: ${formatYmd(new Date(readablePage.updated * 1000))}`, 121 | `Created user: ${readablePage.lastUpdateUser?.displayName || readablePage.user.displayName}`, 122 | `Last editor: ${readablePage.user.displayName}`, 123 | `Other editors: ${readablePage.collaborators 124 | .filter(collab => 125 | collab.id !== readablePage.user.id && 126 | collab.id !== readablePage.lastUpdateUser?.id 127 | ) 128 | .map(user => user.displayName) 129 | .join(', ')}`, 130 | '', 131 | readablePage.lines.map(line => line.text).join('\n'), 132 | '', 133 | `Links:\n${getPageResult.links.length > 0 134 | ? getPageResult.links.map((link: string) => `- ${link}`).join('\n') 135 | : '(None)'}` 136 | ].join('\n'); 137 | 138 | return { 139 | contents: [ 140 | { 141 | uri: request.params.uri, 142 | mimeType: "text/plain", 143 | text: formattedText, 144 | }, 145 | ], 146 | }; 147 | }); 148 | 149 | server.setRequestHandler(ListToolsRequestSchema, async () => { 150 | return { 151 | tools: [ 152 | { 153 | name: "create_page", 154 | description: ` 155 | Create a new page in ${projectName} project on ${SERVICE_LABEL} 156 | 157 | Creates a new page with the specified title and optional body text. 158 | The page will be opened in your default browser. 159 | `, 160 | inputSchema: { 161 | type: "object", 162 | properties: { 163 | title: { 164 | type: "string", 165 | description: "Title of the new page", 166 | }, 167 | body: { 168 | type: "string", 169 | description: "Content in markdown format that will be converted to Scrapbox format. Supports standard markdown syntax including links, code blocks, lists, and emphasis.", 170 | }, 171 | }, 172 | required: ["title"], 173 | }, 174 | }, 175 | { 176 | name: "get_page", 177 | description: ` 178 | Get a page from ${projectName} project on ${SERVICE_LABEL} 179 | Returns page content and its linked pages. 180 | Page content includes title and description in plain text format. 181 | `, 182 | inputSchema: { 183 | type: "object", 184 | properties: { 185 | pageTitle: { 186 | type: "string", 187 | description: "Title of the page", 188 | }, 189 | }, 190 | required: ["pageTitle"], 191 | }, 192 | }, 193 | { 194 | name: "list_pages", 195 | description: ` 196 | List pages from ${projectName} project on ${SERVICE_LABEL} with flexible sorting options. 197 | 198 | Available sorting methods: 199 | - updated: Sort by last update time 200 | - created: Sort by creation time 201 | - accessed: Sort by access time 202 | - linked: Sort by number of incoming links 203 | - views: Sort by view count 204 | - title: Sort by page title 205 | `, 206 | inputSchema: { 207 | type: "object", 208 | properties: { 209 | sort: { 210 | type: "string", 211 | enum: ["updated", "created", "accessed", "linked", "views", "title"], 212 | description: "Sort method for the page list", 213 | }, 214 | limit: { 215 | type: "number", 216 | minimum: 1, 217 | maximum: 1000, 218 | description: "Maximum number of pages to return (1-1000)", 219 | }, 220 | skip: { 221 | type: "number", 222 | minimum: 0, 223 | description: "Number of pages to skip", 224 | }, 225 | excludePinned: { 226 | type: "boolean", 227 | description: "Whether to exclude pinned pages from the results", 228 | }, 229 | }, 230 | required: [], 231 | }, 232 | }, 233 | { 234 | name: "search_pages", 235 | description: ` 236 | Search pages in ${projectName} project on ${SERVICE_LABEL} 237 | 238 | Supports various search features: 239 | - Basic search: "keyword" 240 | - Multiple keywords: "word1 word2" (AND search) 241 | - Exclude words: "word1 -word2" 242 | - Exact phrase: "\\"exact phrase\\"" 243 | `, 244 | inputSchema: { 245 | type: "object", 246 | properties: { 247 | query: { 248 | type: "string", 249 | description: "Search query string", 250 | }, 251 | }, 252 | required: ["query"], 253 | }, 254 | }, 255 | ], 256 | }; 257 | }); 258 | 259 | // list_pagesツールのハンドラーを修正 260 | server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { 261 | if (request.params.name === "list_pages") { 262 | const args = request.params.arguments || {}; 263 | 264 | const result = await listPages(projectName, cosenseSid, { 265 | sort: String(args.sort || ''), 266 | limit: Number(args.limit || 1000), 267 | skip: Number(args.skip || 0), 268 | excludePinned: Boolean(args.excludePinned || false) 269 | }); 270 | 271 | return { 272 | content: [{ 273 | type: "text", 274 | text: JSON.stringify(result, null, 2) 275 | }] 276 | }; 277 | } 278 | 279 | // 他のツールハンドラーが未実装の場合のデフォルトレスポンス 280 | return { 281 | content: [{ 282 | type: "text", 283 | text: "Tool not implemented" 284 | }] 285 | }; 286 | }); 287 | 288 | // ルートのセットアップ 289 | setupRoutes(server, { 290 | projectName, 291 | cosenseSid, 292 | }); 293 | 294 | async function main() { 295 | const transport = new StdioServerTransport(); 296 | await server.connect(transport); 297 | } 298 | 299 | main().catch((error) => { 300 | console.error([ 301 | 'Fatal Error:', 302 | `Message: ${error instanceof Error ? error.message : 'Unknown error'}`, 303 | `Timestamp: ${new Date().toISOString()}` 304 | ].join('\n')); 305 | process.exit(1); 306 | }); 307 | -------------------------------------------------------------------------------- /src/routes/handlers/create-page.ts: -------------------------------------------------------------------------------- 1 | import { createPageUrl } from "../../cosense.js"; 2 | import { convertMarkdownToScrapbox } from '../../utils/markdown-converter.js'; 3 | 4 | export interface CreatePageParams { 5 | title: string; 6 | body?: string; 7 | } 8 | 9 | export async function handleCreatePage( 10 | projectName: string, 11 | _cosenseSid: string | undefined, 12 | params: CreatePageParams 13 | ) { 14 | try { 15 | const title = String(params.title); 16 | const body = params.body; 17 | 18 | const convertedBody = body ? await convertMarkdownToScrapbox(body) : undefined; 19 | const url = createPageUrl(projectName, title, convertedBody); 20 | 21 | const { exec } = await import("child_process"); 22 | exec(`open "${url}"`); 23 | 24 | return { 25 | content: [{ 26 | type: "text", 27 | text: `Opening new page: ${title}\nURL: ${url}` 28 | }] 29 | }; 30 | } catch (error) { 31 | return { 32 | content: [{ 33 | type: "text", 34 | text: [ 35 | 'Error details:', 36 | `Message: ${error instanceof Error ? error.message : 'Unknown error'}`, 37 | `Operation: create_page`, 38 | `Project: ${projectName}`, 39 | `Title: ${params.title}`, 40 | `Timestamp: ${new Date().toISOString()}` 41 | ].join('\n') 42 | }], 43 | isError: true 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/routes/handlers/get-page.ts: -------------------------------------------------------------------------------- 1 | import { getPage, toReadablePage } from "../../cosense.js"; 2 | import { formatYmd } from '../../utils/format.js'; 3 | 4 | export interface GetPageParams { 5 | pageTitle: string; 6 | } 7 | 8 | export async function handleGetPage( 9 | projectName: string, 10 | cosenseSid: string | undefined, 11 | params: GetPageParams 12 | ) { 13 | try { 14 | const page = await getPage(projectName, params.pageTitle, cosenseSid); 15 | 16 | if (!page) { 17 | return { 18 | content: [{ 19 | type: "text", 20 | text: [ 21 | `Error: Page "${params.pageTitle}" not found`, 22 | `Operation: get_page`, 23 | `Project: ${projectName}`, 24 | `Status: 404`, 25 | `Timestamp: ${new Date().toISOString()}` 26 | ].join('\n') 27 | }], 28 | isError: true 29 | }; 30 | } 31 | 32 | const readablePage = toReadablePage(page); 33 | 34 | // ページ情報を整形 35 | const formattedText = [ 36 | `Title: ${readablePage.title}`, 37 | `Created: ${formatYmd(new Date(readablePage.created * 1000))}`, 38 | `Updated: ${formatYmd(new Date(readablePage.updated * 1000))}`, 39 | `Created user: ${readablePage.lastUpdateUser?.displayName || readablePage.user.displayName}`, 40 | `Last editor: ${readablePage.user.displayName}`, 41 | `Other editors: ${readablePage.collaborators 42 | .filter(collab => 43 | collab.id !== readablePage.user.id && 44 | collab.id !== readablePage.lastUpdateUser?.id 45 | ) 46 | .map(user => user.displayName) 47 | .join(', ')}` 48 | ].join('\n'); 49 | 50 | // 本文を追加 51 | const contentText = readablePage.lines.map(line => line.text).join('\n'); 52 | 53 | // リンク情報を追加 54 | const linksText = `\nLinks:\n${readablePage.links.length > 0 55 | ? readablePage.links.map((link: string) => `- ${link}`).join('\n') 56 | : '(None)'}`; 57 | 58 | const fullText = `${formattedText}\n\n${contentText}\n${linksText}`; 59 | return { 60 | content: [{ 61 | type: "text", 62 | text: fullText 63 | }] 64 | }; 65 | } catch (error) { 66 | return { 67 | content: [{ 68 | type: "text", 69 | text: [ 70 | 'Error details:', 71 | `Message: ${error instanceof Error ? error.message : 'Unknown error'}`, 72 | `Operation: get_page`, 73 | `Project: ${projectName}`, 74 | `Page: ${params.pageTitle}`, 75 | `Timestamp: ${new Date().toISOString()}` 76 | ].join('\n') 77 | }], 78 | isError: true 79 | }; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/routes/handlers/list-pages.ts: -------------------------------------------------------------------------------- 1 | import { type ListPagesResponse } from "../../cosense.js"; 2 | import { listPages, listPagesWithSort } from "../../cosense.js"; 3 | import { formatPageOutput, getSortDescription, getSortValue } from '../../utils/format.js'; 4 | 5 | export interface ListPagesParams { 6 | sort?: string; 7 | limit?: number; 8 | skip?: number; 9 | excludePinned?: boolean; 10 | } 11 | 12 | export async function handleListPages( 13 | projectName: string, 14 | cosenseSid: string | undefined, 15 | params: ListPagesParams 16 | ) { 17 | try { 18 | const { 19 | sort, 20 | limit = 1000, 21 | skip = 0, // デフォルト値を設定 22 | excludePinned = false 23 | } = params; 24 | let pages; 25 | 26 | if (excludePinned) { 27 | const targetLimit = limit || 10; 28 | let unpinnedPages: ListPagesResponse['pages'] = []; 29 | let currentSkip = skip || 0; 30 | 31 | while (unpinnedPages.length < targetLimit) { 32 | const fetchedPages = await listPages(projectName, cosenseSid, { 33 | sort, 34 | limit: targetLimit * 3, 35 | skip: currentSkip 36 | }); 37 | 38 | const newUnpinned = fetchedPages.pages.filter(page => !page.pin || page.pin === 0); 39 | unpinnedPages = unpinnedPages.concat(newUnpinned); 40 | 41 | if (fetchedPages.pages.length === 0) break; 42 | currentSkip += fetchedPages.pages.length; 43 | } 44 | 45 | pages = { 46 | ...await listPages(projectName, cosenseSid, { limit: 1 }), 47 | pages: unpinnedPages.slice(0, targetLimit), 48 | limit: targetLimit, 49 | skip: skip || 0 50 | }; 51 | } else { 52 | pages = await listPagesWithSort( 53 | projectName, 54 | { 55 | sort, 56 | limit: limit || 10, 57 | skip, 58 | }, 59 | cosenseSid 60 | ); 61 | } 62 | 63 | let output = [ 64 | `Project: ${projectName}`, 65 | `Total pages: ${pages.count}`, 66 | `Pages fetched: ${pages.limit}`, 67 | `Pages skipped: ${pages.skip}`, 68 | `Sort method: ${getSortDescription(sort)}`, 69 | '---' 70 | ].join('\n') + '\n'; 71 | 72 | output += pages.pages.map((page, index) => { 73 | const sortValue = getSortValue(page, sort); 74 | return formatPageOutput(page, index, { 75 | skip: skip || 0, 76 | showSort: true, 77 | sortValue: sortValue.formatted, 78 | showDescriptions: true // 冒頭5行を表示するオプションを有効化 79 | }) + '\n---'; 80 | }).join('\n'); 81 | 82 | return { 83 | content: [{ 84 | type: "text", 85 | text: output 86 | }] 87 | }; 88 | } catch (error) { 89 | return { 90 | content: [{ 91 | type: "text", 92 | text: [ 93 | 'Error details:', 94 | `Message: ${error instanceof Error ? error.message : 'Unknown error'}`, 95 | `Operation: list_pages`, 96 | `Project: ${projectName}`, 97 | `Sort: ${params.sort || 'default'}`, 98 | `Limit: ${params.limit || 'default'}`, 99 | `Skip: ${params.skip || '0'}`, 100 | `ExcludePinned: ${params.excludePinned}`, 101 | `Timestamp: ${new Date().toISOString()}` 102 | ].join('\n') 103 | }], 104 | isError: true 105 | }; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/routes/handlers/search-pages.ts: -------------------------------------------------------------------------------- 1 | import { searchPages } from "../../cosense.js"; 2 | import { formatPageOutput } from '../../utils/format.js'; 3 | 4 | export interface SearchPagesParams { 5 | query: string; 6 | } 7 | 8 | export async function handleSearchPages( 9 | projectName: string, 10 | cosenseSid: string | undefined, 11 | params: SearchPagesParams 12 | ) { 13 | try { 14 | const query = String(params.query); 15 | const results = await searchPages(projectName, query, cosenseSid); 16 | 17 | if (!results) { 18 | return { 19 | content: [{ 20 | type: "text", 21 | text: [ 22 | `Error: No search results`, 23 | `Operation: search_pages`, 24 | `Project: ${projectName}`, 25 | `Query: ${query}`, 26 | `Status: 404`, 27 | `Timestamp: ${new Date().toISOString()}` 28 | ].join('\n') 29 | }], 30 | isError: true 31 | }; 32 | } 33 | 34 | let output = [ 35 | `Project: ${projectName}`, 36 | `Search query: ${results.searchQuery}`, 37 | `Total results: ${results.count}`, 38 | `Note: Limited to 100 results. No way to fetch beyond this limit. If expected content is not found, please try refining your search query.`, 39 | '---' 40 | ].join('\n') + '\n'; 41 | 42 | output += results.pages.map((page, index) => 43 | formatPageOutput(page, index, { 44 | showMatches: true, 45 | showSnippet: true, 46 | isSearchResult: true // 検索結果であることを示すフラグを追加 47 | }) + '\n---' 48 | ).join('\n'); 49 | 50 | return { 51 | content: [{ 52 | type: "text", 53 | text: output 54 | }] 55 | }; 56 | } catch (error) { 57 | return { 58 | content: [{ 59 | type: "text", 60 | text: [ 61 | 'Error details:', 62 | `Message: ${error instanceof Error ? error.message : 'Unknown error'}`, 63 | `Operation: search_pages`, 64 | `Project: ${projectName}`, 65 | `Query: ${params.query}`, 66 | `Timestamp: ${new Date().toISOString()}` 67 | ].join('\n') 68 | }], 69 | isError: true 70 | }; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/routes/index.ts: -------------------------------------------------------------------------------- 1 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 2 | import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js"; 3 | import { handleListPages } from './handlers/list-pages.js'; 4 | import { handleGetPage } from './handlers/get-page.js'; 5 | import { handleSearchPages } from './handlers/search-pages.js'; 6 | import { handleCreatePage } from './handlers/create-page.js'; 7 | 8 | export function setupRoutes( 9 | server: Server, 10 | config: { 11 | projectName: string; 12 | cosenseSid?: string; 13 | } 14 | ) { 15 | server.setRequestHandler(CallToolRequestSchema, async (request) => { 16 | const { projectName, cosenseSid } = config; 17 | 18 | switch (request.params.name) { 19 | case "list_pages": 20 | return handleListPages( 21 | projectName, 22 | cosenseSid, 23 | request.params.arguments || {} 24 | ); 25 | 26 | case "get_page": 27 | return handleGetPage( 28 | projectName, 29 | cosenseSid, 30 | { 31 | pageTitle: String(request.params.arguments?.pageTitle) 32 | } 33 | ); 34 | 35 | case "search_pages": 36 | return handleSearchPages( 37 | projectName, 38 | cosenseSid, 39 | { 40 | query: String(request.params.arguments?.query) 41 | } 42 | ); 43 | 44 | case "create_page": 45 | return handleCreatePage( 46 | projectName, 47 | cosenseSid, 48 | { 49 | title: String(request.params.arguments?.title), 50 | body: request.params.arguments?.body as string | undefined 51 | } 52 | ); 53 | 54 | default: 55 | return { 56 | content: [{ 57 | type: "text", 58 | text: [ 59 | 'Error details:', 60 | 'Message: Unknown tool requested', 61 | `Tool: ${request.params.name}`, 62 | `Timestamp: ${new Date().toISOString()}` 63 | ].join('\n') 64 | }], 65 | isError: true 66 | }; 67 | } 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /src/types/api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Scrapbox API関連の型定義 3 | */ 4 | 5 | /** 6 | * Scrapboxページの基本情報 7 | */ 8 | export interface ScrapboxPage { 9 | id: string; 10 | title: string; 11 | created: number; 12 | updated: number; 13 | accessed: number; 14 | persistent: boolean; 15 | lines: ScrapboxLine[]; 16 | descriptions?: string[]; // 冒頭5行を追加 17 | } 18 | 19 | /** 20 | * Scrapboxページの行 21 | */ 22 | export interface ScrapboxLine { 23 | id: string; 24 | text: string; 25 | created: number; 26 | updated: number; 27 | } 28 | 29 | /** 30 | * ページ一覧取得APIのレスポンス 31 | */ 32 | export interface ListPagesResponse { 33 | pages: Array<{ 34 | id: string; 35 | title: string; 36 | updated: number; 37 | accessed: number; 38 | created: number; 39 | persistent: boolean; 40 | descriptions?: string[]; // 冒頭5行を追加 41 | }>; 42 | skip?: number; 43 | limit?: number; 44 | count?: number; 45 | } 46 | 47 | /** 48 | * ページ検索APIのレスポンス 49 | */ 50 | export interface SearchPagesResponse { 51 | pages: Array<{ 52 | id: string; 53 | title: string; 54 | updated: number; 55 | accessed: number; 56 | created: number; 57 | persistent: boolean; 58 | match?: string[]; 59 | }>; 60 | } 61 | 62 | /** 63 | * ページ作成APIのリクエストパラメータ 64 | */ 65 | export interface CreatePageParams { 66 | title: string; 67 | lines: string[]; 68 | } 69 | 70 | /** 71 | * ページ作成APIのレスポンス 72 | */ 73 | export interface CreatePageResponse { 74 | id: string; 75 | title: string; 76 | created: number; 77 | updated: number; 78 | accessed: number; 79 | persistent: boolean; 80 | } 81 | 82 | /** 83 | * APIリクエストの共通パラメータ 84 | */ 85 | export interface CommonApiParams { 86 | projectName: string; 87 | cookie: string; 88 | } 89 | 90 | /** 91 | * ページ一覧取得APIのパラメータ 92 | */ 93 | export interface ListPagesParams extends CommonApiParams { 94 | skip?: number; 95 | limit?: number; 96 | } 97 | 98 | /** 99 | * ページ検索APIのパラメータ 100 | */ 101 | export interface SearchPagesParams extends CommonApiParams { 102 | query: string; 103 | } 104 | 105 | /** 106 | * ページ取得APIのパラメータ 107 | */ 108 | export interface GetPageParams extends CommonApiParams { 109 | pageId: string; 110 | } 111 | -------------------------------------------------------------------------------- /src/types/common.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 共通の型定義 3 | */ 4 | export interface AuthParams { 5 | cookie: string; // cosenseSidに統一 6 | projectName: string; 7 | } 8 | 9 | export interface PaginationParams { 10 | skip?: number; 11 | limit?: number; 12 | } 13 | -------------------------------------------------------------------------------- /src/types/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * サーバー設定関連の型定義 3 | */ 4 | 5 | /** 6 | * サーバー設定の型定義 7 | */ 8 | export interface ServerConfig { 9 | /** サーバー名 */ 10 | name: string; 11 | /** バージョン */ 12 | version: string; 13 | /** 環境変数 */ 14 | env: EnvConfig; 15 | } 16 | 17 | /** 18 | * 環境変数の型定義 19 | */ 20 | export interface EnvConfig { 21 | /** Scrapboxのプロジェクト名 */ 22 | SCRAPBOX_PROJECT?: string; 23 | /** Scrapboxの認証Cookie */ 24 | SCRAPBOX_COOKIE?: string; 25 | /** デバッグモードの有効/無効 */ 26 | DEBUG?: boolean; 27 | /** APIのベースURL */ 28 | API_BASE_URL?: string; 29 | } 30 | 31 | /** 32 | * 設定のバリデーション結果 33 | */ 34 | export interface ConfigValidationResult { 35 | /** バリデーションが成功したかどうか */ 36 | isValid: boolean; 37 | /** エラーメッセージ(バリデーション失敗時) */ 38 | errors?: string[]; 39 | } 40 | 41 | /** 42 | * デフォルトの設定値 43 | */ 44 | export const DEFAULT_CONFIG: Partial = { 45 | name: "scrapbox-mcp-server", 46 | version: "1.0.0", 47 | }; 48 | 49 | /** 50 | * APIエンドポイントの設定 51 | */ 52 | export const API_ENDPOINTS = { 53 | /** ページ一覧取得 */ 54 | LIST_PAGES: "/api/pages", 55 | /** ページ検索 */ 56 | SEARCH_PAGES: "/api/pages/search", 57 | /** ページ取得 */ 58 | GET_PAGE: "/api/pages/:pageId", 59 | /** ページ作成 */ 60 | CREATE_PAGE: "/api/pages", 61 | } as const; 62 | 63 | /** 64 | * 設定のデフォルト値 65 | */ 66 | export const DEFAULT_ENV_CONFIG: EnvConfig = { 67 | API_BASE_URL: "https://scrapbox.io", 68 | DEBUG: false, 69 | }; 70 | 71 | /** 72 | * 設定のバリデーション関数の型定義 73 | */ 74 | export type ConfigValidator = (config: ServerConfig) => ConfigValidationResult; 75 | -------------------------------------------------------------------------------- /src/types/error.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Scrapbox MCPサーバーのエラー型定義 3 | */ 4 | 5 | import { ErrorCode } from '@modelcontextprotocol/sdk/types.js'; 6 | 7 | // MCPエラーコードの拡張 8 | export enum ScrapboxErrorCode { 9 | AUTH_ERROR = 'AUTH_ERROR', 10 | NOT_FOUND = 'NOT_FOUND', 11 | RATE_LIMIT = 'RATE_LIMIT', 12 | API_ERROR = 'API_ERROR', 13 | } 14 | 15 | /** 16 | * MCPエラーレスポンスの型定義 17 | */ 18 | export interface ErrorResponse { 19 | success: false; 20 | error: { 21 | code: ErrorCode | ScrapboxErrorCode; 22 | message: string; 23 | details?: unknown; 24 | }; 25 | } 26 | 27 | /** 28 | * Scrapbox APIエラーの型定義 29 | */ 30 | export interface ScrapboxApiError extends Error { 31 | status: number; 32 | response?: { 33 | data?: unknown; 34 | }; 35 | } 36 | 37 | /** 38 | * エラー情報をMCPエラーレスポンスに変換するユーティリティ関数の型定義 39 | */ 40 | export type ErrorConverter = (error: unknown) => ErrorResponse; 41 | 42 | /** 43 | * MCPエラーレスポンスを生成するユーティリティ関数 44 | * @param code エラーコード 45 | * @param message エラーメッセージ 46 | * @param details 追加のエラー詳細情報(オプション) 47 | */ 48 | export const createErrorResponse = ( 49 | code: ErrorCode | ScrapboxErrorCode, 50 | message: string, 51 | details?: unknown 52 | ): ErrorResponse => ({ 53 | success: false, 54 | error: { 55 | code, 56 | message, 57 | details, 58 | }, 59 | }); 60 | -------------------------------------------------------------------------------- /src/types/handlers.ts: -------------------------------------------------------------------------------- 1 | import { AuthParams, PaginationParams } from './common.js'; 2 | import { ErrorResponse } from './error.js'; 3 | import { 4 | ListPagesResponse, 5 | SearchPagesResponse, 6 | CreatePageResponse, 7 | ScrapboxPage, 8 | } from './api.js'; 9 | 10 | /** 11 | * MCPハンドラーの共通レスポンス型 12 | * 成功時のレスポンスまたはエラーレスポンスを返す 13 | */ 14 | export type HandlerResponse = T | ErrorResponse; 15 | 16 | /** 17 | * リストページハンドラーのパラメータ型定義 18 | */ 19 | export interface ListPagesHandlerParams extends PaginationParams { 20 | cosenseSid: string; 21 | projectName: string; 22 | } 23 | 24 | /** 25 | * 検索ページハンドラーのパラメータ型定義 26 | */ 27 | export interface SearchPagesHandlerParams extends PaginationParams { 28 | cosenseSid: string; 29 | projectName: string; 30 | query: string; 31 | } 32 | 33 | /** 34 | * ページ取得ハンドラーの入力パラメータ 35 | */ 36 | export interface GetPageHandlerParams extends AuthParams { 37 | pageId: string; 38 | } 39 | 40 | /** 41 | * ページ作成ハンドラーの入力パラメータ 42 | */ 43 | export interface CreatePageHandlerParams extends AuthParams { 44 | title: string; 45 | content: string; 46 | } 47 | 48 | /** 49 | * 各ハンドラーのレスポンス型 50 | */ 51 | export type ListPagesHandlerResponse = HandlerResponse<{ 52 | success: true; 53 | data: ListPagesResponse; 54 | }>; 55 | 56 | export type SearchPagesHandlerResponse = HandlerResponse<{ 57 | success: true; 58 | data: SearchPagesResponse; 59 | }>; 60 | 61 | export type GetPageHandlerResponse = HandlerResponse<{ 62 | success: true; 63 | data: ScrapboxPage; 64 | }>; 65 | 66 | export type CreatePageHandlerResponse = HandlerResponse<{ 67 | success: true; 68 | data: CreatePageResponse; 69 | }>; 70 | 71 | /** 72 | * ハンドラー関数の型定義 73 | */ 74 | export type RequestHandler = (params: P) => Promise; 75 | -------------------------------------------------------------------------------- /src/utils/format.ts: -------------------------------------------------------------------------------- 1 | // 基本的なページ型を定義 2 | export interface BasePage { 3 | title: string; 4 | created?: number; 5 | updated?: number; 6 | pin?: number; 7 | user?: { 8 | id: string; 9 | name: string; 10 | displayName: string; 11 | photo: string; 12 | }; 13 | lastUpdateUser?: { 14 | id: string; 15 | name: string; 16 | displayName: string; 17 | photo: string; 18 | }; 19 | lastAccessed?: number; 20 | accessed?: number; 21 | views?: number; 22 | linked?: number; 23 | } 24 | 25 | // 検索結果用の拡張ページ型 26 | interface ExtendedPage extends BasePage { 27 | words?: string[]; 28 | lines?: string[]; 29 | collaborators?: Array<{ 30 | id: string; 31 | name: string; 32 | displayName: string; 33 | photo: string; 34 | }>; 35 | descriptions?: string[]; // 冒頭5行を追加 36 | } 37 | 38 | export interface PageMetadata { 39 | title: string; 40 | created?: number; 41 | updated?: number; 42 | pin?: number | boolean; 43 | user?: { 44 | id: string; 45 | name: string; 46 | displayName: string; 47 | photo: string; 48 | }; 49 | lastUpdateUser?: { 50 | id: string; 51 | name: string; 52 | displayName: string; 53 | photo: string; 54 | }; 55 | collaborators?: Array<{ 56 | id: string; 57 | displayName: string; 58 | }>; 59 | words?: string[]; 60 | lines?: string[]; 61 | debug?: { 62 | warning?: string; 63 | error?: string; 64 | }; 65 | } 66 | 67 | export interface FormatPageOptions { 68 | skip?: number; 69 | showSort?: boolean; 70 | showMatches?: boolean; 71 | sortValue?: string | null; 72 | showSnippet?: boolean; 73 | } 74 | 75 | export function formatYmd(date: Date): string { 76 | const y = date.getFullYear(); 77 | const m = date.getMonth() + 1; 78 | const d = date.getDate(); 79 | return `${y}/${m}/${d}`; 80 | } 81 | 82 | export function getSortDescription(sortMethod: string | undefined): string { 83 | const base = { 84 | updated: "Sorted by last updated", 85 | created: "Sorted by creation date", 86 | accessed: "Sorted by last accessed", 87 | linked: "Sorted by number of incoming links", 88 | views: "Sorted by view count", 89 | title: "Sorted by title" 90 | }[sortMethod || ''] || "Default order"; 91 | 92 | return `${base}`; 93 | } 94 | 95 | export function getSortValue(page: ScrapboxPage, sortMethod: string | undefined): { 96 | value: number | string | null; 97 | formatted: string; 98 | } { 99 | switch (sortMethod) { 100 | case 'updated': 101 | return { 102 | value: page.updated || 0, 103 | formatted: page.updated ? formatYmd(new Date(page.updated * 1000)) : 'Not available' 104 | }; 105 | case 'created': 106 | return { 107 | value: page.created || 0, 108 | formatted: page.created ? formatYmd(new Date(page.created * 1000)) : 'Not available' 109 | }; 110 | case 'accessed': 111 | const accessTime = page.accessed || page.lastAccessed || 0; 112 | return { 113 | value: accessTime, 114 | formatted: accessTime ? formatYmd(new Date(accessTime * 1000)) : 'Not available' 115 | }; 116 | case 'linked': 117 | return { 118 | value: page.linked || 0, 119 | formatted: String(page.linked || 0) 120 | }; 121 | case 'views': 122 | return { 123 | value: page.views || 0, 124 | formatted: String(page.views || 0) 125 | }; 126 | case 'title': 127 | return { 128 | value: page.title, 129 | formatted: page.title 130 | }; 131 | default: 132 | return { 133 | value: null, 134 | formatted: 'Not specified' 135 | }; 136 | } 137 | } 138 | 139 | export function formatPageOutput( 140 | page: ExtendedPage, 141 | index: number, 142 | options: { 143 | skip?: number, 144 | showSort?: boolean, 145 | sortValue?: string, 146 | showMatches?: boolean, 147 | showSnippet?: boolean, 148 | isSearchResult?: boolean, // 追加: 検索結果かどうかのフラグ 149 | showDescriptions?: boolean // 冒頭5行表示オプションを追加 150 | } = {} 151 | ): string { 152 | const lines = [ 153 | `Page number: ${(options.skip || 0) + index + 1}`, 154 | `Title: ${page.title}` 155 | ]; 156 | 157 | // 検索結果以外の場合のみ日付を表示 158 | if (!options.isSearchResult) { 159 | lines.push( 160 | `Created: ${formatYmd(new Date((page.created || 0) * 1000))}`, 161 | `Updated: ${formatYmd(new Date((page.updated || 0) * 1000))}` 162 | ); 163 | } 164 | 165 | lines.push(`Pinned: ${page.pin ? 'Yes' : 'No'}`); 166 | 167 | if (options.showMatches && page.words) { 168 | lines.push(`Matched words: ${page.words.join(', ')}`); 169 | } 170 | 171 | if (options.showSort && options.sortValue) { 172 | lines.push(`Sort value: ${options.sortValue}`); 173 | } 174 | 175 | // 作成者の表示 176 | if (page.user) { 177 | lines.push(`Created user: ${page.user.displayName}`); 178 | } 179 | 180 | // 最終更新者の表示 181 | if (page.lastUpdateUser) { 182 | lines.push(`Last editor: ${page.lastUpdateUser.displayName}`); 183 | } 184 | 185 | if (page.collaborators && page.collaborators.length > 0) { 186 | const uniqueCollaborators = page.collaborators 187 | .filter(collab => 188 | collab.id !== page.user?.id && 189 | collab.id !== page.lastUpdateUser?.id 190 | ) 191 | .map(collab => collab.displayName) 192 | .filter((value, index, self) => self.indexOf(value) === index); 193 | 194 | if (uniqueCollaborators.length > 0) { 195 | lines.push(`Other editors: ${uniqueCollaborators.join(', ')}`); 196 | } 197 | } 198 | 199 | if (options.showSnippet && page.lines) { 200 | lines.push('Snippet:'); 201 | lines.push(page.lines.join('\n')); 202 | } 203 | 204 | if (options.showDescriptions && page.descriptions?.length) { 205 | lines.push('Description:'); 206 | lines.push(page.descriptions.join('\n')); 207 | } 208 | 209 | return lines.join('\n'); 210 | } 211 | 212 | // ScrapboxPageインターフェースをBasePageから継承 213 | export interface ScrapboxPage extends BasePage {} 214 | -------------------------------------------------------------------------------- /src/utils/markdown-converter.ts: -------------------------------------------------------------------------------- 1 | import md2sb from 'md2sb'; 2 | 3 | export async function convertMarkdownToScrapbox(markdown: string): Promise { 4 | // md2sbを直接呼び出し、エラーは上位に伝播させる 5 | return await md2sb.default(markdown); 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/sort.ts: -------------------------------------------------------------------------------- 1 | import type { ScrapboxPage } from '../cosense.js'; 2 | 3 | export interface SortOptions { 4 | sort?: string; 5 | excludePinned?: boolean; 6 | } 7 | 8 | export function sortPages(pages: ScrapboxPage[], options: SortOptions = {}): ScrapboxPage[] { 9 | const { sort, excludePinned } = options; 10 | 11 | // ピン留めページのフィルタリング 12 | let filteredPages = excludePinned 13 | ? pages.filter(page => !page.pin) 14 | : pages; 15 | 16 | // ソート処理 17 | return [...filteredPages].sort((a, b) => { 18 | // ピン留めを考慮しないソート 19 | const compareValues = () => { 20 | switch (sort) { 21 | case 'updated': 22 | return (b.updated || 0) - (a.updated || 0); 23 | case 'created': 24 | return (b.created || 0) - (a.created || 0); 25 | case 'accessed': 26 | const aAccess = a.accessed || 0; 27 | const bAccess = b.accessed || 0; 28 | return bAccess - aAccess; 29 | case 'linked': 30 | return (b.linked || 0) - (a.linked || 0); 31 | case 'views': 32 | return (b.views || 0) - (a.views || 0); 33 | case 'title': 34 | return a.title.localeCompare(b.title); 35 | default: 36 | return (b.created || 0) - (a.created || 0); 37 | } 38 | }; 39 | 40 | return compareValues(); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ES2020", 5 | "lib": ["ES2022", "DOM", "DOM.Iterable"], 6 | "module": "node16", 7 | "moduleResolution": "nodenext", 8 | "outDir": "build", 9 | "rootDir": "src", 10 | "strict": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "allowJs": true, 15 | "declaration": true 16 | }, 17 | "include": ["src/**/*"], 18 | "exclude": ["node_modules", "build"] 19 | } 20 | --------------------------------------------------------------------------------