├── .gitignore
├── README.md
├── doc
├── img.png
├── img_1.png
└── img_2.png
├── package-lock.json
├── package.json
├── phpMyAdmin
├── .gitkeep
└── config.inc.php
├── pnpm-lock.yaml
├── src
├── login.html
├── main.js
└── networking
│ ├── inbound-tcp-to-ws-proxy.js
│ ├── outbound-ws-to-tcp-proxy.js
│ ├── php.ini
│ ├── utils.js
│ └── with-networking.js
└── tests
├── fetch-hook.js
├── http-hook.js
├── ip-hook.js
└── ws-hook.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | phpMyAdmin
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PMAtron (phpmyadmin现代风格)
2 |
3 | 
4 | 
5 | 
6 | 
7 |
8 | PMAtron 是一款基于 Electron 的创新桌面应用,能在本地为你呈现完整的 phpMyAdmin 功能体验。它巧妙运用了 PHP-WASM 技术,让你无需传统 PHP 服务器环境即可直接享有 phpMyAdmin 的全部功能。
9 |
10 | #### 登录
11 |
12 |
13 | #### MySQL GUI
14 |
15 |
16 | ## ✨ 功能特色
17 |
18 | PMAtron 为你重新定义使用 phpMyAdmin 的方式,带来:
19 |
20 | - **零配置体验**:无需搭建任何 Web 服务器或 PHP 环境,即刻启动、使用 phpMyAdmin。
21 | - **原生桌面体验**:以桌面应用形式运行,提供更顺畅、更直观的操作。
22 | - **增强安全性**:自定义协议的实现,为传统浏览器访问方式提供更多安全保护层。
23 | - **跨平台支持**:可在 Windows、macOS 和 Linux 上无缝运行。
24 | - **离线能力**:即使在无网络环境下,也能对本地数据库进行访问与管理。
25 | - **现代架构**:基于 Electron 与 PHP-WASM,提供高性能与高可靠性的稳定体验。
26 |
27 | ## 加入我们(利用休息时间维护,开发不易,帮忙点个Star)
28 | 加入我们的技术交流微信群!
29 |
30 | 如果你对 PMAtron 项目有兴趣,想了解更多技术细节、交流使用经验或参与社区贡献,欢迎扫码加入我们的技术交流微信群。
31 |
32 |
33 |
34 | 入群你将获得:
35 |
36 | - 最新开发进度与版本更新信息
37 | - 社区开发者的经验分享与技术答疑
38 | - 使用技巧、BUG 反馈、功能建议的讨论平台
39 | - 第一时间参与社区活动与新特性测试
40 |
41 | 请在加群时备注你的 GitHub 用户名或关注的方向,以便我们更好地为你提供帮助。
42 |
43 | ## 🚀 快速开始
44 |
45 | 运行 PMAtron 非常简单:
46 |
47 | #### 前置条件
48 | - 目前只支持windows
49 | - 下载phpMyAdmin解压到 phpMyAdmin目录 https://www.phpmyadmin.net/downloads/
50 |
51 | #### 安装依赖
52 | ```bash
53 | # 克隆仓库
54 | git clone https://github.com/maskerprc/pmatron.git
55 |
56 | # 进入项目目录
57 | cd pmatron
58 |
59 | # 安装依赖
60 | npm install
61 |
62 | # 启动应用程序
63 | npm start
64 | ```
65 |
66 | ## 🗺️ 开发里程碑
67 |
68 | 以下是 PMAtron 的开发里程碑:
69 |
70 | - [x] **通过 UI 选择当前登录的 MySQL 数据库账号密码**
71 | 允许用户通过图形界面方便地选择和管理 MySQL 数据库的登录凭证。
72 |
73 | - [ ] **支持使用 HTTP 和 SOCKS5 代理访问 MySQL**
74 | 实现通过 HTTP 和 SOCKS5 代理服务器连接到 MySQL 数据库,增强网络连接的灵活性和安全性。
75 |
76 | - [ ] **优化 UI 交互体验,通过 Hack CSS 的方式**
77 | 通过自定义 CSS 样式提升用户界面的美观性和交互的流畅性,提供更好的用户体验。
78 |
79 | - [ ] **支持 PostgreSQL 和 SQLite 数据库**
80 | 扩展数据库支持范围,增加对 PostgreSQL 和 SQLite 的兼容,满足更多用户的需求。
81 |
82 | - [ ] **支持自动更新客户端**
83 | 实现客户端的自动更新功能,确保用户始终使用最新版本,享受最新的功能和安全补丁。
84 |
85 | - [ ] **支持连接导入导出**
86 | 提供连接配置的导入和导出功能,方便用户在不同设备或环境中快速配置数据库连接。
87 |
88 | - [ ] **支持多用户**
89 | 增加多用户支持,允许多个用户在同一客户端中管理不同的数据库连接和配置。
90 |
91 | - [ ] **多语言 i18n 支持**
92 | 实现国际化(i18n),支持多种语言界面,方便全球用户使用 PMAtron。
93 |
94 |
95 | ## 🤝 欢迎贡献
96 |
97 | 我们非常欢迎社区贡献!你可以通过以下方式参与到 PMAtron 的建设中:
98 |
99 | ### 开发流程
100 | 1. Fork 本仓库
101 | 2. 创建分支以添加新特性(`git checkout -b feature/AmazingFeature`)
102 | 3. 提交你的改动(`git commit -m 'Add some AmazingFeature'`)
103 | 4. 推送到远程分支(`git push origin feature/AmazingFeature`)
104 | 5. 发起 Pull Request
105 |
106 | ### 开发环境搭建
107 |
108 | ```bash
109 | # 安装开发依赖
110 | npm install --dev
111 |
112 | # 运行测试
113 | npm test
114 |
115 | # 构建生产版本
116 | npm run build
117 | ```
118 |
119 | ### 代码规范
120 | - 遵循现有的代码风格
121 | - 使用有意义的变量与函数命名
122 | - 对复杂逻辑添加必要的注释
123 | - 为新增特性编写测试
124 |
125 | ## 📈 项目成长轨迹
126 |
127 | [](https://star-history.com/#MaskerPRC/pmatron&Date)
128 |
129 | 自项目诞生以来,得益于出色的社区成员与用户,我们的星标与关注度持续增长。
130 |
131 | ## 🙏 致谢
132 |
133 | PMAtron 的成长离不开众多优秀项目与社区的贡献与支持:
134 |
135 | - 感谢 phpMyAdmin 团队提供出色的数据库管理工具
136 | - 感谢 Electron 团队,让跨平台桌面应用成为可能
137 | - 感谢 PHP-WASM 项目,为我们带来在浏览器环境中运行 PHP 的新思路
138 | - 感谢所有为 PMAtron 做出贡献的开发者与社区成员
139 | - 感谢每一位为本项目加星标、Fork 或反馈问题的用户
140 |
141 | ## 📄 授权许可
142 |
143 | PMAtron 在 MIT 许可下发布。详情请查看 [LICENSE](LICENSE) 文件。
144 |
145 | ---
146 |
147 |
148 | 以 ❤️ 倾注的 PMAtron 团队
149 |
150 |
--------------------------------------------------------------------------------
/doc/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaskerPRC/pmatron/138efdc59a10bfe805dfde49bd4061a36e0ecaed/doc/img.png
--------------------------------------------------------------------------------
/doc/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaskerPRC/pmatron/138efdc59a10bfe805dfde49bd4061a36e0ecaed/doc/img_1.png
--------------------------------------------------------------------------------
/doc/img_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaskerPRC/pmatron/138efdc59a10bfe805dfde49bd4061a36e0ecaed/doc/img_2.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pmatron",
3 | "version": "1.0.0",
4 | "main": "src/main.js",
5 | "type": "module",
6 | "scripts": {
7 | "start": "electron src/main.js"
8 | },
9 | "private": true,
10 | "dependencies": {
11 | "@php-wasm/logger": "^1.0.15",
12 | "@php-wasm/node": "^1.0.14",
13 | "@php-wasm/scopes": "^1.0.14",
14 | "@php-wasm/universal": "^1.0.14",
15 | "@wp-playground/wordpress": "^1.0.14",
16 | "axios": "^1.7.9",
17 | "compressible": "^2.0.18",
18 | "compression": "^1.7.5",
19 | "electron": "^30.1.0",
20 | "express": "^4.19.2",
21 | "file-url": "^4.0.0",
22 | "http-proxy": "^1.18.1",
23 | "https-proxy-agent": "^7.0.6",
24 | "node-fetch": "^3.3.2",
25 | "ws": "^8.18.0"
26 | },
27 | "keywords": [],
28 | "author": "",
29 | "license": "ISC",
30 | "description": ""
31 | }
32 |
--------------------------------------------------------------------------------
/phpMyAdmin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaskerPRC/pmatron/138efdc59a10bfe805dfde49bd4061a36e0ecaed/phpMyAdmin/.gitkeep
--------------------------------------------------------------------------------
/phpMyAdmin/config.inc.php:
--------------------------------------------------------------------------------
1 | .
8 | */
9 |
10 | declare(strict_types=1);
11 |
12 | /**
13 | * This is needed for cookie based authentication to encrypt the cookie.
14 | * Needs to be a 32-bytes long string of random bytes. See FAQ 2.10.
15 | */
16 | $cfg['blowfish_secret'] = 'jukt3J4qjoQvtans15ApZwz7mjVhBnEn'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
17 | $cfg['CheckConfigurationPermissions'] = false;
18 |
19 | $i = 0;
20 | $i++;
21 |
22 | $cfg['Servers'][$i]['AllowNoPassword'] = true;
23 | $cfg['Servers'][$i]['host'] = '127.0.0.1';
24 | /* Authentication type */
25 | $cfg['Servers'][$i]['auth_type'] = 'config';
26 | $cfg['Servers'][$i]['user'] = 'root';
27 | $cfg['Servers'][$i]['password'] = 'root';
28 | $cfg['Servers'][$i]['controluser'] = 'root';
29 | $cfg['Servers'][$i]['controlpass'] = 'root';
30 |
31 |
32 |
33 | $cfg['UploadDir'] = '';
34 | $cfg['SaveDir'] = '';
35 |
36 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | '@php-wasm/node':
12 | specifier: ^1.0.14
13 | version: 1.0.14
14 | '@php-wasm/scopes':
15 | specifier: ^1.0.14
16 | version: 1.0.14
17 | '@php-wasm/universal':
18 | specifier: ^1.0.14
19 | version: 1.0.14
20 | '@wp-playground/wordpress':
21 | specifier: ^1.0.14
22 | version: 1.0.14
23 | axios:
24 | specifier: ^1.7.9
25 | version: 1.7.9
26 | compressible:
27 | specifier: ^2.0.18
28 | version: 2.0.18
29 | compression:
30 | specifier: ^1.7.5
31 | version: 1.7.5
32 | electron:
33 | specifier: ^30.1.0
34 | version: 30.5.1
35 | express:
36 | specifier: ^4.19.2
37 | version: 4.21.2
38 | file-url:
39 | specifier: ^4.0.0
40 | version: 4.0.0
41 | node-fetch:
42 | specifier: ^3.3.2
43 | version: 3.3.2
44 |
45 | packages:
46 |
47 | '@electron/get@2.0.3':
48 | resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
49 | engines: {node: '>=12'}
50 |
51 | '@php-wasm/logger@1.0.14':
52 | resolution: {integrity: sha512-sDzjT1Aj9bEDw+rs03tvZoPAFB6Hb0nU5ZTBPa6J9Uqx2M6F1ir0tYZ8orgOsVpX1BaEO0JI7V6SZT99N5nsbw==}
53 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
54 |
55 | '@php-wasm/node-polyfills@1.0.14':
56 | resolution: {integrity: sha512-59R0dcMlQrrps/QmZjN3LC6x9Db70/8RIrEbqcgog6II0cZGjBWeSIftyccj6g1vnK9ZKLUfKHCI5SphJUlYBg==}
57 |
58 | '@php-wasm/node@1.0.14':
59 | resolution: {integrity: sha512-qmnC+QwMBfDiiv/J6yh6M5IoeH6hGc9KmP8dXiUT+2yVOBjriBaAhMZaXcndgB3sh2iRnMtA+MHUJJLOfoh24w==}
60 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
61 |
62 | '@php-wasm/progress@1.0.14':
63 | resolution: {integrity: sha512-hhlvTCicBvoBL8Bb73aRRiCbOvvPzmGvdo8nifpVw5ykCbv5suScbMiB3kcaBB/rRK4NhEdsNF5cba/BhF5n3Q==}
64 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
65 |
66 | '@php-wasm/scopes@1.0.14':
67 | resolution: {integrity: sha512-ceKv2Y0vx6bvtsLYeTBJeXaiSPS/Gw7NK+mhUjLDgRpuxVenl2Ek6/z6WQ8IU4gI+7Hg4mKIDF4N3Aj7gGjYxw==}
68 | engines: {node: '>=16.15.1', npm: '>=8.11.0'}
69 |
70 | '@php-wasm/stream-compression@1.0.14':
71 | resolution: {integrity: sha512-QZDrar+DpNaOYM1r1hIcCCfZ59IDKT57UeuuNYUuE+KBFafQapsPopPlUycafcvbhpbZTrQI+uMy5miaKRWf9A==}
72 |
73 | '@php-wasm/universal@1.0.14':
74 | resolution: {integrity: sha512-GuQ5E+oiXcaUsrbnQF+XI/UX0nV9DLh4LUEtJDUQAA9/KcEGkmMV+yRhFR2HfMW/qP4V1PlDlsG99DqruBjahw==}
75 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
76 |
77 | '@php-wasm/util@1.0.14':
78 | resolution: {integrity: sha512-PKUvOd0M+C3LXZ7SNuL4AZ4TUBDqcqEBemG4FRjT721deYMMiixaMo6sorQ4nf7ppWyhyYBCyqmb94sp1VW6xw==}
79 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
80 |
81 | '@sindresorhus/is@4.6.0':
82 | resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
83 | engines: {node: '>=10'}
84 |
85 | '@szmarczak/http-timer@4.0.6':
86 | resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
87 | engines: {node: '>=10'}
88 |
89 | '@types/cacheable-request@6.0.3':
90 | resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
91 |
92 | '@types/http-cache-semantics@4.0.4':
93 | resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
94 |
95 | '@types/keyv@3.1.4':
96 | resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
97 |
98 | '@types/node@20.17.9':
99 | resolution: {integrity: sha512-0JOXkRyLanfGPE2QRCwgxhzlBAvaRdCNMcvbd7jFfpmD4eEXll7LRwy5ymJmyeZqk7Nh7eD2LeUyQ68BbndmXw==}
100 |
101 | '@types/responselike@1.0.3':
102 | resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
103 |
104 | '@types/yauzl@2.10.3':
105 | resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
106 |
107 | '@wp-playground/common@1.0.14':
108 | resolution: {integrity: sha512-5LH2Rf/sMM7wt/ZYJqwqaxA9s/esiNDtExOTzdTcA5hhQ1yCWLVpQRjV8w0QI0puz9DwmYF1QeK16a5YE0YUrw==}
109 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
110 |
111 | '@wp-playground/wordpress@1.0.14':
112 | resolution: {integrity: sha512-4KW/GYCm6Ot16xW3tr2/24fZMdogTRKi3NJB1DfQqOWKIggD6leVTUlvWCyx1uxJtTrEu+LCaO11NmMBvuTWMQ==}
113 | engines: {node: '>=18.18.0', npm: '>=8.11.0'}
114 |
115 | accepts@1.3.8:
116 | resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
117 | engines: {node: '>= 0.6'}
118 |
119 | ansi-regex@5.0.1:
120 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
121 | engines: {node: '>=8'}
122 |
123 | ansi-styles@4.3.0:
124 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
125 | engines: {node: '>=8'}
126 |
127 | array-flatten@1.1.1:
128 | resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
129 |
130 | asynckit@0.4.0:
131 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
132 |
133 | axios@1.7.9:
134 | resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
135 |
136 | body-parser@1.20.2:
137 | resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
138 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
139 |
140 | body-parser@1.20.3:
141 | resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
142 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
143 |
144 | boolean@3.2.0:
145 | resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==}
146 | deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
147 |
148 | buffer-crc32@0.2.13:
149 | resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
150 |
151 | bytes@3.1.2:
152 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
153 | engines: {node: '>= 0.8'}
154 |
155 | cacheable-lookup@5.0.4:
156 | resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
157 | engines: {node: '>=10.6.0'}
158 |
159 | cacheable-request@7.0.4:
160 | resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
161 | engines: {node: '>=8'}
162 |
163 | call-bind-apply-helpers@1.0.0:
164 | resolution: {integrity: sha512-CCKAP2tkPau7D3GE8+V8R6sQubA9R5foIzGp+85EXCVSCivuxBNAWqcpn72PKYiIcqoViv/kcUDpaEIMBVi1lQ==}
165 | engines: {node: '>= 0.4'}
166 |
167 | call-bind@1.0.8:
168 | resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
169 | engines: {node: '>= 0.4'}
170 |
171 | cliui@8.0.1:
172 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
173 | engines: {node: '>=12'}
174 |
175 | clone-response@1.0.3:
176 | resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
177 |
178 | color-convert@2.0.1:
179 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
180 | engines: {node: '>=7.0.0'}
181 |
182 | color-name@1.1.4:
183 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
184 |
185 | combined-stream@1.0.8:
186 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
187 | engines: {node: '>= 0.8'}
188 |
189 | comlink@4.4.2:
190 | resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==}
191 |
192 | compressible@2.0.18:
193 | resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
194 | engines: {node: '>= 0.6'}
195 |
196 | compression@1.7.5:
197 | resolution: {integrity: sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==}
198 | engines: {node: '>= 0.8.0'}
199 |
200 | content-disposition@0.5.4:
201 | resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
202 | engines: {node: '>= 0.6'}
203 |
204 | content-type@1.0.5:
205 | resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
206 | engines: {node: '>= 0.6'}
207 |
208 | cookie-signature@1.0.6:
209 | resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
210 |
211 | cookie@0.6.0:
212 | resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
213 | engines: {node: '>= 0.6'}
214 |
215 | cookie@0.7.1:
216 | resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
217 | engines: {node: '>= 0.6'}
218 |
219 | data-uri-to-buffer@4.0.1:
220 | resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
221 | engines: {node: '>= 12'}
222 |
223 | debug@2.6.9:
224 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
225 | peerDependencies:
226 | supports-color: '*'
227 | peerDependenciesMeta:
228 | supports-color:
229 | optional: true
230 |
231 | debug@4.4.0:
232 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
233 | engines: {node: '>=6.0'}
234 | peerDependencies:
235 | supports-color: '*'
236 | peerDependenciesMeta:
237 | supports-color:
238 | optional: true
239 |
240 | decompress-response@6.0.0:
241 | resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
242 | engines: {node: '>=10'}
243 |
244 | defer-to-connect@2.0.1:
245 | resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
246 | engines: {node: '>=10'}
247 |
248 | define-data-property@1.1.4:
249 | resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
250 | engines: {node: '>= 0.4'}
251 |
252 | define-properties@1.2.1:
253 | resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
254 | engines: {node: '>= 0.4'}
255 |
256 | delayed-stream@1.0.0:
257 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
258 | engines: {node: '>=0.4.0'}
259 |
260 | depd@2.0.0:
261 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
262 | engines: {node: '>= 0.8'}
263 |
264 | destroy@1.2.0:
265 | resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
266 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
267 |
268 | detect-node@2.1.0:
269 | resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
270 |
271 | dunder-proto@1.0.0:
272 | resolution: {integrity: sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==}
273 | engines: {node: '>= 0.4'}
274 |
275 | ee-first@1.1.1:
276 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
277 |
278 | electron@30.5.1:
279 | resolution: {integrity: sha512-AhL7+mZ8Lg14iaNfoYTkXQ2qee8mmsQyllKdqxlpv/zrKgfxz6jNVtcRRbQtLxtF8yzcImWdfTQROpYiPumdbw==}
280 | engines: {node: '>= 12.20.55'}
281 | hasBin: true
282 |
283 | emoji-regex@8.0.0:
284 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
285 |
286 | encodeurl@1.0.2:
287 | resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
288 | engines: {node: '>= 0.8'}
289 |
290 | encodeurl@2.0.0:
291 | resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
292 | engines: {node: '>= 0.8'}
293 |
294 | end-of-stream@1.4.4:
295 | resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
296 |
297 | env-paths@2.2.1:
298 | resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
299 | engines: {node: '>=6'}
300 |
301 | es-define-property@1.0.1:
302 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
303 | engines: {node: '>= 0.4'}
304 |
305 | es-errors@1.3.0:
306 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
307 | engines: {node: '>= 0.4'}
308 |
309 | es6-error@4.1.1:
310 | resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
311 |
312 | escalade@3.2.0:
313 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
314 | engines: {node: '>=6'}
315 |
316 | escape-html@1.0.3:
317 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
318 |
319 | escape-string-regexp@4.0.0:
320 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
321 | engines: {node: '>=10'}
322 |
323 | etag@1.8.1:
324 | resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
325 | engines: {node: '>= 0.6'}
326 |
327 | events@3.3.0:
328 | resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
329 | engines: {node: '>=0.8.x'}
330 |
331 | express@4.19.2:
332 | resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
333 | engines: {node: '>= 0.10.0'}
334 |
335 | express@4.21.2:
336 | resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
337 | engines: {node: '>= 0.10.0'}
338 |
339 | extract-zip@2.0.1:
340 | resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
341 | engines: {node: '>= 10.17.0'}
342 | hasBin: true
343 |
344 | fd-slicer@1.1.0:
345 | resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
346 |
347 | fetch-blob@3.2.0:
348 | resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
349 | engines: {node: ^12.20 || >= 14.13}
350 |
351 | file-url@4.0.0:
352 | resolution: {integrity: sha512-vRCdScQ6j3Ku6Kd7W1kZk9c++5SqD6Xz5Jotrjr/nkY714M14RFHy/AAVA2WQvpsqVAVgTbDrYyBpU205F0cLw==}
353 | engines: {node: '>=12'}
354 |
355 | finalhandler@1.2.0:
356 | resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
357 | engines: {node: '>= 0.8'}
358 |
359 | finalhandler@1.3.1:
360 | resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
361 | engines: {node: '>= 0.8'}
362 |
363 | follow-redirects@1.15.9:
364 | resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
365 | engines: {node: '>=4.0'}
366 | peerDependencies:
367 | debug: '*'
368 | peerDependenciesMeta:
369 | debug:
370 | optional: true
371 |
372 | form-data@4.0.1:
373 | resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
374 | engines: {node: '>= 6'}
375 |
376 | formdata-polyfill@4.0.10:
377 | resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
378 | engines: {node: '>=12.20.0'}
379 |
380 | forwarded@0.2.0:
381 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
382 | engines: {node: '>= 0.6'}
383 |
384 | fresh@0.5.2:
385 | resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
386 | engines: {node: '>= 0.6'}
387 |
388 | fs-extra@8.1.0:
389 | resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
390 | engines: {node: '>=6 <7 || >=8'}
391 |
392 | function-bind@1.1.2:
393 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
394 |
395 | get-caller-file@2.0.5:
396 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
397 | engines: {node: 6.* || 8.* || >= 10.*}
398 |
399 | get-intrinsic@1.2.5:
400 | resolution: {integrity: sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==}
401 | engines: {node: '>= 0.4'}
402 |
403 | get-stream@5.2.0:
404 | resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
405 | engines: {node: '>=8'}
406 |
407 | global-agent@3.0.0:
408 | resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
409 | engines: {node: '>=10.0'}
410 |
411 | globalthis@1.0.4:
412 | resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
413 | engines: {node: '>= 0.4'}
414 |
415 | gopd@1.2.0:
416 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
417 | engines: {node: '>= 0.4'}
418 |
419 | got@11.8.6:
420 | resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
421 | engines: {node: '>=10.19.0'}
422 |
423 | graceful-fs@4.2.11:
424 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
425 |
426 | has-property-descriptors@1.0.2:
427 | resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
428 |
429 | has-symbols@1.1.0:
430 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
431 | engines: {node: '>= 0.4'}
432 |
433 | hasown@2.0.2:
434 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
435 | engines: {node: '>= 0.4'}
436 |
437 | http-cache-semantics@4.1.1:
438 | resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
439 |
440 | http-errors@2.0.0:
441 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
442 | engines: {node: '>= 0.8'}
443 |
444 | http2-wrapper@1.0.3:
445 | resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
446 | engines: {node: '>=10.19.0'}
447 |
448 | iconv-lite@0.4.24:
449 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
450 | engines: {node: '>=0.10.0'}
451 |
452 | inherits@2.0.4:
453 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
454 |
455 | ini@4.1.2:
456 | resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==}
457 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
458 |
459 | ipaddr.js@1.9.1:
460 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
461 | engines: {node: '>= 0.10'}
462 |
463 | is-fullwidth-code-point@3.0.0:
464 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
465 | engines: {node: '>=8'}
466 |
467 | json-buffer@3.0.1:
468 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
469 |
470 | json-stringify-safe@5.0.1:
471 | resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
472 |
473 | jsonfile@4.0.0:
474 | resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
475 |
476 | keyv@4.5.4:
477 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
478 |
479 | lowercase-keys@2.0.0:
480 | resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
481 | engines: {node: '>=8'}
482 |
483 | matcher@3.0.0:
484 | resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==}
485 | engines: {node: '>=10'}
486 |
487 | media-typer@0.3.0:
488 | resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
489 | engines: {node: '>= 0.6'}
490 |
491 | merge-descriptors@1.0.1:
492 | resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
493 |
494 | merge-descriptors@1.0.3:
495 | resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
496 |
497 | methods@1.1.2:
498 | resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
499 | engines: {node: '>= 0.6'}
500 |
501 | mime-db@1.52.0:
502 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
503 | engines: {node: '>= 0.6'}
504 |
505 | mime-db@1.53.0:
506 | resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==}
507 | engines: {node: '>= 0.6'}
508 |
509 | mime-types@2.1.35:
510 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
511 | engines: {node: '>= 0.6'}
512 |
513 | mime@1.6.0:
514 | resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
515 | engines: {node: '>=4'}
516 | hasBin: true
517 |
518 | mimic-response@1.0.1:
519 | resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
520 | engines: {node: '>=4'}
521 |
522 | mimic-response@3.1.0:
523 | resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
524 | engines: {node: '>=10'}
525 |
526 | ms@2.0.0:
527 | resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
528 |
529 | ms@2.1.3:
530 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
531 |
532 | negotiator@0.6.3:
533 | resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
534 | engines: {node: '>= 0.6'}
535 |
536 | negotiator@0.6.4:
537 | resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==}
538 | engines: {node: '>= 0.6'}
539 |
540 | node-domexception@1.0.0:
541 | resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
542 | engines: {node: '>=10.5.0'}
543 |
544 | node-fetch@3.3.2:
545 | resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
546 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
547 |
548 | normalize-url@6.1.0:
549 | resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
550 | engines: {node: '>=10'}
551 |
552 | object-inspect@1.13.3:
553 | resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==}
554 | engines: {node: '>= 0.4'}
555 |
556 | object-keys@1.1.1:
557 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
558 | engines: {node: '>= 0.4'}
559 |
560 | on-finished@2.4.1:
561 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
562 | engines: {node: '>= 0.8'}
563 |
564 | on-headers@1.0.2:
565 | resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
566 | engines: {node: '>= 0.8'}
567 |
568 | once@1.4.0:
569 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
570 |
571 | p-cancelable@2.1.1:
572 | resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
573 | engines: {node: '>=8'}
574 |
575 | parseurl@1.3.3:
576 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
577 | engines: {node: '>= 0.8'}
578 |
579 | path-to-regexp@0.1.12:
580 | resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
581 |
582 | path-to-regexp@0.1.7:
583 | resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
584 |
585 | pend@1.2.0:
586 | resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
587 |
588 | progress@2.0.3:
589 | resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
590 | engines: {node: '>=0.4.0'}
591 |
592 | proxy-addr@2.0.7:
593 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
594 | engines: {node: '>= 0.10'}
595 |
596 | proxy-from-env@1.1.0:
597 | resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
598 |
599 | pump@3.0.2:
600 | resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
601 |
602 | qs@6.11.0:
603 | resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
604 | engines: {node: '>=0.6'}
605 |
606 | qs@6.13.0:
607 | resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
608 | engines: {node: '>=0.6'}
609 |
610 | quick-lru@5.1.1:
611 | resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
612 | engines: {node: '>=10'}
613 |
614 | range-parser@1.2.1:
615 | resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
616 | engines: {node: '>= 0.6'}
617 |
618 | raw-body@2.5.2:
619 | resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
620 | engines: {node: '>= 0.8'}
621 |
622 | require-directory@2.1.1:
623 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
624 | engines: {node: '>=0.10.0'}
625 |
626 | resolve-alpn@1.2.1:
627 | resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
628 |
629 | responselike@2.0.1:
630 | resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
631 |
632 | roarr@2.15.4:
633 | resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==}
634 | engines: {node: '>=8.0'}
635 |
636 | safe-buffer@5.2.1:
637 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
638 |
639 | safer-buffer@2.1.2:
640 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
641 |
642 | semver-compare@1.0.0:
643 | resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==}
644 |
645 | semver@6.3.1:
646 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
647 | hasBin: true
648 |
649 | semver@7.6.3:
650 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
651 | engines: {node: '>=10'}
652 | hasBin: true
653 |
654 | send@0.18.0:
655 | resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
656 | engines: {node: '>= 0.8.0'}
657 |
658 | send@0.19.0:
659 | resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
660 | engines: {node: '>= 0.8.0'}
661 |
662 | serialize-error@7.0.1:
663 | resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
664 | engines: {node: '>=10'}
665 |
666 | serve-static@1.15.0:
667 | resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
668 | engines: {node: '>= 0.8.0'}
669 |
670 | serve-static@1.16.2:
671 | resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
672 | engines: {node: '>= 0.8.0'}
673 |
674 | set-function-length@1.2.2:
675 | resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
676 | engines: {node: '>= 0.4'}
677 |
678 | setprototypeof@1.2.0:
679 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
680 |
681 | side-channel@1.0.6:
682 | resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
683 | engines: {node: '>= 0.4'}
684 |
685 | sprintf-js@1.1.3:
686 | resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
687 |
688 | statuses@2.0.1:
689 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
690 | engines: {node: '>= 0.8'}
691 |
692 | string-width@4.2.3:
693 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
694 | engines: {node: '>=8'}
695 |
696 | strip-ansi@6.0.1:
697 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
698 | engines: {node: '>=8'}
699 |
700 | sumchecker@3.0.1:
701 | resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
702 | engines: {node: '>= 8.0'}
703 |
704 | toidentifier@1.0.1:
705 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
706 | engines: {node: '>=0.6'}
707 |
708 | type-fest@0.13.1:
709 | resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
710 | engines: {node: '>=10'}
711 |
712 | type-is@1.6.18:
713 | resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
714 | engines: {node: '>= 0.6'}
715 |
716 | undici-types@6.19.8:
717 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
718 |
719 | universalify@0.1.2:
720 | resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
721 | engines: {node: '>= 4.0.0'}
722 |
723 | unpipe@1.0.0:
724 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
725 | engines: {node: '>= 0.8'}
726 |
727 | utils-merge@1.0.1:
728 | resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
729 | engines: {node: '>= 0.4.0'}
730 |
731 | vary@1.1.2:
732 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
733 | engines: {node: '>= 0.8'}
734 |
735 | wasm-feature-detect@1.8.0:
736 | resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==}
737 |
738 | web-streams-polyfill@3.3.3:
739 | resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
740 | engines: {node: '>= 8'}
741 |
742 | wrap-ansi@7.0.0:
743 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
744 | engines: {node: '>=10'}
745 |
746 | wrappy@1.0.2:
747 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
748 |
749 | ws@8.18.0:
750 | resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
751 | engines: {node: '>=10.0.0'}
752 | peerDependencies:
753 | bufferutil: ^4.0.1
754 | utf-8-validate: '>=5.0.2'
755 | peerDependenciesMeta:
756 | bufferutil:
757 | optional: true
758 | utf-8-validate:
759 | optional: true
760 |
761 | y18n@5.0.8:
762 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
763 | engines: {node: '>=10'}
764 |
765 | yargs-parser@21.1.1:
766 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
767 | engines: {node: '>=12'}
768 |
769 | yargs@17.7.2:
770 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
771 | engines: {node: '>=12'}
772 |
773 | yauzl@2.10.0:
774 | resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
775 |
776 | snapshots:
777 |
778 | '@electron/get@2.0.3':
779 | dependencies:
780 | debug: 4.4.0
781 | env-paths: 2.2.1
782 | fs-extra: 8.1.0
783 | got: 11.8.6
784 | progress: 2.0.3
785 | semver: 6.3.1
786 | sumchecker: 3.0.1
787 | optionalDependencies:
788 | global-agent: 3.0.0
789 | transitivePeerDependencies:
790 | - supports-color
791 |
792 | '@php-wasm/logger@1.0.14':
793 | dependencies:
794 | '@php-wasm/node-polyfills': 1.0.14
795 |
796 | '@php-wasm/node-polyfills@1.0.14': {}
797 |
798 | '@php-wasm/node@1.0.14':
799 | dependencies:
800 | '@php-wasm/logger': 1.0.14
801 | '@php-wasm/node-polyfills': 1.0.14
802 | '@php-wasm/universal': 1.0.14
803 | '@php-wasm/util': 1.0.14
804 | '@wp-playground/common': 1.0.14
805 | '@wp-playground/wordpress': 1.0.14
806 | comlink: 4.4.2
807 | events: 3.3.0
808 | express: 4.19.2
809 | ini: 4.1.2
810 | wasm-feature-detect: 1.8.0
811 | ws: 8.18.0
812 | yargs: 17.7.2
813 | transitivePeerDependencies:
814 | - bufferutil
815 | - supports-color
816 | - utf-8-validate
817 |
818 | '@php-wasm/progress@1.0.14':
819 | dependencies:
820 | '@php-wasm/logger': 1.0.14
821 | '@php-wasm/node-polyfills': 1.0.14
822 |
823 | '@php-wasm/scopes@1.0.14': {}
824 |
825 | '@php-wasm/stream-compression@1.0.14':
826 | dependencies:
827 | '@php-wasm/node-polyfills': 1.0.14
828 | '@php-wasm/util': 1.0.14
829 |
830 | '@php-wasm/universal@1.0.14':
831 | dependencies:
832 | '@php-wasm/logger': 1.0.14
833 | '@php-wasm/node-polyfills': 1.0.14
834 | '@php-wasm/progress': 1.0.14
835 | '@php-wasm/stream-compression': 1.0.14
836 | '@php-wasm/util': 1.0.14
837 | comlink: 4.4.2
838 | ini: 4.1.2
839 |
840 | '@php-wasm/util@1.0.14': {}
841 |
842 | '@sindresorhus/is@4.6.0': {}
843 |
844 | '@szmarczak/http-timer@4.0.6':
845 | dependencies:
846 | defer-to-connect: 2.0.1
847 |
848 | '@types/cacheable-request@6.0.3':
849 | dependencies:
850 | '@types/http-cache-semantics': 4.0.4
851 | '@types/keyv': 3.1.4
852 | '@types/node': 20.17.9
853 | '@types/responselike': 1.0.3
854 |
855 | '@types/http-cache-semantics@4.0.4': {}
856 |
857 | '@types/keyv@3.1.4':
858 | dependencies:
859 | '@types/node': 20.17.9
860 |
861 | '@types/node@20.17.9':
862 | dependencies:
863 | undici-types: 6.19.8
864 |
865 | '@types/responselike@1.0.3':
866 | dependencies:
867 | '@types/node': 20.17.9
868 |
869 | '@types/yauzl@2.10.3':
870 | dependencies:
871 | '@types/node': 20.17.9
872 | optional: true
873 |
874 | '@wp-playground/common@1.0.14':
875 | dependencies:
876 | '@php-wasm/universal': 1.0.14
877 | '@php-wasm/util': 1.0.14
878 | comlink: 4.4.2
879 | ini: 4.1.2
880 |
881 | '@wp-playground/wordpress@1.0.14':
882 | dependencies:
883 | '@php-wasm/logger': 1.0.14
884 | '@php-wasm/node': 1.0.14
885 | '@php-wasm/universal': 1.0.14
886 | '@php-wasm/util': 1.0.14
887 | '@wp-playground/common': 1.0.14
888 | comlink: 4.4.2
889 | events: 3.3.0
890 | express: 4.19.2
891 | ini: 4.1.2
892 | wasm-feature-detect: 1.8.0
893 | ws: 8.18.0
894 | yargs: 17.7.2
895 | transitivePeerDependencies:
896 | - bufferutil
897 | - supports-color
898 | - utf-8-validate
899 |
900 | accepts@1.3.8:
901 | dependencies:
902 | mime-types: 2.1.35
903 | negotiator: 0.6.3
904 |
905 | ansi-regex@5.0.1: {}
906 |
907 | ansi-styles@4.3.0:
908 | dependencies:
909 | color-convert: 2.0.1
910 |
911 | array-flatten@1.1.1: {}
912 |
913 | asynckit@0.4.0: {}
914 |
915 | axios@1.7.9:
916 | dependencies:
917 | follow-redirects: 1.15.9
918 | form-data: 4.0.1
919 | proxy-from-env: 1.1.0
920 | transitivePeerDependencies:
921 | - debug
922 |
923 | body-parser@1.20.2:
924 | dependencies:
925 | bytes: 3.1.2
926 | content-type: 1.0.5
927 | debug: 2.6.9
928 | depd: 2.0.0
929 | destroy: 1.2.0
930 | http-errors: 2.0.0
931 | iconv-lite: 0.4.24
932 | on-finished: 2.4.1
933 | qs: 6.11.0
934 | raw-body: 2.5.2
935 | type-is: 1.6.18
936 | unpipe: 1.0.0
937 | transitivePeerDependencies:
938 | - supports-color
939 |
940 | body-parser@1.20.3:
941 | dependencies:
942 | bytes: 3.1.2
943 | content-type: 1.0.5
944 | debug: 2.6.9
945 | depd: 2.0.0
946 | destroy: 1.2.0
947 | http-errors: 2.0.0
948 | iconv-lite: 0.4.24
949 | on-finished: 2.4.1
950 | qs: 6.13.0
951 | raw-body: 2.5.2
952 | type-is: 1.6.18
953 | unpipe: 1.0.0
954 | transitivePeerDependencies:
955 | - supports-color
956 |
957 | boolean@3.2.0:
958 | optional: true
959 |
960 | buffer-crc32@0.2.13: {}
961 |
962 | bytes@3.1.2: {}
963 |
964 | cacheable-lookup@5.0.4: {}
965 |
966 | cacheable-request@7.0.4:
967 | dependencies:
968 | clone-response: 1.0.3
969 | get-stream: 5.2.0
970 | http-cache-semantics: 4.1.1
971 | keyv: 4.5.4
972 | lowercase-keys: 2.0.0
973 | normalize-url: 6.1.0
974 | responselike: 2.0.1
975 |
976 | call-bind-apply-helpers@1.0.0:
977 | dependencies:
978 | es-errors: 1.3.0
979 | function-bind: 1.1.2
980 |
981 | call-bind@1.0.8:
982 | dependencies:
983 | call-bind-apply-helpers: 1.0.0
984 | es-define-property: 1.0.1
985 | get-intrinsic: 1.2.5
986 | set-function-length: 1.2.2
987 |
988 | cliui@8.0.1:
989 | dependencies:
990 | string-width: 4.2.3
991 | strip-ansi: 6.0.1
992 | wrap-ansi: 7.0.0
993 |
994 | clone-response@1.0.3:
995 | dependencies:
996 | mimic-response: 1.0.1
997 |
998 | color-convert@2.0.1:
999 | dependencies:
1000 | color-name: 1.1.4
1001 |
1002 | color-name@1.1.4: {}
1003 |
1004 | combined-stream@1.0.8:
1005 | dependencies:
1006 | delayed-stream: 1.0.0
1007 |
1008 | comlink@4.4.2: {}
1009 |
1010 | compressible@2.0.18:
1011 | dependencies:
1012 | mime-db: 1.53.0
1013 |
1014 | compression@1.7.5:
1015 | dependencies:
1016 | bytes: 3.1.2
1017 | compressible: 2.0.18
1018 | debug: 2.6.9
1019 | negotiator: 0.6.4
1020 | on-headers: 1.0.2
1021 | safe-buffer: 5.2.1
1022 | vary: 1.1.2
1023 | transitivePeerDependencies:
1024 | - supports-color
1025 |
1026 | content-disposition@0.5.4:
1027 | dependencies:
1028 | safe-buffer: 5.2.1
1029 |
1030 | content-type@1.0.5: {}
1031 |
1032 | cookie-signature@1.0.6: {}
1033 |
1034 | cookie@0.6.0: {}
1035 |
1036 | cookie@0.7.1: {}
1037 |
1038 | data-uri-to-buffer@4.0.1: {}
1039 |
1040 | debug@2.6.9:
1041 | dependencies:
1042 | ms: 2.0.0
1043 |
1044 | debug@4.4.0:
1045 | dependencies:
1046 | ms: 2.1.3
1047 |
1048 | decompress-response@6.0.0:
1049 | dependencies:
1050 | mimic-response: 3.1.0
1051 |
1052 | defer-to-connect@2.0.1: {}
1053 |
1054 | define-data-property@1.1.4:
1055 | dependencies:
1056 | es-define-property: 1.0.1
1057 | es-errors: 1.3.0
1058 | gopd: 1.2.0
1059 |
1060 | define-properties@1.2.1:
1061 | dependencies:
1062 | define-data-property: 1.1.4
1063 | has-property-descriptors: 1.0.2
1064 | object-keys: 1.1.1
1065 | optional: true
1066 |
1067 | delayed-stream@1.0.0: {}
1068 |
1069 | depd@2.0.0: {}
1070 |
1071 | destroy@1.2.0: {}
1072 |
1073 | detect-node@2.1.0:
1074 | optional: true
1075 |
1076 | dunder-proto@1.0.0:
1077 | dependencies:
1078 | call-bind-apply-helpers: 1.0.0
1079 | es-errors: 1.3.0
1080 | gopd: 1.2.0
1081 |
1082 | ee-first@1.1.1: {}
1083 |
1084 | electron@30.5.1:
1085 | dependencies:
1086 | '@electron/get': 2.0.3
1087 | '@types/node': 20.17.9
1088 | extract-zip: 2.0.1
1089 | transitivePeerDependencies:
1090 | - supports-color
1091 |
1092 | emoji-regex@8.0.0: {}
1093 |
1094 | encodeurl@1.0.2: {}
1095 |
1096 | encodeurl@2.0.0: {}
1097 |
1098 | end-of-stream@1.4.4:
1099 | dependencies:
1100 | once: 1.4.0
1101 |
1102 | env-paths@2.2.1: {}
1103 |
1104 | es-define-property@1.0.1: {}
1105 |
1106 | es-errors@1.3.0: {}
1107 |
1108 | es6-error@4.1.1:
1109 | optional: true
1110 |
1111 | escalade@3.2.0: {}
1112 |
1113 | escape-html@1.0.3: {}
1114 |
1115 | escape-string-regexp@4.0.0:
1116 | optional: true
1117 |
1118 | etag@1.8.1: {}
1119 |
1120 | events@3.3.0: {}
1121 |
1122 | express@4.19.2:
1123 | dependencies:
1124 | accepts: 1.3.8
1125 | array-flatten: 1.1.1
1126 | body-parser: 1.20.2
1127 | content-disposition: 0.5.4
1128 | content-type: 1.0.5
1129 | cookie: 0.6.0
1130 | cookie-signature: 1.0.6
1131 | debug: 2.6.9
1132 | depd: 2.0.0
1133 | encodeurl: 1.0.2
1134 | escape-html: 1.0.3
1135 | etag: 1.8.1
1136 | finalhandler: 1.2.0
1137 | fresh: 0.5.2
1138 | http-errors: 2.0.0
1139 | merge-descriptors: 1.0.1
1140 | methods: 1.1.2
1141 | on-finished: 2.4.1
1142 | parseurl: 1.3.3
1143 | path-to-regexp: 0.1.7
1144 | proxy-addr: 2.0.7
1145 | qs: 6.11.0
1146 | range-parser: 1.2.1
1147 | safe-buffer: 5.2.1
1148 | send: 0.18.0
1149 | serve-static: 1.15.0
1150 | setprototypeof: 1.2.0
1151 | statuses: 2.0.1
1152 | type-is: 1.6.18
1153 | utils-merge: 1.0.1
1154 | vary: 1.1.2
1155 | transitivePeerDependencies:
1156 | - supports-color
1157 |
1158 | express@4.21.2:
1159 | dependencies:
1160 | accepts: 1.3.8
1161 | array-flatten: 1.1.1
1162 | body-parser: 1.20.3
1163 | content-disposition: 0.5.4
1164 | content-type: 1.0.5
1165 | cookie: 0.7.1
1166 | cookie-signature: 1.0.6
1167 | debug: 2.6.9
1168 | depd: 2.0.0
1169 | encodeurl: 2.0.0
1170 | escape-html: 1.0.3
1171 | etag: 1.8.1
1172 | finalhandler: 1.3.1
1173 | fresh: 0.5.2
1174 | http-errors: 2.0.0
1175 | merge-descriptors: 1.0.3
1176 | methods: 1.1.2
1177 | on-finished: 2.4.1
1178 | parseurl: 1.3.3
1179 | path-to-regexp: 0.1.12
1180 | proxy-addr: 2.0.7
1181 | qs: 6.13.0
1182 | range-parser: 1.2.1
1183 | safe-buffer: 5.2.1
1184 | send: 0.19.0
1185 | serve-static: 1.16.2
1186 | setprototypeof: 1.2.0
1187 | statuses: 2.0.1
1188 | type-is: 1.6.18
1189 | utils-merge: 1.0.1
1190 | vary: 1.1.2
1191 | transitivePeerDependencies:
1192 | - supports-color
1193 |
1194 | extract-zip@2.0.1:
1195 | dependencies:
1196 | debug: 4.4.0
1197 | get-stream: 5.2.0
1198 | yauzl: 2.10.0
1199 | optionalDependencies:
1200 | '@types/yauzl': 2.10.3
1201 | transitivePeerDependencies:
1202 | - supports-color
1203 |
1204 | fd-slicer@1.1.0:
1205 | dependencies:
1206 | pend: 1.2.0
1207 |
1208 | fetch-blob@3.2.0:
1209 | dependencies:
1210 | node-domexception: 1.0.0
1211 | web-streams-polyfill: 3.3.3
1212 |
1213 | file-url@4.0.0: {}
1214 |
1215 | finalhandler@1.2.0:
1216 | dependencies:
1217 | debug: 2.6.9
1218 | encodeurl: 1.0.2
1219 | escape-html: 1.0.3
1220 | on-finished: 2.4.1
1221 | parseurl: 1.3.3
1222 | statuses: 2.0.1
1223 | unpipe: 1.0.0
1224 | transitivePeerDependencies:
1225 | - supports-color
1226 |
1227 | finalhandler@1.3.1:
1228 | dependencies:
1229 | debug: 2.6.9
1230 | encodeurl: 2.0.0
1231 | escape-html: 1.0.3
1232 | on-finished: 2.4.1
1233 | parseurl: 1.3.3
1234 | statuses: 2.0.1
1235 | unpipe: 1.0.0
1236 | transitivePeerDependencies:
1237 | - supports-color
1238 |
1239 | follow-redirects@1.15.9: {}
1240 |
1241 | form-data@4.0.1:
1242 | dependencies:
1243 | asynckit: 0.4.0
1244 | combined-stream: 1.0.8
1245 | mime-types: 2.1.35
1246 |
1247 | formdata-polyfill@4.0.10:
1248 | dependencies:
1249 | fetch-blob: 3.2.0
1250 |
1251 | forwarded@0.2.0: {}
1252 |
1253 | fresh@0.5.2: {}
1254 |
1255 | fs-extra@8.1.0:
1256 | dependencies:
1257 | graceful-fs: 4.2.11
1258 | jsonfile: 4.0.0
1259 | universalify: 0.1.2
1260 |
1261 | function-bind@1.1.2: {}
1262 |
1263 | get-caller-file@2.0.5: {}
1264 |
1265 | get-intrinsic@1.2.5:
1266 | dependencies:
1267 | call-bind-apply-helpers: 1.0.0
1268 | dunder-proto: 1.0.0
1269 | es-define-property: 1.0.1
1270 | es-errors: 1.3.0
1271 | function-bind: 1.1.2
1272 | gopd: 1.2.0
1273 | has-symbols: 1.1.0
1274 | hasown: 2.0.2
1275 |
1276 | get-stream@5.2.0:
1277 | dependencies:
1278 | pump: 3.0.2
1279 |
1280 | global-agent@3.0.0:
1281 | dependencies:
1282 | boolean: 3.2.0
1283 | es6-error: 4.1.1
1284 | matcher: 3.0.0
1285 | roarr: 2.15.4
1286 | semver: 7.6.3
1287 | serialize-error: 7.0.1
1288 | optional: true
1289 |
1290 | globalthis@1.0.4:
1291 | dependencies:
1292 | define-properties: 1.2.1
1293 | gopd: 1.2.0
1294 | optional: true
1295 |
1296 | gopd@1.2.0: {}
1297 |
1298 | got@11.8.6:
1299 | dependencies:
1300 | '@sindresorhus/is': 4.6.0
1301 | '@szmarczak/http-timer': 4.0.6
1302 | '@types/cacheable-request': 6.0.3
1303 | '@types/responselike': 1.0.3
1304 | cacheable-lookup: 5.0.4
1305 | cacheable-request: 7.0.4
1306 | decompress-response: 6.0.0
1307 | http2-wrapper: 1.0.3
1308 | lowercase-keys: 2.0.0
1309 | p-cancelable: 2.1.1
1310 | responselike: 2.0.1
1311 |
1312 | graceful-fs@4.2.11: {}
1313 |
1314 | has-property-descriptors@1.0.2:
1315 | dependencies:
1316 | es-define-property: 1.0.1
1317 |
1318 | has-symbols@1.1.0: {}
1319 |
1320 | hasown@2.0.2:
1321 | dependencies:
1322 | function-bind: 1.1.2
1323 |
1324 | http-cache-semantics@4.1.1: {}
1325 |
1326 | http-errors@2.0.0:
1327 | dependencies:
1328 | depd: 2.0.0
1329 | inherits: 2.0.4
1330 | setprototypeof: 1.2.0
1331 | statuses: 2.0.1
1332 | toidentifier: 1.0.1
1333 |
1334 | http2-wrapper@1.0.3:
1335 | dependencies:
1336 | quick-lru: 5.1.1
1337 | resolve-alpn: 1.2.1
1338 |
1339 | iconv-lite@0.4.24:
1340 | dependencies:
1341 | safer-buffer: 2.1.2
1342 |
1343 | inherits@2.0.4: {}
1344 |
1345 | ini@4.1.2: {}
1346 |
1347 | ipaddr.js@1.9.1: {}
1348 |
1349 | is-fullwidth-code-point@3.0.0: {}
1350 |
1351 | json-buffer@3.0.1: {}
1352 |
1353 | json-stringify-safe@5.0.1:
1354 | optional: true
1355 |
1356 | jsonfile@4.0.0:
1357 | optionalDependencies:
1358 | graceful-fs: 4.2.11
1359 |
1360 | keyv@4.5.4:
1361 | dependencies:
1362 | json-buffer: 3.0.1
1363 |
1364 | lowercase-keys@2.0.0: {}
1365 |
1366 | matcher@3.0.0:
1367 | dependencies:
1368 | escape-string-regexp: 4.0.0
1369 | optional: true
1370 |
1371 | media-typer@0.3.0: {}
1372 |
1373 | merge-descriptors@1.0.1: {}
1374 |
1375 | merge-descriptors@1.0.3: {}
1376 |
1377 | methods@1.1.2: {}
1378 |
1379 | mime-db@1.52.0: {}
1380 |
1381 | mime-db@1.53.0: {}
1382 |
1383 | mime-types@2.1.35:
1384 | dependencies:
1385 | mime-db: 1.52.0
1386 |
1387 | mime@1.6.0: {}
1388 |
1389 | mimic-response@1.0.1: {}
1390 |
1391 | mimic-response@3.1.0: {}
1392 |
1393 | ms@2.0.0: {}
1394 |
1395 | ms@2.1.3: {}
1396 |
1397 | negotiator@0.6.3: {}
1398 |
1399 | negotiator@0.6.4: {}
1400 |
1401 | node-domexception@1.0.0: {}
1402 |
1403 | node-fetch@3.3.2:
1404 | dependencies:
1405 | data-uri-to-buffer: 4.0.1
1406 | fetch-blob: 3.2.0
1407 | formdata-polyfill: 4.0.10
1408 |
1409 | normalize-url@6.1.0: {}
1410 |
1411 | object-inspect@1.13.3: {}
1412 |
1413 | object-keys@1.1.1:
1414 | optional: true
1415 |
1416 | on-finished@2.4.1:
1417 | dependencies:
1418 | ee-first: 1.1.1
1419 |
1420 | on-headers@1.0.2: {}
1421 |
1422 | once@1.4.0:
1423 | dependencies:
1424 | wrappy: 1.0.2
1425 |
1426 | p-cancelable@2.1.1: {}
1427 |
1428 | parseurl@1.3.3: {}
1429 |
1430 | path-to-regexp@0.1.12: {}
1431 |
1432 | path-to-regexp@0.1.7: {}
1433 |
1434 | pend@1.2.0: {}
1435 |
1436 | progress@2.0.3: {}
1437 |
1438 | proxy-addr@2.0.7:
1439 | dependencies:
1440 | forwarded: 0.2.0
1441 | ipaddr.js: 1.9.1
1442 |
1443 | proxy-from-env@1.1.0: {}
1444 |
1445 | pump@3.0.2:
1446 | dependencies:
1447 | end-of-stream: 1.4.4
1448 | once: 1.4.0
1449 |
1450 | qs@6.11.0:
1451 | dependencies:
1452 | side-channel: 1.0.6
1453 |
1454 | qs@6.13.0:
1455 | dependencies:
1456 | side-channel: 1.0.6
1457 |
1458 | quick-lru@5.1.1: {}
1459 |
1460 | range-parser@1.2.1: {}
1461 |
1462 | raw-body@2.5.2:
1463 | dependencies:
1464 | bytes: 3.1.2
1465 | http-errors: 2.0.0
1466 | iconv-lite: 0.4.24
1467 | unpipe: 1.0.0
1468 |
1469 | require-directory@2.1.1: {}
1470 |
1471 | resolve-alpn@1.2.1: {}
1472 |
1473 | responselike@2.0.1:
1474 | dependencies:
1475 | lowercase-keys: 2.0.0
1476 |
1477 | roarr@2.15.4:
1478 | dependencies:
1479 | boolean: 3.2.0
1480 | detect-node: 2.1.0
1481 | globalthis: 1.0.4
1482 | json-stringify-safe: 5.0.1
1483 | semver-compare: 1.0.0
1484 | sprintf-js: 1.1.3
1485 | optional: true
1486 |
1487 | safe-buffer@5.2.1: {}
1488 |
1489 | safer-buffer@2.1.2: {}
1490 |
1491 | semver-compare@1.0.0:
1492 | optional: true
1493 |
1494 | semver@6.3.1: {}
1495 |
1496 | semver@7.6.3:
1497 | optional: true
1498 |
1499 | send@0.18.0:
1500 | dependencies:
1501 | debug: 2.6.9
1502 | depd: 2.0.0
1503 | destroy: 1.2.0
1504 | encodeurl: 1.0.2
1505 | escape-html: 1.0.3
1506 | etag: 1.8.1
1507 | fresh: 0.5.2
1508 | http-errors: 2.0.0
1509 | mime: 1.6.0
1510 | ms: 2.1.3
1511 | on-finished: 2.4.1
1512 | range-parser: 1.2.1
1513 | statuses: 2.0.1
1514 | transitivePeerDependencies:
1515 | - supports-color
1516 |
1517 | send@0.19.0:
1518 | dependencies:
1519 | debug: 2.6.9
1520 | depd: 2.0.0
1521 | destroy: 1.2.0
1522 | encodeurl: 1.0.2
1523 | escape-html: 1.0.3
1524 | etag: 1.8.1
1525 | fresh: 0.5.2
1526 | http-errors: 2.0.0
1527 | mime: 1.6.0
1528 | ms: 2.1.3
1529 | on-finished: 2.4.1
1530 | range-parser: 1.2.1
1531 | statuses: 2.0.1
1532 | transitivePeerDependencies:
1533 | - supports-color
1534 |
1535 | serialize-error@7.0.1:
1536 | dependencies:
1537 | type-fest: 0.13.1
1538 | optional: true
1539 |
1540 | serve-static@1.15.0:
1541 | dependencies:
1542 | encodeurl: 1.0.2
1543 | escape-html: 1.0.3
1544 | parseurl: 1.3.3
1545 | send: 0.18.0
1546 | transitivePeerDependencies:
1547 | - supports-color
1548 |
1549 | serve-static@1.16.2:
1550 | dependencies:
1551 | encodeurl: 2.0.0
1552 | escape-html: 1.0.3
1553 | parseurl: 1.3.3
1554 | send: 0.19.0
1555 | transitivePeerDependencies:
1556 | - supports-color
1557 |
1558 | set-function-length@1.2.2:
1559 | dependencies:
1560 | define-data-property: 1.1.4
1561 | es-errors: 1.3.0
1562 | function-bind: 1.1.2
1563 | get-intrinsic: 1.2.5
1564 | gopd: 1.2.0
1565 | has-property-descriptors: 1.0.2
1566 |
1567 | setprototypeof@1.2.0: {}
1568 |
1569 | side-channel@1.0.6:
1570 | dependencies:
1571 | call-bind: 1.0.8
1572 | es-errors: 1.3.0
1573 | get-intrinsic: 1.2.5
1574 | object-inspect: 1.13.3
1575 |
1576 | sprintf-js@1.1.3:
1577 | optional: true
1578 |
1579 | statuses@2.0.1: {}
1580 |
1581 | string-width@4.2.3:
1582 | dependencies:
1583 | emoji-regex: 8.0.0
1584 | is-fullwidth-code-point: 3.0.0
1585 | strip-ansi: 6.0.1
1586 |
1587 | strip-ansi@6.0.1:
1588 | dependencies:
1589 | ansi-regex: 5.0.1
1590 |
1591 | sumchecker@3.0.1:
1592 | dependencies:
1593 | debug: 4.4.0
1594 | transitivePeerDependencies:
1595 | - supports-color
1596 |
1597 | toidentifier@1.0.1: {}
1598 |
1599 | type-fest@0.13.1:
1600 | optional: true
1601 |
1602 | type-is@1.6.18:
1603 | dependencies:
1604 | media-typer: 0.3.0
1605 | mime-types: 2.1.35
1606 |
1607 | undici-types@6.19.8: {}
1608 |
1609 | universalify@0.1.2: {}
1610 |
1611 | unpipe@1.0.0: {}
1612 |
1613 | utils-merge@1.0.1: {}
1614 |
1615 | vary@1.1.2: {}
1616 |
1617 | wasm-feature-detect@1.8.0: {}
1618 |
1619 | web-streams-polyfill@3.3.3: {}
1620 |
1621 | wrap-ansi@7.0.0:
1622 | dependencies:
1623 | ansi-styles: 4.3.0
1624 | string-width: 4.2.3
1625 | strip-ansi: 6.0.1
1626 |
1627 | wrappy@1.0.2: {}
1628 |
1629 | ws@8.18.0: {}
1630 |
1631 | y18n@5.0.8: {}
1632 |
1633 | yargs-parser@21.1.1: {}
1634 |
1635 | yargs@17.7.2:
1636 | dependencies:
1637 | cliui: 8.0.1
1638 | escalade: 3.2.0
1639 | get-caller-file: 2.0.5
1640 | require-directory: 2.1.1
1641 | string-width: 4.2.3
1642 | y18n: 5.0.8
1643 | yargs-parser: 21.1.1
1644 |
1645 | yauzl@2.10.0:
1646 | dependencies:
1647 | buffer-crc32: 0.2.13
1648 | fd-slicer: 1.1.0
1649 |
--------------------------------------------------------------------------------
/src/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PMAtron 登录
6 |
249 |
250 |
251 |
252 |
253 |
254 |
用PMAtron 登录你的Mysql 吧
255 |
287 |
288 |
289 |
290 |
291 |
292 |
添加新项
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
554 |
555 |
556 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import {app, BrowserWindow, protocol, ipcMain} from 'electron'
2 | import path from 'path'
3 | import fs from 'fs'
4 | import {
5 | createNodeFsMountHandler,
6 | getPHPLoaderModule,
7 | } from '@php-wasm/node';
8 |
9 | import {
10 | withNetworking
11 | } from './networking/with-networking.js'
12 | import {
13 | PHP,
14 | PHPRequestHandler,
15 | setPhpIniEntries,
16 | proxyFileSystem,
17 | loadPHPRuntime,
18 | } from '@php-wasm/universal';
19 | import {wordPressRewriteRules, getFileNotFoundActionForWordPress} from '@wp-playground/wordpress';
20 | import {rootCertificates} from 'tls';
21 | import compressible from 'compressible';
22 |
23 |
24 | function shouldCompress( _, res ) {
25 | const types = res.getHeader( 'content-type' );
26 | const type = Array.isArray( types ) ? types[ 0 ] : types;
27 | return type && compressible( type );
28 | }
29 |
30 | // Configuration for the PHP environment
31 | const environment = {
32 | php: {
33 | version: '8.3',
34 | },
35 | server: {
36 | scheme: 'phpapp',
37 | host: 'localhost',
38 | path: path.resolve('./phpMyAdmin'),
39 | mount: '/phpMyAdmin',
40 | debug: false,
41 | }
42 | };
43 |
44 | // Create preload script content
45 | const preloadScript = `
46 | const { contextBridge, ipcRenderer } = require('electron');
47 |
48 | contextBridge.exposeInMainWorld('api', {
49 | updateConfig: (credentials) => ipcRenderer.send('update-config', credentials),
50 | onUpdateSuccess: (callback) => ipcRenderer.on('update-config-success', callback),
51 | onUpdateFailure: (callback) => ipcRenderer.on('update-config-failure', callback)
52 | });
53 | `;
54 |
55 | export async function loadNodeRuntime(
56 | phpVersion,
57 | options = {}
58 | ) {
59 | const emscriptenOptions = {
60 | quit: function (code, error) {
61 | throw error;
62 | },
63 | ...(options.emscriptenOptions || {}),
64 | };
65 | return await loadPHPRuntime(
66 | await getPHPLoaderModule(phpVersion),
67 | await withNetworking(emscriptenOptions)
68 | );
69 | }
70 |
71 | // Initialize PHP instance with necessary configurations
72 | async function getPHPInstance(isPrimary, requestHandler) {
73 | const id = await loadNodeRuntime(environment.php.version);
74 | const php = new PHP(id);
75 | php.requestHandler = requestHandler;
76 |
77 | await setPhpIniEntries(php, {
78 | memory_limit: '2048M',
79 | disable_functions: 'openssl_random_pseudo_bytes',
80 | allow_url_fopen: '1',
81 | 'openssl.cafile': '/internal/shared/ca-bundle.crt',
82 | });
83 |
84 | return {php, runtimeId: id};
85 | }
86 |
87 | // Convert request body to bytes
88 | const requestBodyToBytes = async (request) => {
89 | return Buffer.from(await request.arrayBuffer());
90 | }
91 |
92 | // Initialize PHP handler
93 | async function initializePHPHandler() {
94 | const requestHandler = new PHPRequestHandler({
95 | phpFactory: async ({isPrimary, requestHandler: reqHandler}) => {
96 | const {php} = await getPHPInstance(isPrimary, reqHandler);
97 | if (!isPrimary) {
98 | proxyFileSystem(await requestHandler.getPrimaryPhp(), php, [
99 | '/tmp',
100 | requestHandler.documentRoot,
101 | ]);
102 | }
103 | if (reqHandler) {
104 | php.requestHandler = reqHandler;
105 | }
106 | return php;
107 | },
108 | documentRoot: environment.server.mount,
109 | absoluteUrl: `${environment.server.scheme}://${environment.server.host}`,
110 | rewriteRules: wordPressRewriteRules,
111 | getFileNotFoundAction: getFileNotFoundActionForWordPress,
112 | });
113 |
114 | const php = await requestHandler.getPrimaryPhp();
115 | php.mkdir(environment.server.mount);
116 | php.mount(environment.server.mount, createNodeFsMountHandler(environment.server.path));
117 | php.chdir(environment.server.mount);
118 | php.writeFile('/internal/shared/ca-bundle.crt', rootCertificates.join('\n'));
119 |
120 |
121 | return php;
122 | }
123 |
124 | // Create temporary preload script file
125 | const preloadPath = path.resolve("./src/preload.js");
126 | fs.writeFileSync(preloadPath, preloadScript);
127 |
128 | // Register custom protocol
129 | protocol.registerSchemesAsPrivileged([
130 | {
131 | scheme: environment.server.scheme,
132 | privileges: {
133 | standard: true,
134 | secure: true,
135 | supportFetchAPI: true,
136 | corsEnabled: true,
137 | stream: true
138 | }
139 | }
140 | ]);
141 | async function createWindow() {
142 |
143 | const win = new BrowserWindow({
144 | width: 1024,
145 | height: 768,
146 | webPreferences: {
147 | nodeIntegration: false,
148 | contextIsolation: true,
149 | preload: preloadPath,
150 | webSecurity: false, // Note: In production, consider security implications
151 | allowRunningInsecureContent: true
152 | }
153 | });
154 |
155 | // Initialize PHP handler
156 | const php = await initializePHPHandler();
157 |
158 | // Content Security Policy middleware
159 | const cspMiddleware = (headers) => {
160 | const csp = [
161 | "default-src 'self' 'unsafe-inline' 'unsafe-eval'",
162 | `script-src 'self' 'unsafe-inline' 'unsafe-eval' ${environment.server.scheme}://${environment.server.host}`,
163 | "style-src 'self' 'unsafe-inline'",
164 | "img-src 'self' data: blob:",
165 | `connect-src 'self' ${environment.server.scheme}://${environment.server.host}`,
166 | ].join('; ');
167 |
168 | headers['Content-Security-Policy'] = csp;
169 | return headers;
170 | };
171 |
172 | // Register protocol handler
173 | protocol.handle(environment.server.scheme, async (request) => {
174 | try {
175 | const url = new URL(request.url);
176 | const headers = {};
177 | request.headers.forEach((value, key) => {
178 | headers[key.toLowerCase()] = value;
179 | });
180 |
181 | // Handle static files (including JavaScript files)
182 | if (url.pathname.endsWith('.js') || url.pathname.endsWith('.css') || url.pathname.endsWith('.html') || url.pathname.endsWith('.png') || url.pathname.endsWith('.jpg')) {
183 | const filePath = path.join(environment.server.path, url.pathname);
184 | try {
185 | let contentType = 'text/plain';
186 | if (url.pathname.endsWith('.js')) {
187 | contentType = 'application/javascript';
188 | } else if (url.pathname.endsWith('.css')) {
189 | contentType = 'text/css';
190 | } else if (url.pathname.endsWith('.html')) {
191 | contentType = 'text/html';
192 | if (url.pathname.endsWith('login.html')) {
193 | const content = fs.readFileSync(path.resolve("./src/login.html"));
194 | return new Response(content, {
195 | headers: {
196 | 'Content-Type': contentType,
197 | 'Access-Control-Allow-Origin': '*'
198 | }
199 | });
200 | }
201 | } else if (url.pathname.endsWith('.png')) {
202 | contentType = 'image/png';
203 | } else if (url.pathname.endsWith('.jpg')) {
204 | contentType = 'image/jpeg';
205 | }
206 | const content = fs.readFileSync(filePath);
207 | return new Response(content, {
208 | headers: {
209 | 'Content-Type': contentType,
210 | 'Access-Control-Allow-Origin': '*'
211 | }
212 | });
213 | } catch (err) {
214 | console.error('Static file error:', err);
215 | }
216 | }
217 |
218 | // Prepare request data for PHP
219 | const requestData = {
220 | url: url.pathname + url.search,
221 | headers: headers,
222 | method: request.method,
223 | body: await requestBodyToBytes(request),
224 | };
225 |
226 | // Process request through PHP handler
227 | const response = await php.requestHandler.request(requestData);
228 |
229 | if (environment.server.debug) {
230 | console.log('Request:', {
231 | url: url.toString(),
232 | method: request.method,
233 | headers: headers
234 | });
235 | console.log('Response:', {
236 | status: response.httpStatusCode,
237 | headers: response.headers
238 | });
239 | }
240 |
241 | // Apply security headers and return response
242 | const finalHeaders = cspMiddleware({...response.headers});
243 | return new Response(response.bytes, {
244 | status: response.httpStatusCode,
245 | headers: finalHeaders
246 | });
247 | } catch (error) {
248 | console.error('Error handling request:', error);
249 | return new Response('Internal Server Error', {
250 | status: 500,
251 | headers: {'Content-Type': 'text/plain'}
252 | });
253 | }
254 | });
255 |
256 | // Load initial page
257 | await win.loadURL(`${environment.server.scheme}://${environment.server.host}/login.html`);
258 |
259 | if (environment.server.debug) {
260 | }
261 | win.webContents.openDevTools();
262 |
263 | // Cleanup preload script on window close
264 | win.on('closed', () => {
265 | try {
266 | fs.unlinkSync(preloadPath);
267 | } catch (err) {
268 | console.error('Error cleaning up preload script:', err);
269 | }
270 | });
271 |
272 | // 监听来自渲染进程的更新配置请求
273 | ipcMain.on('update-config', (event, { hostname, username, password }) => {
274 | try {
275 | const configFilePath = path.join(environment.server.path, 'config.inc.php');
276 | let configContent = fs.readFileSync(configFilePath, 'utf-8');
277 |
278 | configContent = configContent.replace(/\$cfg\['Servers'\]\[\$i\]\['host'\] = '.*?';/, `$cfg['Servers'][$i]['host'] = '${hostname}';`);
279 | configContent = configContent.replace(/\$cfg\['Servers'\]\[\$i\]\['user'\] = '.*?';/, `$cfg['Servers'][$i]['user'] = '${username}';`);
280 | configContent = configContent.replace(/\$cfg\['Servers'\]\[\$i\]\['password'\] = '.*?';/, `$cfg['Servers'][$i]['password'] = '${password}';`);
281 |
282 | fs.writeFileSync(configFilePath, configContent, 'utf-8');
283 |
284 | // 通知渲染进程更新成功
285 | event.sender.send('update-config-success');
286 |
287 | // 更新完成后跳转至根页面
288 | win.loadURL(`${environment.server.scheme}://${environment.server.host}/`);
289 | } catch (err) {
290 | console.error('Error updating config:', err);
291 | // 通知渲染进程更新失败
292 | event.sender.send('update-config-failure', err.message);
293 | }
294 | });
295 | }
296 |
297 | app.whenReady().then(async () => {
298 | await createWindow();
299 |
300 | app.on('activate', async () => {
301 | if (BrowserWindow.getAllWindows().length === 0) {
302 | await createWindow();
303 | }
304 | });
305 | });
306 |
307 | app.on('window-all-closed', () => {
308 | if (process.platform !== 'darwin') {
309 | app.quit();
310 | }
311 | });
312 |
313 |
--------------------------------------------------------------------------------
/src/networking/inbound-tcp-to-ws-proxy.js:
--------------------------------------------------------------------------------
1 | import { createServer } from 'net';
2 | import { WebSocketServer, WebSocket } from 'ws';
3 | import { debugLog } from './utils.js';
4 | function log(...args) {
5 | debugLog('[TCP Server]', ...args);
6 | }
7 |
8 | export function addTCPServerToWebSocketServerClass(
9 | wsListenPort,
10 | WSServer
11 | ) {
12 | return class PHPWasmWebSocketServer extends WSServer {
13 | constructor(options, callback) {
14 | const requestedPort = options.port;
15 | options.port = wsListenPort;
16 | listenTCPToWSProxy({
17 | tcpListenPort: requestedPort,
18 | wsConnectPort: wsListenPort,
19 | });
20 | super(options, callback);
21 | }
22 | };
23 | }
24 |
25 | export function listenTCPToWSProxy(options) {
26 | options = {
27 | wsConnectHost: '127.0.0.1',
28 | ...options,
29 | };
30 | const { tcpListenPort, wsConnectHost, wsConnectPort } = options;
31 | const server = createServer();
32 | server.on('connection', function handleConnection(tcpSource) {
33 | const inBuffer = [];
34 |
35 | const wsTarget = new WebSocket(
36 | `ws://${wsConnectHost}:${wsConnectPort}/`
37 | );
38 | wsTarget.binaryType = 'arraybuffer';
39 | function wsSend(data) {
40 | wsTarget.send(new Uint8Array(data));
41 | }
42 |
43 | wsTarget.addEventListener('open', function () {
44 | log('Outbound WebSocket connection established');
45 | while (inBuffer.length > 0) {
46 | wsSend(inBuffer.shift());
47 | }
48 | });
49 | wsTarget.addEventListener('message', (e) => {
50 | log(
51 | 'WS->TCP message:',
52 | new TextDecoder().decode(e.data)
53 | );
54 | // @ts-ignore-next-line
55 | tcpSource.write(Buffer.from(e.data));
56 | });
57 | wsTarget.addEventListener('close', () => {
58 | log('WebSocket connection closed');
59 | tcpSource.end();
60 | });
61 |
62 | tcpSource.on('data', function (data) {
63 | log('TCP->WS message:', data);
64 | if (wsTarget.readyState === WebSocket.OPEN) {
65 | while (inBuffer.length > 0) {
66 | wsSend(inBuffer.shift());
67 | }
68 | wsSend(data);
69 | } else {
70 | inBuffer.push(data);
71 | }
72 | });
73 | tcpSource.once('close', function () {
74 | log('TCP connection closed');
75 | wsTarget.close();
76 | });
77 | tcpSource.on('error', function () {
78 | log('TCP connection error');
79 | wsTarget.close();
80 | });
81 | });
82 | server.listen(tcpListenPort, function () {
83 | log('TCP server listening');
84 | });
85 | }
86 |
--------------------------------------------------------------------------------
/src/networking/outbound-ws-to-tcp-proxy.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as dns from 'dns';
4 | import * as util from 'node:util';
5 | import * as net from 'net';
6 | import * as http from 'http';
7 | import { WebSocketServer } from 'ws';
8 | import { debugLog } from './utils.js';
9 |
10 | function log(...args) {
11 | debugLog('[WS Server]', ...args);
12 | }
13 |
14 | const lookup = util.promisify(dns.lookup);
15 |
16 | function prependByte(
17 | chunk,
18 | byte
19 | ) {
20 | if (typeof chunk === 'string') {
21 | chunk = String.fromCharCode(byte) + chunk;
22 | } else if (
23 | chunk instanceof ArrayBuffer ||
24 | 'byteLength' in chunk /* for Node.js */
25 | ) {
26 | const buffer = new Uint8Array((chunk).byteLength + 1);
27 | buffer[0] = byte;
28 | buffer.set(new Uint8Array(chunk), 1);
29 | chunk = buffer.buffer;
30 | } else {
31 | log({ chunk });
32 | throw new Error('Unsupported chunk type: ' + typeof chunk);
33 | }
34 | return chunk;
35 | }
36 |
37 | /**
38 | * Send a chunk of data to the remote server.
39 | */
40 | export const COMMAND_CHUNK = 0x01;
41 | /**
42 | * Set a TCP socket option.
43 | */
44 | export const COMMAND_SET_SOCKETOPT = 0x02;
45 |
46 | /**
47 | * Adds support for TCP socket options to WebSocket class.
48 | *
49 | * Socket options are implemented by adopting a specific data transmission
50 | * protocol between WS client and WS server The first byte
51 | * of every message is a command type, and the remaining bytes
52 | * are the actual data.
53 | *
54 | * @param WebSocketConstructor
55 | * @returns Decorated constructor
56 | */
57 | export function addSocketOptionsSupportToWebSocketClass(
58 | WebSocketConstructor
59 | ) {
60 | return class PHPWasmWebSocketConstructor extends WebSocketConstructor {
61 | // @ts-ignore
62 | send(chunk, callback) {
63 | return this.sendCommand(COMMAND_CHUNK, chunk, callback);
64 | }
65 |
66 | setSocketOpt(
67 | optionClass,
68 | optionName,
69 | optionValue
70 | ) {
71 | return this.sendCommand(
72 | COMMAND_SET_SOCKETOPT,
73 | new Uint8Array([optionClass, optionName, optionValue]).buffer,
74 | () => undefined
75 | );
76 | }
77 | sendCommand(
78 | commandType,
79 | chunk,
80 | callback
81 | ) {
82 | return (WebSocketConstructor.prototype.send).call(
83 | this,
84 | prependByte(chunk, commandType),
85 | callback
86 | );
87 | }
88 | };
89 | }
90 |
91 | export function initOutboundWebsocketProxyServer(
92 | listenPort,
93 | listenHost = '127.0.0.1'
94 | ) {
95 | log(`Binding the WebSockets server to ${listenHost}:${listenPort}...`);
96 | const webServer = http.createServer((request, response) => {
97 | response.writeHead(403, { 'Content-Type': 'text/plain' });
98 | response.write(
99 | '403 Permission Denied\nOnly websockets are allowed here.\n'
100 | );
101 | response.end();
102 | });
103 | return new Promise((resolve) => {
104 | webServer.listen(listenPort, listenHost, function () {
105 | const wsServer = new WebSocketServer({ server: webServer });
106 | wsServer.on('connection', onWsConnect);
107 | resolve(webServer);
108 | });
109 | });
110 | }
111 |
112 | // Handle new WebSocket client
113 | async function onWsConnect(client, request) {
114 | const clientAddr = client?._socket?.remoteAddress || client.url;
115 | const clientLog = function (...args) {
116 | log(' ' + clientAddr + ': ', ...args);
117 | };
118 |
119 | clientLog(
120 | 'WebSocket connection from : ' +
121 | clientAddr +
122 | ' at URL ' +
123 | (request ? request.url : client.upgradeReq.url)
124 | );
125 | clientLog(
126 | 'Version ' +
127 | client.protocolVersion +
128 | ', subprotocol: ' +
129 | client.protocol
130 | );
131 |
132 | // Parse the search params (the host doesn't matter):
133 | const reqUrl = new URL(`ws://0.0.0.0` + request.url);
134 | const reqTargetPort = Number(reqUrl.searchParams.get('port'));
135 | const reqTargetHost = reqUrl.searchParams.get('host');
136 | if (!reqTargetPort || !reqTargetHost) {
137 | clientLog('Missing host or port information');
138 | client.close(3000);
139 | return;
140 | }
141 |
142 | // eslint-disable-next-line prefer-const
143 | let target;
144 | const recvQueue = [];
145 | function flushMessagesQueue() {
146 | while (recvQueue.length > 0) {
147 | const msg = recvQueue.pop();
148 | const commandType = msg[0];
149 | clientLog('flushing', { commandType }, msg);
150 | if (commandType === COMMAND_CHUNK) {
151 | target.write(msg.slice(1));
152 | } else if (commandType === COMMAND_SET_SOCKETOPT) {
153 | const SOL_SOCKET = 1;
154 | const SO_KEEPALIVE = 9;
155 |
156 | const IPPROTO_TCP = 6;
157 | const TCP_NODELAY = 1;
158 | if (msg[1] === SOL_SOCKET && msg[2] === SO_KEEPALIVE) {
159 | target.setKeepAlive(msg[3]);
160 | } else if (msg[1] === IPPROTO_TCP && msg[2] === TCP_NODELAY) {
161 | target.setNoDelay(msg[3]);
162 | }
163 | } else {
164 | clientLog('Unknown command type: ' + commandType);
165 | process.exit();
166 | }
167 | }
168 | }
169 |
170 | client.on('message', function (msg) {
171 | // clientLog('PHP -> network buffer:', msg);
172 | recvQueue.unshift(msg);
173 | if (target) {
174 | flushMessagesQueue();
175 | }
176 | });
177 | client.on('close', function (code, reason) {
178 | clientLog(
179 | 'WebSocket client disconnected: ' + code + ' [' + reason + ']'
180 | );
181 | if (target) {
182 | target.end();
183 | }
184 | });
185 | client.on('error', function (a) {
186 | clientLog('WebSocket client error: ' + a);
187 | target.end();
188 | });
189 |
190 | // Resolve the target host to an IP address if it isn't one already
191 | let reqTargetIp;
192 | if (net.isIP(reqTargetHost) === 0) {
193 | clientLog('resolving ' + reqTargetHost + '... ');
194 | try {
195 | const resolution = await lookup(reqTargetHost);
196 | reqTargetIp = resolution.address;
197 | clientLog('resolved ' + reqTargetHost + ' -> ' + reqTargetIp);
198 | } catch (e) {
199 | clientLog("can't resolve " + reqTargetHost + ' due to:', e);
200 | // Send empty binary data to notify requester that connection was
201 | // initiated
202 | client.send([]);
203 | client.close(3000);
204 | return;
205 | }
206 | } else {
207 | reqTargetIp = reqTargetHost;
208 | }
209 | clientLog(
210 | 'Opening a socket connection to ' + reqTargetIp + ':' + reqTargetPort
211 | );
212 | target = net.createConnection(reqTargetPort, reqTargetIp, function () {
213 | clientLog('Connected to target');
214 | flushMessagesQueue();
215 | });
216 | target.on('data', function (data) {
217 | // clientLog(
218 | // 'network -> PHP buffer:',
219 | // [...data.slice(0, 100)].join(', ') + '...'
220 | // );
221 | try {
222 | client.send(data);
223 | } catch (e) {
224 | clientLog('Client closed, cleaning up target');
225 | target.end();
226 | }
227 | });
228 | target.on('end', function () {
229 | clientLog('target disconnected');
230 | client.close();
231 | });
232 | target.on('error', function (e) {
233 | clientLog('target connection error', e);
234 | target.end();
235 | client.close(3000);
236 | });
237 | }
238 |
--------------------------------------------------------------------------------
/src/networking/php.ini:
--------------------------------------------------------------------------------
1 | error_reporting=E_ALL
2 | display_errors=1
3 | html_errors=1
4 | display_startup_errors=On
5 | log_errors=1
6 | always_populate_raw_post_data=-1
7 | upload_max_filesize=2000M
8 | post_max_size=2000M
9 | disable_functions=proc_open,popen,curl_exec,curl_multi_exec
10 | allow_url_fopen=On
11 | session.save_path=/home/web_user
12 | implicit_flush=1
13 | output_buffering=4096
14 |
--------------------------------------------------------------------------------
/src/networking/utils.js:
--------------------------------------------------------------------------------
1 | import * as net from 'net';
2 | import { logger } from '@php-wasm/logger';
3 |
4 | export function debugLog(message, ...args) {
5 | if (process.env['DEV'] && !process.env['TEST']) {
6 | logger.log(message, ...args);
7 | }
8 | }
9 |
10 | export async function findFreePorts(n) {
11 | const serversPromises = [];
12 | for (let i = 0; i < n; i++) {
13 | serversPromises.push(listenOnRandomPort());
14 | }
15 |
16 | const servers = await Promise.all(serversPromises);
17 | const ports = [];
18 | for (const server of servers) {
19 | const address = server.address();
20 | ports.push(address.port);
21 | server.close();
22 | }
23 |
24 | return ports;
25 | }
26 |
27 | function listenOnRandomPort() {
28 | return new Promise((resolve) => {
29 | const server = net.createServer();
30 | server.listen(0, () => {
31 | resolve(server);
32 | });
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/src/networking/with-networking.js:
--------------------------------------------------------------------------------
1 | import {
2 | initOutboundWebsocketProxyServer,
3 | addSocketOptionsSupportToWebSocketClass,
4 | } from './outbound-ws-to-tcp-proxy.js';
5 | import { addTCPServerToWebSocketServerClass } from './inbound-tcp-to-ws-proxy.js';
6 | import { findFreePorts } from './utils.js';
7 |
8 | export async function withNetworking(
9 | phpModuleArgs = {}
10 | ) {
11 | const [inboundProxyWsServerPort, outboundProxyWsServerPort] =
12 | await findFreePorts(2);
13 |
14 | const outboundNetworkProxyServer = await initOutboundWebsocketProxyServer(
15 | outboundProxyWsServerPort
16 | );
17 |
18 | return {
19 | ...phpModuleArgs,
20 | outboundNetworkProxyServer,
21 | websocket: {
22 | ...(phpModuleArgs['websocket'] || {}),
23 | url: (_, host, port) => {
24 | const query = new URLSearchParams({
25 | host,
26 | port,
27 | }).toString();
28 | return `ws://127.0.0.1:${outboundProxyWsServerPort}/?${query}`;
29 | },
30 | subprotocol: 'binary',
31 | decorator: addSocketOptionsSupportToWebSocketClass,
32 | serverDecorator: addTCPServerToWebSocketServerClass.bind(
33 | null,
34 | inboundProxyWsServerPort
35 | ),
36 | },
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/tests/fetch-hook.js:
--------------------------------------------------------------------------------
1 | const originalFetch = global.fetch;
2 |
3 | global.fetch = async function(...args) {
4 | console.log('Fetch Request:', args);
5 | return originalFetch.apply(this, args);
6 | };
7 |
--------------------------------------------------------------------------------
/tests/http-hook.js:
--------------------------------------------------------------------------------
1 |
2 | import http from 'http'
3 | import https from 'https'
4 |
5 | // 保存原始的 http.request 和 https.request 方法
6 | const originalHttpRequest = http.request;
7 | const originalHttpsRequest = https.request;
8 |
9 | // 重写 http.request 和 https.request 方法
10 | http.request = function(options, callback) {
11 | console.log(`HTTP Request:${options.host} ${options.port} ${options.path}`, );
12 | return originalHttpRequest.call(http, options, callback);
13 | };
14 |
15 | https.request = function(options, callback) {
16 | console.log('HTTPS Request:', options);
17 | return originalHttpsRequest.call(https, options, callback);
18 | };
19 |
--------------------------------------------------------------------------------
/tests/ip-hook.js:
--------------------------------------------------------------------------------
1 |
2 | import net from 'net'
3 | import dgram from 'dgram'
4 |
5 | // 保存原始方法
6 | const originalCreateConnection = net.createConnection;
7 | const originalConnect = net.connect;
8 | const originalCreateServer = net.createServer;
9 | const originalCreateSocket = dgram.createSocket;
10 |
11 | // 重写 net.createConnection
12 | net.createConnection = function(...args) {
13 | console.log('net.createConnection called with:', args);
14 | return originalCreateConnection.apply(net, args);
15 | };
16 |
17 | // 重写 net.connect
18 | net.connect = function(...args) {
19 | console.log('net.connect called with:', args);
20 | return originalConnect.apply(net, args);
21 | };
22 |
23 | // 重写 net.createServer
24 | net.createServer = function(...args) {
25 | console.log('net.createServer called with:', args);
26 | return originalCreateServer.apply(net, args);
27 | };
28 |
29 | // 重写 dgram.createSocket
30 | dgram.createSocket = function(...args) {
31 | console.log('dgram.createSocket called with:', args);
32 | const socket = originalCreateSocket.apply(dgram, args);
33 |
34 | // 拦截 socket 的 send 方法
35 | const originalSend = socket.send;
36 | socket.send = function(...sendArgs) {
37 | console.log('dgram.send called with:', sendArgs);
38 | return originalSend.apply(socket, sendArgs);
39 | };
40 |
41 | // 拦截 socket 的 bind 方法
42 | const originalBind = socket.bind;
43 | socket.bind = function(...bindArgs) {
44 | console.log('dgram.bind called with:', bindArgs);
45 | return originalBind.apply(socket, bindArgs);
46 | };
47 |
48 | return socket;
49 | };
50 |
--------------------------------------------------------------------------------
/tests/ws-hook.js:
--------------------------------------------------------------------------------
1 | // wsInterceptor.mjs
2 | import WebSocket from 'ws';
3 |
4 | // 保存原始的 WebSocket 构造函数
5 | const OriginalWebSocket = WebSocket;
6 |
7 | // 创建一个自定义的 WebSocket 构造函数
8 | class InterceptedWebSocket extends OriginalWebSocket {
9 | constructor(address, protocols, options) {
10 | super(address, protocols, options);
11 |
12 | // 监听连接打开事件
13 | this.on('open', () => {
14 | console.log(`WebSocket连接已打开: ${address}`);
15 | // 您可以在这里添加自定义逻辑,如记录连接信息
16 | });
17 |
18 | // 监听消息接收事件
19 | this.on('message', (data) => {
20 | console.log(`WebSocket接收到消息: ${data}`);
21 | // 您可以在这里添加自定义逻辑,如处理或记录消息
22 | });
23 |
24 | // 监听连接关闭事件
25 | this.on('close', (code, reason) => {
26 | console.log(`WebSocket连接已关闭: ${address}, 代码: ${code}, 原因: ${reason}`);
27 | // 您可以在这里添加自定义逻辑,如清理资源
28 | });
29 |
30 | // 监听错误事件
31 | this.on('error', (error) => {
32 | console.error(`WebSocket错误: ${error}`);
33 | // 您可以在这里添加自定义逻辑,如错误处理
34 | });
35 | }
36 |
37 | // 重写 send 方法,以便在发送消息时执行自定义逻辑
38 | send(data, options, callback) {
39 | console.log(`WebSocket发送消息: ${data}`);
40 | // 您可以在这里修改数据或执行其他操作
41 |
42 | // 调用原始的 send 方法
43 | super.send(data, options, callback);
44 | }
45 | }
46 |
47 | // 定义一个函数来替换全局的 WebSocket
48 | export async function hookWebSocket() {
49 | globalThis.WebSocket = InterceptedWebSocket;
50 |
51 | // 如果 ws 模块已经被导入过,则需要替换其默认导出
52 | try {
53 | const wsModule = await import('ws');
54 | if (wsModule.default) {
55 | wsModule.default = InterceptedWebSocket;
56 | }
57 | } catch (err) {
58 | console.warn('ws 模块尚未被导入,稍后可能需要重新拦截。');
59 | }
60 | }
61 |
--------------------------------------------------------------------------------