mirror of
https://github.com/Molunerfinn/PicGo.git
synced 2026-09-20 03:16:37 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aefdb9bdb | ||
|
|
f1817eb1e1 | ||
|
|
2bd5d0653b | ||
|
|
9841418779 | ||
|
|
7bc70628f9 | ||
|
|
a928b4c8ab | ||
|
|
7df37a2526 | ||
|
|
dacb926f17 |
Vendored
+6
-2
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"eslint.enable": true,
|
||||
"eslint.alwaysShowStatus": true,
|
||||
"eslint.format.enable": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
@@ -23,5 +24,8 @@
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
"prettier.enable": false
|
||||
}
|
||||
"prettier.enable": false,
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
}
|
||||
@@ -1,3 +1,20 @@
|
||||
# :tada: 2.4.0-beta.10 (2025-06-08)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* finish form uploader for picgo server ([9841418](https://github.com/Molunerfinn/PicGo/commit/9841418))
|
||||
* **server:** add support for form upload in PicGo Server ([#1327](https://github.com/Molunerfinn/PicGo/issues/1327)) ([a928b4c](https://github.com/Molunerfinn/PicGo/commit/a928b4c)), closes [#428](https://github.com/Molunerfinn/PicGo/issues/428)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* auto-copy url can't be turned off ([#1300](https://github.com/Molunerfinn/PicGo/issues/1300)) ([dacb926](https://github.com/Molunerfinn/PicGo/commit/dacb926))
|
||||
* encoded url filename unreadable ([2bd5d06](https://github.com/Molunerfinn/PicGo/commit/2bd5d06))
|
||||
* unable to use clip in wayland ([#1301](https://github.com/Molunerfinn/PicGo/issues/1301)) ([7df37a2](https://github.com/Molunerfinn/PicGo/commit/7df37a2))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0-beta.9 (2024-12-02)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
PicGo is an Electron-based cross-platform image upload tool that supports multiple image hosting services (图床) including SMMS, GitHub, Aliyun OSS, Qiniu, Tencent COS, and more. It's built with Vue 3 + TypeScript for the renderer process and Node.js for the main process.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Structure
|
||||
- **Main Process**: `src/main/` - Electron main process with Node.js capabilities
|
||||
- **Renderer Process**: `src/renderer/` - Vue 3 frontend (no direct Node.js access)
|
||||
- **Universal Code**: `src/universal/` - Shared code between processes
|
||||
- **Entry Points**:
|
||||
- `src/background.ts` - Main process bootstrap
|
||||
- `src/main.ts` - Renderer process entry
|
||||
|
||||
### Key Directories
|
||||
- `src/main/apis/` - Main process APIs (uploader, system, window management)
|
||||
- `src/main/server/` - HTTP server for external uploads
|
||||
- `src/renderer/pages/` - Vue components for different views
|
||||
- `src/renderer/store/` - Vuex-like state management
|
||||
- `public/i18n/` - Internationalization files
|
||||
- `test/` - Unit and e2e tests
|
||||
|
||||
### Data Storage
|
||||
- **Config**: JSON file at `~/.picgo/config.json` (via `@picgo/store`)
|
||||
- **Gallery**: Separate DB for uploaded images history
|
||||
- **Settings**: Stored in config with namespaced keys (`settings.*`)
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Setup & Install
|
||||
```bash
|
||||
yarn install # Use yarn, NOT npm install
|
||||
```
|
||||
|
||||
### Development
|
||||
```bash
|
||||
yarn dev # Start development mode with hot reload
|
||||
yarn electron:serve # Alias for dev
|
||||
```
|
||||
|
||||
### Build & Release
|
||||
```bash
|
||||
yarn build # Build for production
|
||||
yarn electron:build # Build for production
|
||||
yarn release # Build and publish release
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
yarn lint # Run ESLint
|
||||
yarn lint:fix # Auto-fix lint issues
|
||||
yarn lint:dpdm # Check circular dependencies
|
||||
yarn gen-i18n # Generate i18n type definitions
|
||||
```
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
# Unit tests
|
||||
yarn test:unit # Run unit tests with Karma
|
||||
|
||||
# E2E tests
|
||||
yarn test:e2e # Run end-to-end tests
|
||||
```
|
||||
|
||||
### Git Workflow
|
||||
```bash
|
||||
yarn cz # Commit with conventional commits
|
||||
```
|
||||
|
||||
## Key Development Patterns
|
||||
|
||||
### Process Communication
|
||||
- Use IPC events for cross-process communication
|
||||
- Event names defined in `src/universal/events/constants.ts`
|
||||
- Main process handles Node.js operations, renderer sends requests
|
||||
|
||||
### Configuration
|
||||
- Settings stored in namespaced config keys
|
||||
- Use `saveConfig()` and `getConfig()` from renderer
|
||||
- Main process uses direct picgo instance APIs
|
||||
|
||||
### Internationalization
|
||||
- Translation files in `public/i18n/*.yml`
|
||||
- Run `yarn gen-i18n` after modifying translations
|
||||
- Use `T()` function for translations in renderer
|
||||
|
||||
### File Organization
|
||||
- **Main**: Node.js operations, file system, native features
|
||||
- **Renderer**: UI, Vue components, user interactions
|
||||
- **Universal**: Types, constants, shared utilities
|
||||
|
||||
## Build Configuration
|
||||
- **Electron Builder**: Configured in `vue.config.js`
|
||||
- **Platforms**: macOS (dmg), Windows (exe), Linux (AppImage, snap)
|
||||
- **Auto-updater**: Disabled (commented out in background.ts)
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a new feature
|
||||
1. Determine if it belongs in main or renderer process
|
||||
2. Add events to `src/universal/events/constants.ts` if needed
|
||||
3. For Node.js operations, add IPC handlers in main process
|
||||
4. For UI, add Vue components in renderer
|
||||
|
||||
### Modifying i18n
|
||||
1. Update `public/i18n/[lang].yml`
|
||||
2. Run `yarn gen-i18n`
|
||||
3. Add language option in `src/universal/i18n/index.ts`
|
||||
|
||||
### Adding new picbed support
|
||||
1. Use picgo plugin system (external to core)
|
||||
2. Core picbed configs are in `src/renderer/pages/picbeds/`
|
||||
|
||||
## Environment Notes
|
||||
- **Development**: Uses `vue-cli-plugin-electron-builder`
|
||||
- **Production**: Built with `electron-builder`
|
||||
- **Testing**: Karma for unit tests, Spectron for e2e
|
||||
- **Hot reload**: Available for both main and renderer processes
|
||||
+836
-207
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PicGo - The Ultimate Image Upload & Management Tool</title>
|
||||
<meta name="description" content="Seamlessly upload images to multiple cloud storage services with a beautiful, cross-platform interface. Supports 20+ image hosting services." />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"features": "Features",
|
||||
"plugins": "Plugins",
|
||||
"download": "Download",
|
||||
"docs": "Docs",
|
||||
"github": "GitHub"
|
||||
},
|
||||
"hero": {
|
||||
"title": "PicGo",
|
||||
"subtitle": "The Ultimate Image Upload & Management Tool",
|
||||
"description": "Seamlessly upload images to multiple cloud storage services with a beautiful, cross-platform interface. Supports 20+ image hosting services with powerful plugin system.",
|
||||
"download": "Download Free",
|
||||
"viewDocs": "View Documentation",
|
||||
"currentVersion": "Current Version"
|
||||
},
|
||||
"features": {
|
||||
"title": "Powerful Features",
|
||||
"subtitle": "Everything you need for efficient image management",
|
||||
"multiPicbed": {
|
||||
"title": "Multi-Picbed Support",
|
||||
"description": "Support for 20+ image hosting services including GitHub, SMMS, Aliyun OSS, Qiniu, Tencent COS, and more. Switch between different picbeds seamlessly."
|
||||
},
|
||||
"pluginSystem": {
|
||||
"title": "Plugin System",
|
||||
"description": "Extend PicGo's functionality with powerful plugins. From custom uploaders to advanced image processing, the possibilities are endless."
|
||||
},
|
||||
"crossPlatform": {
|
||||
"title": "Cross-Platform",
|
||||
"description": "Available on macOS, Windows, and Linux with native performance and consistent user experience across all platforms."
|
||||
},
|
||||
"clipboardUpload": {
|
||||
"title": "Clipboard Upload",
|
||||
"description": "Upload images directly from your clipboard with a single shortcut. Perfect for quick screenshots and captures."
|
||||
},
|
||||
"batchUpload": {
|
||||
"title": "Batch Operations",
|
||||
"description": "Upload multiple images at once, rename files automatically, and manage your uploads efficiently with batch operations."
|
||||
},
|
||||
"galleryManagement": {
|
||||
"title": "Gallery Management",
|
||||
"description": "Keep track of all your uploaded images with a built-in gallery. Search, preview, and manage your image history with ease."
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"title": "Plugin Ecosystem",
|
||||
"subtitle": "Extend PicGo beyond imagination",
|
||||
"description": "With our powerful plugin system, you can add new image hosting services, customize upload workflows, integrate with other tools, and much more.",
|
||||
"viewPlugins": "Browse Plugins",
|
||||
"createPlugin": "Create Your Own Plugin"
|
||||
},
|
||||
"supportedServices": {
|
||||
"title": "Supported Services",
|
||||
"subtitle": "Connect with your favorite image hosting services",
|
||||
"github": "GitHub",
|
||||
"smms": "SM.MS",
|
||||
"aliyun": "Aliyun OSS",
|
||||
"qiniu": "Qiniu",
|
||||
"tencent": "Tencent COS",
|
||||
"upyun": "Upyun",
|
||||
"imgur": "Imgur",
|
||||
"weibo": "Weibo",
|
||||
"andMore": "And 15+ more..."
|
||||
},
|
||||
"download": {
|
||||
"title": "Download PicGo",
|
||||
"subtitle": "Available for all major platforms",
|
||||
"macos": "Download for macOS",
|
||||
"windows": "Download for Windows",
|
||||
"linux": "Download for Linux",
|
||||
"or": "or",
|
||||
"viewReleases": "View all releases"
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "© 2017-2024 PicGo. Open source project maintained by",
|
||||
"author": "Molunerfinn",
|
||||
"license": "Licensed under MIT License",
|
||||
"links": {
|
||||
"github": "GitHub",
|
||||
"issues": "Issues",
|
||||
"discussions": "Discussions",
|
||||
"sponsor": "Sponsor"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"switch": "Switch Language",
|
||||
"english": "English",
|
||||
"chinese": "中文"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"nav": {
|
||||
"home": "ホーム",
|
||||
"features": "機能",
|
||||
"plugins": "プラグイン",
|
||||
"download": "ダウンロード",
|
||||
"docs": "ドキュメント",
|
||||
"github": "GitHub"
|
||||
},
|
||||
"hero": {
|
||||
"title": "PicGo",
|
||||
"subtitle": "究極の画像アップロード&管理ツール",
|
||||
"description": "美しいクロスプラットフォームインターフェースで、複数のクラウドストレージサービスに画像をシームレスにアップロード。20以上の画像ホスティングサービスをサポートし、強力なプラグインシステムを搭載。",
|
||||
"download": "無料ダウンロード",
|
||||
"viewDocs": "ドキュメントを見る",
|
||||
"currentVersion": "現在のバージョン"
|
||||
},
|
||||
"features": {
|
||||
"title": "強力な機能",
|
||||
"subtitle": "効率的な画像管理に必要なすべて",
|
||||
"multiPicbed": {
|
||||
"title": "マルチピクベッドサポート",
|
||||
"description": "GitHub、SMMS、Alibaba Cloud OSS、Qiniu、Tencent COSなど、20以上の画像ホスティングサービスをサポート。異なるピクベッド間をシームレスに切り替え。"
|
||||
},
|
||||
"pluginSystem": {
|
||||
"title": "プラグインシステム",
|
||||
"description": "強力なプラグインでPicGoの機能を拡張。カスタムアップローダーから高度な画像処理まで、可能性は無限大。"
|
||||
},
|
||||
"crossPlatform": {
|
||||
"title": "クロスプラットフォーム",
|
||||
"description": "macOS、Windows、Linuxで利用可能。すべてのプラットフォームでネイティブパフォーマンスと一貫したユーザー体験を提供。"
|
||||
},
|
||||
"clipboardUpload": {
|
||||
"title": "クリップボードアップロード",
|
||||
"description": "単一のショートカットでクリップボードから画像を直接アップロード。スクリーンショットやキャプチャーに最適。"
|
||||
},
|
||||
"batchUpload": {
|
||||
"title": "バッチ操作",
|
||||
"description": "複数の画像を一度にアップロードし、ファイルを自動的にリネーム。バッチ操作で効率的にアップロードを管理。"
|
||||
},
|
||||
"galleryManagement": {
|
||||
"title": "ギャラリー管理",
|
||||
"description": "内蔵ギャラリーですべてのアップロード画像を追跡。検索、プレビュー、画像履歴を簡単に管理。"
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"title": "プラグインエコシステム",
|
||||
"subtitle": "想像を超えてPicGoを拡張",
|
||||
"description": "強力なプラグインシステムにより、新しい画像ホスティングサービスを追加したり、アップロードワークフローをカスタマイズしたり、他のツールと統合したり、さらに多くのことが可能。",
|
||||
"viewPlugins": "プラグインを見る",
|
||||
"createPlugin": "独自のプラグインを作成"
|
||||
},
|
||||
"supportedServices": {
|
||||
"title": "サポートされているサービス",
|
||||
"subtitle": "お気に入りの画像ホスティングサービスと接続",
|
||||
"github": "GitHub",
|
||||
"smms": "SM.MS",
|
||||
"aliyun": "Alibaba Cloud OSS",
|
||||
"qiniu": "Qiniu",
|
||||
"tencent": "Tencent COS",
|
||||
"upyun": "Upyun",
|
||||
"imgur": "Imgur",
|
||||
"weibo": "Weibo",
|
||||
"andMore": "さらに15以上..."
|
||||
},
|
||||
"download": {
|
||||
"title": "PicGoをダウンロード",
|
||||
"subtitle": "すべての主要プラットフォームで利用可能",
|
||||
"macos": "macOS版をダウンロード",
|
||||
"windows": "Windows版をダウンロード",
|
||||
"linux": "Linux版をダウンロード",
|
||||
"or": "または",
|
||||
"viewReleases": "すべてのリリースを見る"
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "© 2017-2024 PicGo。オープンソースプロジェクト、メンテナ:",
|
||||
"author": "Molunerfinn",
|
||||
"license": "MITライセンスの下で提供",
|
||||
"links": {
|
||||
"github": "GitHub",
|
||||
"issues": "問題報告",
|
||||
"discussions": "ディスカッション",
|
||||
"sponsor": "スポンサー"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"switch": "言語を切り替え",
|
||||
"english": "English",
|
||||
"chinese": "中文"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"nav": {
|
||||
"home": "首页",
|
||||
"features": "特性",
|
||||
"plugins": "插件",
|
||||
"download": "下载",
|
||||
"docs": "文档",
|
||||
"github": "GitHub"
|
||||
},
|
||||
"hero": {
|
||||
"title": "PicGo",
|
||||
"subtitle": "终极图片上传与管理工具",
|
||||
"description": "无缝上传图片到多个云存储服务,拥有美观的跨平台界面。支持20多种图床服务,配备强大的插件系统。",
|
||||
"download": "免费下载",
|
||||
"viewDocs": "查看文档",
|
||||
"currentVersion": "当前版本"
|
||||
},
|
||||
"features": {
|
||||
"title": "强大特性",
|
||||
"subtitle": "高效图片管理所需的一切",
|
||||
"multiPicbed": {
|
||||
"title": "多图床支持",
|
||||
"description": "支持20多种图床服务,包括GitHub、SMMS、阿里云OSS、七牛云、腾讯云COS等。无缝切换不同图床。"
|
||||
},
|
||||
"pluginSystem": {
|
||||
"title": "插件系统",
|
||||
"description": "通过强大的插件系统扩展PicGo功能。从自定义上传器到高级图片处理,可能性无限。"
|
||||
},
|
||||
"crossPlatform": {
|
||||
"title": "跨平台",
|
||||
"description": "支持macOS、Windows和Linux,原生性能,所有平台提供一致的用户体验。"
|
||||
},
|
||||
"clipboardUpload": {
|
||||
"title": "剪贴板上传",
|
||||
"description": "通过快捷键直接从剪贴板上传图片。完美适用于快速截图和捕获。"
|
||||
},
|
||||
"batchUpload": {
|
||||
"title": "批量操作",
|
||||
"description": "一次性上传多张图片,自动重命名文件,通过批量操作高效管理上传。"
|
||||
},
|
||||
"galleryManagement": {
|
||||
"title": "相册管理",
|
||||
"description": "通过内置相册跟踪所有上传图片。轻松搜索、预览和管理图片历史记录。"
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"title": "插件生态",
|
||||
"subtitle": "让PicGo超越想象",
|
||||
"description": "凭借强大的插件系统,您可以添加新的图床服务、自定义上传工作流、集成其他工具等等。",
|
||||
"viewPlugins": "浏览插件",
|
||||
"createPlugin": "创建您的插件"
|
||||
},
|
||||
"supportedServices": {
|
||||
"title": "支持的服务",
|
||||
"subtitle": "连接您喜爱的图床服务",
|
||||
"github": "GitHub",
|
||||
"smms": "SM.MS",
|
||||
"aliyun": "阿里云OSS",
|
||||
"qiniu": "七牛云",
|
||||
"tencent": "腾讯云COS",
|
||||
"upyun": "又拍云",
|
||||
"imgur": "Imgur",
|
||||
"weibo": "微博图床",
|
||||
"andMore": "以及15+更多..."
|
||||
},
|
||||
"download": {
|
||||
"title": "下载PicGo",
|
||||
"subtitle": "支持所有主流平台",
|
||||
"macos": "下载macOS版",
|
||||
"windows": "下载Windows版",
|
||||
"linux": "下载Linux版",
|
||||
"or": "或",
|
||||
"viewReleases": "查看所有版本"
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "© 2017-2024 PicGo。由",
|
||||
"author": "Molunerfinn",
|
||||
"license": "维护的开源项目,MIT许可证",
|
||||
"links": {
|
||||
"github": "GitHub",
|
||||
"issues": "问题反馈",
|
||||
"discussions": "讨论",
|
||||
"sponsor": "赞助"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"switch": "切换语言",
|
||||
"english": "English",
|
||||
"chinese": "中文"
|
||||
}
|
||||
}
|
||||
+20
-6
@@ -1,10 +1,24 @@
|
||||
import Vue from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import App from './APP.vue'
|
||||
import 'melody.css'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import en from './locales/en.json'
|
||||
import zhCN from './locales/zh-CN.json'
|
||||
import 'tailwindcss/tailwind.css'
|
||||
import axios from 'axios'
|
||||
|
||||
Vue.prototype.$http = axios
|
||||
const messages = {
|
||||
en,
|
||||
'zh-CN': zhCN
|
||||
}
|
||||
|
||||
new Vue({
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
messages
|
||||
})
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(i18n)
|
||||
app.config.globalProperties.$http = axios
|
||||
app.mount('#app')
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "picgo-website",
|
||||
"version": "1.0.0",
|
||||
"description": "Modern PicGo official website",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"serve": "npx serve ."
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.31",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"axios": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"vite": "^5.3.4",
|
||||
"tailwindcss": "^3.4.6",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"postcss": "^8.4.39",
|
||||
"serve": "^14.2.3"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
Generated
+1998
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||
"./**/*.{vue,js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
'sans': ['Inter', 'system-ui', 'sans-serif'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
+4
-1
@@ -4,7 +4,10 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>PicGo</title>
|
||||
<title>PicGo - The Ultimate Image Upload & Management Tool</title>
|
||||
<meta name="description" content="Seamlessly upload images to multiple cloud storage services with a beautiful, cross-platform interface. Supports 20+ image hosting services.">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 3000,
|
||||
open: true
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'assets',
|
||||
sourcemap: true,
|
||||
target: 'es2022'
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: ['vue', 'vue-i18n', 'axios']
|
||||
}
|
||||
})
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "picgo",
|
||||
"version": "2.4.0-beta.9",
|
||||
"version": "2.4.0-beta.10",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "vue-cli-service electron:build",
|
||||
@@ -34,7 +34,8 @@
|
||||
"lowdb": "^1.0.0",
|
||||
"marked": "^7.0.4",
|
||||
"mitt": "^3.0.0",
|
||||
"picgo": "^1.5.8",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"picgo": "^1.5.9",
|
||||
"qrcode.vue": "^3.3.3",
|
||||
"shell-path": "2.1.0",
|
||||
"uuid": "^9.0.0",
|
||||
@@ -54,6 +55,7 @@
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/lowdb": "^1.0.9",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@types/node": "^16.10.2",
|
||||
"@types/request-promise-native": "^1.0.17",
|
||||
"@types/semver": "^7.3.8",
|
||||
|
||||
+7
-12
@@ -17,18 +17,13 @@ if [ "$XDG_SESSION_TYPE" = "x11" ]; then
|
||||
echo $filePath
|
||||
fi
|
||||
elif [ "$XDG_SESSION_TYPE" = "wayland" ]; then
|
||||
command -v wl-copy >/dev/null 2>&1 || { echo >&1 "no wl-clipboard"; exit 1; }
|
||||
filePath=`wl-copy -o 2>/dev/null | grep ^file:// | cut -c8-`
|
||||
if [ ! -n "$filePath" ] ;then
|
||||
if
|
||||
wl-copy -t image/png -o >/dev/null 2>&1
|
||||
then
|
||||
wl-copy -t image/png image/png -o >$1 2>/dev/null
|
||||
echo $1
|
||||
else
|
||||
echo "no image"
|
||||
fi
|
||||
command -v wl-paste >/dev/null 2>&1 || { echo >&1 "no wl-clipboard"; exit 1; }
|
||||
isImage=`wl-paste --list-types | grep image`
|
||||
if [ -n "$isImage" ]; then
|
||||
wl-paste --type image/png > $1 2>/dev/null
|
||||
echo $1
|
||||
else
|
||||
echo $filePath
|
||||
echo "no image"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -21,6 +21,7 @@ import path from 'path'
|
||||
import { privacyManager } from '~/main/utils/privacyManager'
|
||||
import writeFile from 'write-file-atomic'
|
||||
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
|
||||
import { cleanupFormUploaderFiles } from '~/main/utils/cleanupFormUploaderFiles'
|
||||
|
||||
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
|
||||
return new Promise((resolve) => {
|
||||
@@ -176,6 +177,7 @@ class Uploader {
|
||||
return false
|
||||
} finally {
|
||||
ipcMain.removeAllListeners(GET_RENAME_FILE_NAME)
|
||||
cleanupFormUploaderFiles(img)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { app as APP } from 'electron'
|
||||
import { getLogger } from '@core/utils/localLogger'
|
||||
import dayjs from 'dayjs'
|
||||
import { T } from '~/main/i18n'
|
||||
import { FORM_IMAGE_FOLDER } from '~/universal/utils/static'
|
||||
const STORE_PATH = APP.getPath('userData')
|
||||
const configFilePath = path.join(STORE_PATH, 'data.json')
|
||||
const configFileBackupPath = path.join(STORE_PATH, 'data.bak.json')
|
||||
@@ -131,9 +132,19 @@ function getGalleryDBPath (): {
|
||||
}
|
||||
}
|
||||
|
||||
function getFormImageFolderPath (): string {
|
||||
const STORE_PATH = dbPathDir()
|
||||
const formImagesPath = path.join(STORE_PATH, FORM_IMAGE_FOLDER)
|
||||
if (!fs.existsSync(formImagesPath)) {
|
||||
fs.mkdirSync(formImagesPath, { recursive: true })
|
||||
}
|
||||
return formImagesPath
|
||||
}
|
||||
|
||||
export {
|
||||
dbChecker,
|
||||
dbPathChecker,
|
||||
dbPathDir,
|
||||
getGalleryDBPath
|
||||
getGalleryDBPath,
|
||||
getFormImageFolderPath
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import picgo from '@core/picgo'
|
||||
import logger from '@core/picgo/logger'
|
||||
import axios from 'axios'
|
||||
import formUploader from './middlewares/formUploader'
|
||||
|
||||
class Server {
|
||||
private httpServer: http.Server
|
||||
@@ -56,6 +57,8 @@ class Server {
|
||||
success: false
|
||||
}
|
||||
})
|
||||
} else if (formUploader.isFileUpload(request)) {
|
||||
formUploader.handleFileUpload(request, response)
|
||||
} else {
|
||||
let body: string = ''
|
||||
let postObj: IObj
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import http from 'http'
|
||||
import multer from 'multer'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { dbPathDir } from 'apis/core/datastore/dbChecker'
|
||||
import logger from '@core/picgo/logger'
|
||||
import { handleResponse } from '../utils'
|
||||
import routers from '../routerManager'
|
||||
import { FORM_IMAGE_FOLDER } from '~/universal/utils/static'
|
||||
|
||||
// Multer 错误类型定义
|
||||
export interface MulterError extends Error {
|
||||
code: string
|
||||
field?: string
|
||||
storageErrors?: any[]
|
||||
}
|
||||
|
||||
// Multer 中间件适配器类型
|
||||
export type MulterMiddleware = (
|
||||
req: http.IncomingMessage,
|
||||
res: http.ServerResponse,
|
||||
callback: (error?: MulterError) => void
|
||||
) => void;
|
||||
|
||||
// 扩展 multer 函数的返回类型
|
||||
declare module 'multer' {
|
||||
interface Multer {
|
||||
array(fieldname: string, maxCount?: number): MulterMiddleware;
|
||||
single(fieldname: string): MulterMiddleware;
|
||||
fields(fields: { name: string; maxCount?: number }[]): MulterMiddleware;
|
||||
none(): MulterMiddleware;
|
||||
}
|
||||
}
|
||||
|
||||
class FormUploader {
|
||||
private upload!: multer.Multer
|
||||
private formImagesPath!: string
|
||||
|
||||
constructor () {
|
||||
this.initializeStorage()
|
||||
this.setupMulter()
|
||||
}
|
||||
|
||||
private initializeStorage () {
|
||||
const STORE_PATH = dbPathDir()
|
||||
this.formImagesPath = path.join(STORE_PATH, FORM_IMAGE_FOLDER)
|
||||
if (!fs.existsSync(this.formImagesPath)) {
|
||||
fs.mkdirSync(this.formImagesPath, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
private setupMulter () {
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req: http.IncomingMessage, file: Express.Multer.File, cb: (error: Error | null, destination: string) => void) => {
|
||||
cb(null, this.formImagesPath)
|
||||
},
|
||||
filename: (req: http.IncomingMessage, file: Express.Multer.File, cb: (error: Error | null, filename: string) => void) => {
|
||||
cb(null, file.originalname || Date.now() + path.extname(file.originalname))
|
||||
}
|
||||
})
|
||||
|
||||
this.upload = multer({
|
||||
storage
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件上传的中间件
|
||||
*/
|
||||
public handleFileUpload = (request: http.IncomingMessage, response: http.ServerResponse): void => {
|
||||
logger.info('[PicGo Server] handling file upload')
|
||||
|
||||
this.upload.array('files')(request, response, async (err?: MulterError) => {
|
||||
if (err) {
|
||||
logger.error('[PicGo Server] file upload error', err)
|
||||
return handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: 'File upload failed'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const files = request.files
|
||||
if (!files || files.length === 0) {
|
||||
return handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: 'No files were uploaded'
|
||||
}
|
||||
})
|
||||
}
|
||||
const filePaths = files.map((file) => file.path)
|
||||
logger.info('[PicGo Server] files uploaded: ' + filePaths.join(', '))
|
||||
|
||||
const handler = routers.getHandler(request.url!)
|
||||
handler!({
|
||||
list: filePaths,
|
||||
response
|
||||
})
|
||||
} catch (err: any) {
|
||||
logger.error('[PicGo Server] process upload files error', err)
|
||||
handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: 'Failed to process uploaded files'
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查请求是否为文件上传
|
||||
*/
|
||||
public isFileUpload (request: http.IncomingMessage): boolean {
|
||||
return !!(request.headers['content-type'] && request.headers['content-type'].includes('multipart/form-data'))
|
||||
}
|
||||
}
|
||||
|
||||
export default new FormUploader()
|
||||
@@ -0,0 +1,24 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { getFormImageFolderPath } from '@core/datastore/dbChecker'
|
||||
import logger from '@core/picgo/logger'
|
||||
|
||||
export const cleanupFormUploaderFiles = (filePathList?: string[]): void => {
|
||||
const formImageFolderPath = getFormImageFolderPath()
|
||||
if (Array.isArray(filePathList)) {
|
||||
filePathList.forEach(async filePath => {
|
||||
try {
|
||||
// 检查文件路径是否在 formImageFolderPath 目录下
|
||||
const relativePath = path.relative(formImageFolderPath, filePath)
|
||||
const isWithinFolder = !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
|
||||
|
||||
if (isWithinFolder && await fs.pathExists(filePath)) {
|
||||
await fs.remove(filePath)
|
||||
logger.info(`[PicGo] Deleted temp file: ${filePath}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error(`[PicGo] Failed to delete temp file ${filePath}:`, error)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { clipboard, Notification, dialog } from 'electron'
|
||||
import { handleUrlEncode } from '~/universal/utils/common'
|
||||
|
||||
export const handleCopyUrl = (str: string): void => {
|
||||
if (db.get('settings.autoCopy') !== false) {
|
||||
if (db.get('settings.autoCopyUrl') !== false) {
|
||||
clipboard.writeText(str)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ async function initData () {
|
||||
form.uploadNotification = settings.uploadNotification || false
|
||||
form.miniWindowOnTop = settings.miniWindowOnTop || false
|
||||
form.logLevel = initLogLevel(settings.logLevel || [])
|
||||
form.autoCopyUrl = settings.autoCopy === undefined ? true : settings.autoCopy
|
||||
form.autoCopyUrl = settings.autoCopyUrl === undefined ? true : settings.autoCopyUrl
|
||||
form.checkBetaUpdate = settings.checkBetaUpdate === undefined ? true : settings.checkBetaUpdate
|
||||
form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? false : settings.useBuiltinClipboard
|
||||
form.language = settings.language ?? 'zh-CN'
|
||||
|
||||
Vendored
+14
@@ -7,3 +7,17 @@ declare var notificationList: IAppNotification[]
|
||||
declare module 'epipebomb' {
|
||||
export default function epipebomb(stream: NodeJS.Process['stdout'], callback: () => void): void
|
||||
}
|
||||
|
||||
// 扩展原生 IncomingMessage,添加 multer 字段
|
||||
declare module 'http' {
|
||||
interface IncomingMessage {
|
||||
files?: {
|
||||
path: string;
|
||||
originalname: string;
|
||||
mimetype: string;
|
||||
size: number;
|
||||
[key: string]: any;
|
||||
}[];
|
||||
body?: any;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const CLIPBOARD_IMAGE_FOLDER = 'picgo-clipboard-images'
|
||||
export const FORM_IMAGE_FOLDER = 'picgo-form-images'
|
||||
export const RELEASE_URL = 'https://api.github.com/repos/Molunerfinn/PicGo/releases'
|
||||
export const RELEASE_URL_BACKUP = 'https://picgo-release.molunerfinn.com'
|
||||
export const STABLE_RELEASE_URL = 'https://github.com/Molunerfinn/PicGo/releases/latest'
|
||||
|
||||
@@ -2906,6 +2906,13 @@
|
||||
resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
||||
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
|
||||
|
||||
"@types/multer@^1.4.12":
|
||||
version "1.4.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.12.tgz#da67bd0c809f3a63fe097c458c0d4af1fea50ab7"
|
||||
integrity sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==
|
||||
dependencies:
|
||||
"@types/express" "*"
|
||||
|
||||
"@types/node@*", "@types/node@^14.6.2", "@types/node@^16.10.2":
|
||||
version "16.11.18"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-16.11.18.tgz#39ed7c52943b0cee6d7299b717707bd51b1f90b9"
|
||||
@@ -3950,6 +3957,11 @@ app-builder-lib@23.3.3:
|
||||
tar "^6.1.11"
|
||||
temp-file "^3.4.0"
|
||||
|
||||
append-field@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
|
||||
integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==
|
||||
|
||||
arch@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
|
||||
@@ -4472,6 +4484,13 @@ builtins@^5.0.1:
|
||||
dependencies:
|
||||
semver "^7.0.0"
|
||||
|
||||
busboy@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
|
||||
dependencies:
|
||||
streamsearch "^1.1.0"
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
@@ -5019,7 +5038,7 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
concat-stream@^1.6.2:
|
||||
concat-stream@^1.5.2, concat-stream@^1.6.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
|
||||
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
|
||||
@@ -9344,6 +9363,19 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1:
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
multer@^1.4.5-lts.1:
|
||||
version "1.4.5-lts.1"
|
||||
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.5-lts.1.tgz#803e24ad1984f58edffbc79f56e305aec5cfd1ac"
|
||||
integrity sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==
|
||||
dependencies:
|
||||
append-field "^1.0.0"
|
||||
busboy "^1.0.0"
|
||||
concat-stream "^1.5.2"
|
||||
mkdirp "^0.5.4"
|
||||
object-assign "^4.1.1"
|
||||
type-is "^1.6.4"
|
||||
xtend "^4.0.0"
|
||||
|
||||
multicast-dns@^7.2.5:
|
||||
version "7.2.5"
|
||||
resolved "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced"
|
||||
@@ -9539,7 +9571,7 @@ number-is-nan@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0:
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
@@ -9986,10 +10018,10 @@ pend@~1.2.0:
|
||||
resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||
|
||||
picgo@^1.5.8:
|
||||
version "1.5.8"
|
||||
resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.5.8.tgz#5c66a88219aec4e139886f242a49cedc2b7f1c48"
|
||||
integrity sha512-z3ATQJeELMkn+g3Cyf3l/AEvSmrDmrFF2bn8ZY/69kEPhixx9NTEpsfRvMeIlLPQM1BTu+ZZ25XWLnPYu5hliA==
|
||||
picgo@^1.5.9:
|
||||
version "1.5.9"
|
||||
resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.5.9.tgz#2ff46958c3f53203d7d13b870a1ae4be90aaa3e3"
|
||||
integrity sha512-6jO53RdHBP9tl9w6fwm+WtlU6qeYMsZAH9HsXZDkyXqQYMRdQ7t2K4BXZo3DQJ76ebYD40fDHAaIW92k7m2A0w==
|
||||
dependencies:
|
||||
"@picgo/i18n" "^1.0.0"
|
||||
"@picgo/store" "^2.0.2"
|
||||
@@ -11580,6 +11612,11 @@ stream-browserify@3.0.0:
|
||||
inherits "~2.0.4"
|
||||
readable-stream "^3.5.0"
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
|
||||
strict-uri-encode@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||
@@ -12210,7 +12247,7 @@ type-fest@^0.8.1:
|
||||
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||
|
||||
type-is@~1.6.18:
|
||||
type-is@^1.6.4, type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
|
||||
Reference in New Issue
Block a user