From 49d16f051244703b2981a12dc19b247c935b1ed3 Mon Sep 17 00:00:00 2001 From: vibsin9322 Date: Thu, 21 Aug 2025 20:43:34 +0900 Subject: [PATCH] =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 3 +- alternative-git-servers.md | 298 --- api/files.js | 40 - api/index.js | 4 - api/simple.js | 124 -- api/test.js | 21 - backup/supabase/admin-supabase-config.js | 119 -- backup/supabase/clean-storage-setup.sql | 62 - backup/supabase/setup-guide.md | 150 -- backup/supabase/storage-policies.sql | 39 - backup/supabase/supabase-config.js | 309 --- backup/supabase/supabase-schema.sql | 128 -- backup/supabase/temp-public-policy.sql | 16 - cookies.txt | 5 - create-git-repo.sh | 141 -- debug-files.js | 68 - deploy-manual.sh | 46 - enhanced-server.js | 234 -- manual-nas-deployment-guide.md | 328 --- nas-git-connection-test.md | 257 --- package-lock.json | 2499 ++++++++++++++++++++-- package.json | 21 +- pm2-ecosystem.config.js | 25 - pm2-start.sh | 51 - render.yaml | 12 - scripts/init-database.js | 73 - simple.html | 110 - ssh-connect.sh | 12 - styles.css | 2 +- synology-git-diagnostic.md | 203 -- synology-setup.md | 248 --- vercel.json | 33 - 게시판.png | Bin 33458 -> 0 bytes 오류.png | Bin 30735 -> 0 bytes 34 files changed, 2313 insertions(+), 3368 deletions(-) delete mode 100644 alternative-git-servers.md delete mode 100644 api/files.js delete mode 100644 api/index.js delete mode 100644 api/simple.js delete mode 100644 api/test.js delete mode 100644 backup/supabase/admin-supabase-config.js delete mode 100644 backup/supabase/clean-storage-setup.sql delete mode 100644 backup/supabase/setup-guide.md delete mode 100644 backup/supabase/storage-policies.sql delete mode 100644 backup/supabase/supabase-config.js delete mode 100644 backup/supabase/supabase-schema.sql delete mode 100644 backup/supabase/temp-public-policy.sql delete mode 100644 cookies.txt delete mode 100644 create-git-repo.sh delete mode 100644 debug-files.js delete mode 100644 deploy-manual.sh delete mode 100644 enhanced-server.js delete mode 100644 manual-nas-deployment-guide.md delete mode 100644 nas-git-connection-test.md delete mode 100644 pm2-ecosystem.config.js delete mode 100644 pm2-start.sh delete mode 100644 render.yaml delete mode 100644 scripts/init-database.js delete mode 100644 simple.html delete mode 100644 ssh-connect.sh delete mode 100644 synology-git-diagnostic.md delete mode 100644 synology-setup.md delete mode 100644 vercel.json delete mode 100644 게시판.png delete mode 100644 오류.png diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 5125765..6601e89 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -43,7 +43,8 @@ "Bash(ssh:*)", "Bash(scp:*)", "Bash(cat:*)", - "Bash(./deploy-manual.sh)" + "Bash(./deploy-manual.sh)", + "Bash(npm install)" ], "deny": [], "ask": [], diff --git a/alternative-git-servers.md b/alternative-git-servers.md deleted file mode 100644 index 26efc10..0000000 --- a/alternative-git-servers.md +++ /dev/null @@ -1,298 +0,0 @@ -# 시놀로지 NAS 대안 Git 서버 설치 방안 - -## 🚀 개요 - -시놀로지 Git Server 패키지가 작동하지 않을 때 사용할 수 있는 대안적인 Git 서버 설치 방법들을 제공합니다. - -## 🐳 방법 1: Docker를 이용한 Gitea 설치 (권장) - -### 1.1 장점 -- 웹 기반 Git 관리 인터페이스 -- GitHub와 유사한 사용자 경험 -- 이슈 관리, 위키, 프로젝트 관리 기능 -- 가벼움 (Go 언어 기반) - -### 1.2 설치 과정 - -#### Docker 설치 확인 -```bash -# DSM > 패키지 센터 > Docker 설치 -# 또는 SSH에서 확인 -docker --version -``` - -#### Gitea 컨테이너 실행 -```bash -# SSH로 NAS 접속 -ssh admin@your-nas-ip - -# Gitea 데이터 디렉토리 생성 -sudo mkdir -p /volume1/docker/gitea - -# Gitea 컨테이너 실행 -docker run -d \ - --name gitea \ - -p 3000:3000 \ - -p 222:22 \ - -v /volume1/docker/gitea:/data \ - -e USER_UID=1000 \ - -e USER_GID=1000 \ - gitea/gitea:latest -``` - -#### 웹 설정 -1. 브라우저에서 `http://your-nas-ip:3000` 접속 -2. 초기 설정 완료: - - 데이터베이스: SQLite3 (기본) - - 관리자 계정 생성 - - 저장소 루트 경로: `/data/git/repositories` - -### 1.3 저장소 생성 및 연결 -```bash -# 웹 인터페이스에서 새 저장소 'jaryo-file-manager' 생성 -# 로컬에서 연결 -git remote add gitea http://your-nas-ip:3000/username/jaryo-file-manager.git -git push gitea master -``` - -## 📦 방법 2: 순수 Git 서버 설치 - -### 2.1 수동 Git 설치 -```bash -# SSH로 NAS 접속 -ssh admin@your-nas-ip - -# 패키지 관리자 업데이트 -sudo apt update - -# Git 설치 -sudo apt install git git-daemon-run - -# 버전 확인 -git --version -``` - -### 2.2 Git 서비스 설정 -```bash -# Git 사용자 생성 -sudo adduser git -sudo su git -cd /home/git - -# SSH 키 디렉토리 생성 -mkdir .ssh && chmod 700 .ssh -touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys - -# Git 저장소 디렉토리 생성 -mkdir /home/git/repositories -``` - -### 2.3 systemd 서비스 설정 -```bash -# Git daemon 서비스 파일 생성 -sudo tee /etc/systemd/system/git-daemon.service << EOF -[Unit] -Description=Git Daemon -After=network.target - -[Service] -ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/home/git/repositories --export-all --verbose --enable=receive-pack -Restart=always -User=git -Group=git -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - -# 서비스 활성화 -sudo systemctl enable git-daemon -sudo systemctl start git-daemon -sudo systemctl status git-daemon -``` - -### 2.4 저장소 생성 -```bash -# git 사용자로 전환 -sudo su git -cd /home/git/repositories - -# bare 저장소 생성 -git init --bare jaryo-file-manager.git -``` - -## 🌐 방법 3: GitLab CE Docker 설치 - -### 3.1 특징 -- 기업급 Git 관리 플랫폼 -- CI/CD 파이프라인 지원 -- 이슈 추적, 위키, 프로젝트 관리 -- 더 많은 리소스 필요 - -### 3.2 설치 과정 -```bash -# GitLab 데이터 디렉토리 생성 -sudo mkdir -p /volume1/docker/gitlab/{config,logs,data} - -# GitLab 컨테이너 실행 (최소 4GB RAM 권장) -docker run -d \ - --hostname your-nas-ip \ - --name gitlab \ - -p 8080:80 \ - -p 8443:443 \ - -p 8022:22 \ - -v /volume1/docker/gitlab/config:/etc/gitlab \ - -v /volume1/docker/gitlab/logs:/var/log/gitlab \ - -v /volume1/docker/gitlab/data:/var/opt/gitlab \ - gitlab/gitlab-ce:latest -``` - -### 3.3 초기 설정 -```bash -# 컨테이너 시작 대기 (2-3분) -docker logs -f gitlab - -# 브라우저에서 http://your-nas-ip:8080 접속 -# 초기 root 비밀번호 확인 -docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password -``` - -## 🔧 방법 4: Forgejo (Gitea Fork) 설치 - -### 4.1 특징 -- Gitea의 커뮤니티 중심 포크 -- 더 빠른 개발 주기 -- 오픈소스 중심 - -### 4.2 설치 과정 -```bash -# Forgejo 데이터 디렉토리 생성 -sudo mkdir -p /volume1/docker/forgejo - -# Forgejo 컨테이너 실행 -docker run -d \ - --name forgejo \ - -p 3000:3000 \ - -p 222:22 \ - -v /volume1/docker/forgejo:/data \ - -e USER_UID=1000 \ - -e USER_GID=1000 \ - codeberg.org/forgejo/forgejo:latest -``` - -## 📱 방법 5: 간단한 HTTP Git 서버 - -### 5.1 Python 기반 간단 서버 -```bash -# Python Git HTTP 서버 스크립트 생성 -cat > /volume1/web/git-http-server.py << 'EOF' -#!/usr/bin/env python3 -import os -import http.server -import socketserver -from subprocess import Popen, PIPE - -class GitHTTPHandler(http.server.SimpleHTTPRequestHandler): - def do_GET(self): - if self.path.endswith('.git/info/refs'): - # Git 정보 요청 처리 - self.send_response(200) - self.send_header('Content-type', 'text/plain') - self.end_headers() - - repo_path = self.path.split('/')[1] - git_dir = f'/volume1/git/{repo_path}' - - if os.path.exists(git_dir): - proc = Popen(['git', 'upload-pack', '--advertise-refs', git_dir], - stdout=PIPE, stderr=PIPE) - output, _ = proc.communicate() - self.wfile.write(output) - else: - self.wfile.write(b'Repository not found') - else: - super().do_GET() - -PORT = 8000 -with socketserver.TCPServer(("", PORT), GitHTTPHandler) as httpd: - print(f"Git HTTP Server running on port {PORT}") - httpd.serve_forever() -EOF - -# 실행 권한 부여 -chmod +x /volume1/web/git-http-server.py - -# 서버 실행 -python3 /volume1/web/git-http-server.py -``` - -## 🔀 방법별 비교표 - -| 방법 | 난이도 | 리소스 사용량 | 기능 | 웹 UI | 권장도 | -|------|--------|---------------|------|-------|--------| -| Gitea | 쉬움 | 낮음 | 풍부 | ✅ | ⭐⭐⭐⭐⭐ | -| 순수 Git | 보통 | 매우 낮음 | 기본 | ❌ | ⭐⭐⭐ | -| GitLab CE | 어려움 | 높음 | 매우 풍부 | ✅ | ⭐⭐⭐⭐ | -| Forgejo | 쉬움 | 낮음 | 풍부 | ✅ | ⭐⭐⭐⭐ | -| Python 서버 | 보통 | 낮음 | 제한적 | ❌ | ⭐⭐ | - -## 🚀 빠른 시작 가이드 (Gitea 권장) - -### 1단계: Docker 설치 확인 -```bash -# DSM 패키지 센터에서 Docker 설치 -``` - -### 2단계: Gitea 설치 -```bash -ssh admin@your-nas-ip -sudo mkdir -p /volume1/docker/gitea -docker run -d --name gitea -p 3000:3000 -p 222:22 -v /volume1/docker/gitea:/data gitea/gitea:latest -``` - -### 3단계: 웹 설정 -- `http://your-nas-ip:3000` 접속 -- 초기 설정 완료 -- 관리자 계정 생성 - -### 4단계: 저장소 생성 및 연결 -```bash -# 웹에서 새 저장소 생성 -# 로컬에서 연결 -cd /c/Users/COMTREE/claude_code/jaryo -git remote add gitea http://your-nas-ip:3000/admin/jaryo-file-manager.git -git push gitea master -``` - -## 🛠️ 문제 해결 - -### Docker 관련 문제 -```bash -# 컨테이너 상태 확인 -docker ps -a - -# 로그 확인 -docker logs gitea - -# 컨테이너 재시작 -docker restart gitea -``` - -### 포트 충돌 문제 -```bash -# 사용 중인 포트 확인 -sudo netstat -tulpn | grep :3000 - -# 다른 포트 사용 -docker run -d --name gitea -p 3001:3000 -p 223:22 -v /volume1/docker/gitea:/data gitea/gitea:latest -``` - -### 권한 문제 -```bash -# 데이터 디렉토리 권한 수정 -sudo chown -R 1000:1000 /volume1/docker/gitea -``` - -이 가이드를 통해 시놀로지 NAS Git Server 패키지 문제를 우회하여 안정적인 Git 서버를 구축할 수 있습니다. \ No newline at end of file diff --git a/api/files.js b/api/files.js deleted file mode 100644 index ae4fc90..0000000 --- a/api/files.js +++ /dev/null @@ -1,40 +0,0 @@ -// 파일 API -module.exports = (req, res) => { - // CORS 헤더 설정 - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); - - if (req.method === 'OPTIONS') { - res.status(200).end(); - return; - } - - // 샘플 파일 데이터 - const files = [ - { - id: 1, - title: '샘플 문서', - description: '데모용 파일입니다', - category: '문서', - tags: ['샘플', '테스트'], - created_at: new Date().toISOString(), - file_url: '#' - }, - { - id: 2, - title: '이미지 파일', - description: '예시 이미지', - category: '이미지', - tags: ['샘플'], - created_at: new Date().toISOString(), - file_url: '#' - } - ]; - - res.status(200).json({ - success: true, - data: files, - message: '파일 목록을 성공적으로 불러왔습니다.' - }); -}; \ No newline at end of file diff --git a/api/index.js b/api/index.js deleted file mode 100644 index 3a025de..0000000 --- a/api/index.js +++ /dev/null @@ -1,4 +0,0 @@ -const app = require('../server'); - -// Vercel 서버리스 함수로 export -module.exports = app; diff --git a/api/simple.js b/api/simple.js deleted file mode 100644 index a857985..0000000 --- a/api/simple.js +++ /dev/null @@ -1,124 +0,0 @@ -// Vercel Serverless 함수 핸들러 -module.exports = function handler(req, res) { - // CORS 헤더 설정 - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); - - if (req.method === 'OPTIONS') { - res.status(200).end(); - return; - } - - const { url, method } = req; - - // 헬스 체크 - if (url === '/health' || url === '/api/health') { - res.json({ - success: true, - message: 'Jaryo File Manager is running', - timestamp: new Date().toISOString(), - environment: process.env.NODE_ENV || 'production', - path: url - }); - return; - } - - // 루트 경로 - if (url === '/' || url === '/api') { - res.setHeader('Content-Type', 'text/html'); - res.end(` - - - - - - Jaryo File Manager - - - -
-

🚀 Jaryo File Manager

-
-

✅ 배포 성공!

-

Vercel Serverless에서 성공적으로 실행 중입니다.

-

시간: ${new Date().toLocaleString('ko-KR')}

-
-
-

🔧 API 엔드포인트

-

헬스 체크

-

파일 목록 API

-

공개 파일 API

-
-
-

📱 페이지

-

메인 페이지

-

관리자 페이지

-
-
- - - `); - return; - } - - // API 라우트들 - if (url === '/api/files' || url === '/api/files/public') { - res.json({ - success: true, - data: [ - { - id: 1, - title: '샘플 문서', - description: '데모용 파일입니다', - category: '문서', - tags: ['샘플', '테스트'], - created_at: new Date().toISOString(), - file_url: '#' - }, - { - id: 2, - title: '이미지 파일', - description: '예시 이미지', - category: '이미지', - tags: ['샘플'], - created_at: new Date().toISOString(), - file_url: '#' - } - ], - message: url.includes('public') ? '공개 파일 목록' : '파일 목록 API (데모 모드)' - }); - return; - } - - if (url === '/api/categories') { - res.json({ - success: true, - data: [ - { id: 1, name: '문서', description: '문서 파일' }, - { id: 2, name: '이미지', description: '이미지 파일' }, - { id: 3, name: '동영상', description: '동영상 파일' }, - { id: 4, name: '프레젠테이션', description: '프레젠테이션 파일' }, - { id: 5, name: '기타', description: '기타 파일' } - ], - message: '카테고리 목록' - }); - return; - } - - // 404 핸들러 - res.status(404).json({ - success: false, - error: '요청한 리소스를 찾을 수 없습니다.', - path: url, - method: method - }); -} diff --git a/api/test.js b/api/test.js deleted file mode 100644 index bcca53f..0000000 --- a/api/test.js +++ /dev/null @@ -1,21 +0,0 @@ -// 테스트용 간단한 API -module.exports = (req, res) => { - // CORS 헤더 설정 - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); - - if (req.method === 'OPTIONS') { - res.status(200).end(); - return; - } - - // 간단한 응답 - res.status(200).json({ - success: true, - message: 'API가 정상 작동합니다!', - timestamp: new Date().toISOString(), - url: req.url, - method: req.method - }); -}; \ No newline at end of file diff --git a/backup/supabase/admin-supabase-config.js b/backup/supabase/admin-supabase-config.js deleted file mode 100644 index 1dd95ee..0000000 --- a/backup/supabase/admin-supabase-config.js +++ /dev/null @@ -1,119 +0,0 @@ -// Supabase configuration (오프라인 모드) -// ⚠️ 오프라인 모드로 강제 설정됨 -const SUPABASE_CONFIG = { - url: 'https://kncudtzthmjegowbgnto.supabase.co', - anonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImtuY3VkdHp0aG1qZWdvd2JnbnRvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTU1Njc5OTksImV4cCI6MjA3MTE0Mzk5OX0.NlJN2vdgM96RvyVJE6ILQeDVUOU9X2F9vUn-jr_xlKc' -}; - -// Supabase 클라이언트 초기화 (강제 비활성화) -let supabase = null; - -// 설정이 유효한지 확인 -function isSupabaseConfigured() { - return false; // 강제로 false 반환 -} - -// Supabase 클라이언트 초기화 함수 (오프라인 모드 강제) -function initializeSupabase() { - console.log('⚠️ 오프라인 모드로 강제 설정되었습니다.'); - return false; -} - -// 인증 상태 변경 리스너 (오프라인 모드용 - 빈 함수) -function setupAuthListener(callback) { - // 오프라인 모드에서는 아무것도 하지 않음 - return; -} - -// 현재 사용자 가져오기 (오프라인 모드용 - null 반환) -async function getCurrentUser() { - return null; -} - -// 로그인 (오프라인 모드용 - 빈 함수) -async function signIn(email, password) { - throw new Error('오프라인 모드에서는 로그인할 수 없습니다.'); -} - -// 회원가입 (오프라인 모드용 - 빈 함수) -async function signUp(email, password, metadata = {}) { - throw new Error('오프라인 모드에서는 회원가입할 수 없습니다.'); -} - -// 로그아웃 (오프라인 모드용 - 빈 함수) -async function signOut() { - throw new Error('오프라인 모드에서는 로그아웃할 수 없습니다.'); -} - -// 데이터베이스 헬퍼 함수들 (오프라인 모드용) -const SupabaseHelper = { - // 파일 목록 가져오기 (오프라인 모드용) - async getFiles(userId) { - console.log('🔍 SupabaseHelper.getFiles 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase 데이터베이스를 사용할 수 없습니다.'); - }, - - // 파일 추가 (오프라인 모드용) - async addFile(fileData, userId) { - console.log('🔍 SupabaseHelper.addFile 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase 데이터베이스를 사용할 수 없습니다.'); - }, - - // 파일 수정 (오프라인 모드용) - async updateFile(id, updates, userId) { - console.log('🔍 SupabaseHelper.updateFile 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase 데이터베이스를 사용할 수 없습니다.'); - }, - - // 파일 삭제 (오프라인 모드용) - async deleteFile(id, userId) { - console.log('🔍 SupabaseHelper.deleteFile 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase 데이터베이스를 사용할 수 없습니다.'); - }, - - // 실시간 구독 설정 (오프라인 모드용) - subscribeToFiles(userId, callback) { - console.log('🔍 SupabaseHelper.subscribeToFiles 호출됨 (오프라인 모드)'); - return null; - }, - - // 파일 업로드 (오프라인 모드용) - async uploadFile(file, filePath) { - console.log('🔍 SupabaseHelper.uploadFile 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase Storage를 사용할 수 없습니다.'); - }, - - // 파일 다운로드 URL 가져오기 (오프라인 모드용) - async getFileUrl(filePath) { - console.log('🔍 SupabaseHelper.getFileUrl 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase Storage를 사용할 수 없습니다.'); - }, - - // 파일 삭제 (Storage) (오프라인 모드용) - async deleteStorageFile(filePath) { - console.log('🔍 SupabaseHelper.deleteStorageFile 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase Storage를 사용할 수 없습니다.'); - }, - - // 첨부파일 정보 추가 (오프라인 모드용) - async addFileAttachment(fileId, attachmentData) { - console.log('🔍 SupabaseHelper.addFileAttachment 호출됨 (오프라인 모드)'); - throw new Error('오프라인 모드에서는 Supabase 데이터베이스를 사용할 수 없습니다.'); - }, - - // Storage 버킷 확인 및 생성 (오프라인 모드용) - async checkOrCreateBucket() { - console.log('🔍 SupabaseHelper.checkOrCreateBucket 호출됨 (오프라인 모드)'); - return false; - } -}; - -// 전역으로 내보내기 -window.SupabaseHelper = SupabaseHelper; -window.initializeSupabase = initializeSupabase; -window.isSupabaseConfigured = isSupabaseConfigured; -window.setupAuthListener = setupAuthListener; -window.getCurrentUser = getCurrentUser; -window.signIn = signIn; -window.signUp = signUp; -window.signOut = signOut; \ No newline at end of file diff --git a/backup/supabase/clean-storage-setup.sql b/backup/supabase/clean-storage-setup.sql deleted file mode 100644 index 01dbb5e..0000000 --- a/backup/supabase/clean-storage-setup.sql +++ /dev/null @@ -1,62 +0,0 @@ --- 완전 초기화 후 Storage 정책 재설정 - --- 1단계: 모든 기존 Storage 정책 삭제 -DROP POLICY IF EXISTS "Users can upload to own folder" ON storage.objects; -DROP POLICY IF EXISTS "Users can view own files" ON storage.objects; -DROP POLICY IF EXISTS "Users can update own files" ON storage.objects; -DROP POLICY IF EXISTS "Users can delete own files" ON storage.objects; -DROP POLICY IF EXISTS "Public upload for testing" ON storage.objects; -DROP POLICY IF EXISTS "Public read for testing" ON storage.objects; - --- 혹시 다른 이름으로 생성된 정책들도 삭제 -DROP POLICY IF EXISTS "Enable insert for authenticated users only" ON storage.objects; -DROP POLICY IF EXISTS "Enable select for authenticated users only" ON storage.objects; -DROP POLICY IF EXISTS "Enable update for authenticated users only" ON storage.objects; -DROP POLICY IF EXISTS "Enable delete for authenticated users only" ON storage.objects; - --- 2단계: RLS 활성화 확인 (보통 이미 활성화되어 있음) -ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY; - --- 3단계: 새 정책 생성 --- 업로드 정책 -CREATE POLICY "Users can upload to own folder" -ON storage.objects -FOR INSERT -WITH CHECK ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 조회 정책 -CREATE POLICY "Users can view own files" -ON storage.objects -FOR SELECT -USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 업데이트 정책 -CREATE POLICY "Users can update own files" -ON storage.objects -FOR UPDATE -USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 삭제 정책 -CREATE POLICY "Users can delete own files" -ON storage.objects -FOR DELETE -USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 4단계: 정책 생성 확인 -SELECT - 'Storage policies created successfully!' as message, - COUNT(*) as policy_count -FROM pg_policies -WHERE schemaname = 'storage' AND tablename = 'objects'; \ No newline at end of file diff --git a/backup/supabase/setup-guide.md b/backup/supabase/setup-guide.md deleted file mode 100644 index f5f9ec7..0000000 --- a/backup/supabase/setup-guide.md +++ /dev/null @@ -1,150 +0,0 @@ -# Supabase 설정 가이드 - -이 문서는 자료실 시스템을 Supabase와 연동하기 위한 설정 가이드입니다. - -## 1. Supabase 프로젝트 생성 - -1. [Supabase](https://supabase.com)에 접속하여 계정을 생성합니다. -2. 새 프로젝트를 생성합니다. -3. 프로젝트 이름과 비밀번호를 설정합니다. -4. 리전은 `ap-northeast-1` (Asia Pacific - Tokyo)를 선택하는 것을 권장합니다. - -## 2. 데이터베이스 스키마 설정 - -1. Supabase 대시보드에서 **SQL Editor**로 이동합니다. -2. `supabase-schema.sql` 파일의 내용을 복사하여 실행합니다. -3. 스키마가 성공적으로 생성되었는지 **Table Editor**에서 확인합니다. - -### 생성되는 테이블 -- `files`: 파일 메타데이터 저장 -- `file_attachments`: 첨부파일 정보 저장 - -## 3. Storage 버킷 설정 - -1. Supabase 대시보드에서 **Storage**로 이동합니다. -2. **New bucket** 버튼을 클릭합니다. -3. 버킷 이름을 `files`로 설정합니다. -4. **Public bucket** 체크박스는 해제합니다 (보안상 권장). -5. 버킷을 생성합니다. - -### Storage 정책 설정 -버킷 생성 후 **Policies** 탭에서 다음 정책들을 추가합니다: - -#### SELECT 정책 (파일 조회) -```sql -CREATE POLICY "Users can view their own files" ON storage.objects -FOR SELECT USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); -``` - -#### INSERT 정책 (파일 업로드) -```sql -CREATE POLICY "Users can upload their own files" ON storage.objects -FOR INSERT WITH CHECK ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); -``` - -#### DELETE 정책 (파일 삭제) -```sql -CREATE POLICY "Users can delete their own files" ON storage.objects -FOR DELETE USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); -``` - -## 4. API 키 및 URL 설정 - -1. Supabase 대시보드에서 **Settings** > **API**로 이동합니다. -2. 다음 정보를 확인합니다: - - **Project URL**: `https://your-project-id.supabase.co` - - **Project API keys** > **anon public**: `eyJ...` - -3. `supabase-config.js` 파일을 수정합니다: -```javascript -const SUPABASE_CONFIG = { - url: 'https://your-project-id.supabase.co', // 실제 Project URL로 교체 - anonKey: 'eyJ...' // 실제 anon public key로 교체 -}; -``` - -## 5. 인증 설정 (선택사항) - -### 이메일 인증 비활성화 (개발용) -개발 환경에서 빠른 테스트를 위해 이메일 인증을 비활성화할 수 있습니다: - -1. **Authentication** > **Settings**로 이동 -2. **Enable email confirmations** 체크박스 해제 -3. **Save** 클릭 - -⚠️ **주의**: 프로덕션 환경에서는 이메일 인증을 활성화하는 것을 강력히 권장합니다. - -### 이메일 템플릿 설정 (프로덕션용) -1. **Authentication** > **Email Templates**에서 이메일 템플릿을 커스터마이징할 수 있습니다. -2. 회사 브랜드에 맞게 이메일 디자인을 수정하세요. - -## 6. 보안 설정 - -### Row Level Security (RLS) -스키마 실행 시 자동으로 설정되지만, 다음 사항을 확인하세요: - -1. **Authentication** > **Policies**에서 정책이 올바르게 설정되었는지 확인 -2. 각 테이블에 사용자별 접근 제한이 적용되어 있는지 확인 - -### 환경변수 보안 -프로덕션 환경에서는 API 키를 환경변수로 관리하세요: - -```javascript -const SUPABASE_CONFIG = { - url: process.env.SUPABASE_URL || 'YOUR_SUPABASE_PROJECT_URL', - anonKey: process.env.SUPABASE_ANON_KEY || 'YOUR_SUPABASE_ANON_KEY' -}; -``` - -## 7. 테스트 - -설정 완료 후 다음 기능들을 테스트하세요: - -1. **회원가입/로그인** - 새 계정 생성 및 로그인 -2. **파일 추가** - 새 자료 추가 (첨부파일 포함) -3. **파일 수정** - 기존 자료 수정 -4. **파일 삭제** - 자료 삭제 (첨부파일도 함께 삭제되는지 확인) -5. **파일 다운로드** - 첨부파일 다운로드 -6. **실시간 동기화** - 다른 브라우저에서 같은 계정으로 로그인하여 실시간 동기화 확인 - -## 8. 문제 해결 - -### 연결 오류 -- Supabase URL과 API 키가 올바른지 확인 -- 브라우저 콘솔에서 오류 메시지 확인 -- CORS 설정 확인 (대부분 자동으로 설정됨) - -### 권한 오류 -- RLS 정책이 올바르게 설정되었는지 확인 -- 사용자가 올바르게 인증되었는지 확인 - -### 파일 업로드 오류 -- Storage 버킷이 올바르게 생성되었는지 확인 -- Storage 정책이 올바르게 설정되었는지 확인 -- 파일 크기 제한 확인 (Supabase 기본값: 50MB) - -## 9. 추가 개선사항 - -### 성능 최적화 -- 대용량 파일 처리를 위한 chunk 업로드 구현 -- 이미지 최적화 및 썸네일 생성 -- CDN 연동 고려 - -### 기능 확장 -- 파일 공유 기능 -- 버전 관리 -- 협업 기능 -- 백업 및 복원 기능 - ---- - -설정 중 문제가 발생하면 [Supabase 공식 문서](https://supabase.com/docs)를 참고하거나 이슈를 등록해주세요. \ No newline at end of file diff --git a/backup/supabase/storage-policies.sql b/backup/supabase/storage-policies.sql deleted file mode 100644 index 95ec94c..0000000 --- a/backup/supabase/storage-policies.sql +++ /dev/null @@ -1,39 +0,0 @@ --- Storage 전용 정책 (Supabase Dashboard → Storage → Policies에서 실행) - --- 1. 파일 업로드 정책 -CREATE POLICY "Users can upload to own folder" -ON storage.objects -FOR INSERT -WITH CHECK ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 2. 파일 조회 정책 -CREATE POLICY "Users can view own files" -ON storage.objects -FOR SELECT -USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 3. 파일 업데이트 정책 -CREATE POLICY "Users can update own files" -ON storage.objects -FOR UPDATE -USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 4. 파일 삭제 정책 -CREATE POLICY "Users can delete own files" -ON storage.objects -FOR DELETE -USING ( - bucket_id = 'files' AND - auth.uid()::text = (storage.foldername(name))[1] -); - --- 참고: storage.foldername(name)[1]은 'user_id/filename.txt'에서 'user_id' 부분을 추출합니다. \ No newline at end of file diff --git a/backup/supabase/supabase-config.js b/backup/supabase/supabase-config.js deleted file mode 100644 index 21061ab..0000000 --- a/backup/supabase/supabase-config.js +++ /dev/null @@ -1,309 +0,0 @@ -// Supabase configuration -// ⚠️ 실제 사용 시에는 이 값들을 환경변수나 설정 파일로 관리하세요 -const SUPABASE_CONFIG = { - // 실제 Supabase 프로젝트 URL로 교체하세요 - url: 'https://kncudtzthmjegowbgnto.supabase.co', - // 실제 Supabase anon key로 교체하세요 - anonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImtuY3VkdHp0aG1qZWdvd2JnbnRvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTU1Njc5OTksImV4cCI6MjA3MTE0Mzk5OX0.NlJN2vdgM96RvyVJE6ILQeDVUOU9X2F9vUn-jr_xlKc' -}; - -// Supabase 클라이언트 초기화 -let supabase; - -// 설정이 유효한지 확인 -function isSupabaseConfigured() { - return SUPABASE_CONFIG.url !== 'YOUR_SUPABASE_PROJECT_URL' && - SUPABASE_CONFIG.anonKey !== 'YOUR_SUPABASE_ANON_KEY'; -} - -// Supabase 클라이언트 초기화 함수 -function initializeSupabase() { - if (!isSupabaseConfigured()) { - console.warn('⚠️ Supabase가 설정되지 않았습니다. localStorage를 사용합니다.'); - return false; - } - - try { - supabase = window.supabase.createClient(SUPABASE_CONFIG.url, SUPABASE_CONFIG.anonKey); - console.log('✅ Supabase 클라이언트가 초기화되었습니다.'); - return true; - } catch (error) { - console.error('❌ Supabase 초기화 오류:', error); - return false; - } -} - -// 인증 상태 변경 리스너 -function setupAuthListener(callback) { - if (!supabase) return; - - supabase.auth.onAuthStateChange((event, session) => { - console.log('Auth state changed:', event, session); - if (callback) callback(event, session); - }); -} - -// 현재 사용자 가져오기 -async function getCurrentUser() { - if (!supabase) return null; - - try { - const { data: { user }, error } = await supabase.auth.getUser(); - if (error) throw error; - return user; - } catch (error) { - console.error('사용자 정보 가져오기 오류:', error); - return null; - } -} - -// 로그인 -async function signIn(email, password) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { data, error } = await supabase.auth.signInWithPassword({ - email, - password - }); - - if (error) throw error; - return data; -} - -// 회원가입 -async function signUp(email, password, metadata = {}) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { data, error } = await supabase.auth.signUp({ - email, - password, - options: { - data: metadata - } - }); - - if (error) throw error; - return data; -} - -// 로그아웃 -async function signOut() { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { error } = await supabase.auth.signOut(); - if (error) throw error; -} - -// 데이터베이스 헬퍼 함수들 -const SupabaseHelper = { - // 파일 목록 가져오기 - async getFiles(userId) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - let query = supabase - .from('files') - .select(` - *, - file_attachments (*) - `); - - // 공개 파일 요청이 아닌 경우에만 사용자 ID로 필터링 - if (userId !== 'public') { - query = query.eq('user_id', userId); - } - - const { data, error } = await query.order('created_at', { ascending: false }); - - if (error) throw error; - return data; - }, - - // 파일 추가 - async addFile(fileData, userId) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - // 데이터베이스 스키마에 맞는 필드만 추출 - const dbFileData = { - title: fileData.title, - description: fileData.description || '', - category: fileData.category, - tags: fileData.tags || [], - user_id: userId - // created_at, updated_at은 데이터베이스에서 자동 생성 - }; - - const { data, error } = await supabase - .from('files') - .insert([dbFileData]) - .select() - .single(); - - if (error) throw error; - return data; - }, - - // 파일 수정 - async updateFile(id, updates, userId) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - // 데이터베이스 스키마에 맞는 필드만 추출 - const dbUpdates = { - title: updates.title, - description: updates.description, - category: updates.category, - tags: updates.tags || [] - // updated_at은 트리거에 의해 자동 업데이트됨 - }; - - const { data, error } = await supabase - .from('files') - .update(dbUpdates) - .eq('id', id) - .eq('user_id', userId) - .select() - .single(); - - if (error) throw error; - return data; - }, - - // 파일 삭제 - async deleteFile(id, userId) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { error } = await supabase - .from('files') - .delete() - .eq('id', id) - .eq('user_id', userId); - - if (error) throw error; - }, - - // 실시간 구독 설정 - subscribeToFiles(userId, callback) { - if (!supabase) return null; - - return supabase - .channel('files') - .on('postgres_changes', { - event: '*', - schema: 'public', - table: 'files', - filter: `user_id=eq.${userId}` - }, callback) - .subscribe(); - }, - - // 파일 업로드 (Storage) - async uploadFile(file, filePath) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { data, error } = await supabase.storage - .from('files') - .upload(filePath, file); - - if (error) throw error; - return data; - }, - - // 파일 다운로드 URL 가져오기 - async getFileUrl(filePath) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - try { - // 먼저 파일이 존재하는지 확인 - const { data: fileExists, error: checkError } = await supabase.storage - .from('files') - .list(filePath.substring(0, filePath.lastIndexOf('/')), { - search: filePath.substring(filePath.lastIndexOf('/') + 1) - }); - - if (checkError) { - throw new Error(`Storage 버킷 오류: ${checkError.message}`); - } - - if (!fileExists || fileExists.length === 0) { - throw new Error('파일을 찾을 수 없습니다.'); - } - - // 파일이 존재하면 URL 생성 - const { data } = supabase.storage - .from('files') - .getPublicUrl(filePath); - - return data.publicUrl; - } catch (error) { - console.error('파일 URL 생성 오류:', error); - throw error; - } - }, - - // 파일 삭제 (Storage) - async deleteStorageFile(filePath) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { error } = await supabase.storage - .from('files') - .remove([filePath]); - - if (error) throw error; - }, - - // 첨부파일 정보 추가 - async addFileAttachment(fileId, attachmentData) { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - const { data, error } = await supabase - .from('file_attachments') - .insert([{ - file_id: fileId, - ...attachmentData - }]) - .select() - .single(); - - if (error) throw error; - return data; - }, - - // Storage 버킷 확인 및 생성 - async checkOrCreateBucket() { - if (!supabase) throw new Error('Supabase가 초기화되지 않았습니다.'); - - try { - // 버킷 목록 확인 - const { data: buckets, error: listError } = await supabase.storage.listBuckets(); - - if (listError) { - console.error('버킷 목록 조회 오류:', listError); - return false; - } - - // 'files' 버킷이 있는지 확인 - const filesBucket = buckets.find(bucket => bucket.name === 'files'); - - if (filesBucket) { - console.log('✅ files 버킷이 존재합니다.'); - return true; - } else { - console.warn('⚠️ files 버킷이 존재하지 않습니다.'); - console.log('Supabase Dashboard에서 files 버킷을 생성해주세요.'); - return false; - } - } catch (error) { - console.error('버킷 확인 오류:', error); - return false; - } - } -}; - -// 전역으로 내보내기 -window.SupabaseHelper = SupabaseHelper; -window.initializeSupabase = initializeSupabase; -window.isSupabaseConfigured = isSupabaseConfigured; -window.setupAuthListener = setupAuthListener; -window.getCurrentUser = getCurrentUser; -window.signIn = signIn; -window.signUp = signUp; -window.signOut = signOut; \ No newline at end of file diff --git a/backup/supabase/supabase-schema.sql b/backup/supabase/supabase-schema.sql deleted file mode 100644 index 3d408a8..0000000 --- a/backup/supabase/supabase-schema.sql +++ /dev/null @@ -1,128 +0,0 @@ --- Supabase 데이터베이스 스키마 --- 이 파일을 Supabase SQL 에디터에서 실행하세요 - --- 1. files 테이블 생성 -CREATE TABLE IF NOT EXISTS public.files ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - title TEXT NOT NULL, - description TEXT, - category TEXT NOT NULL, - tags TEXT[] DEFAULT '{}', - user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL, - created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, - updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL -); - --- 2. file_attachments 테이블 생성 (파일 첨부 정보) -CREATE TABLE IF NOT EXISTS public.file_attachments ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - file_id UUID REFERENCES public.files(id) ON DELETE CASCADE NOT NULL, - original_name TEXT NOT NULL, - storage_path TEXT NOT NULL, - file_size INTEGER NOT NULL, - mime_type TEXT NOT NULL, - created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL -); - --- 3. Row Level Security (RLS) 정책 활성화 -ALTER TABLE public.files ENABLE ROW LEVEL SECURITY; -ALTER TABLE public.file_attachments ENABLE ROW LEVEL SECURITY; - --- 4. files 테이블 RLS 정책 --- 사용자는 자신의 파일만 조회할 수 있음 -CREATE POLICY "Users can view their own files" ON public.files - FOR SELECT USING (auth.uid() = user_id); - --- 사용자는 자신의 파일만 생성할 수 있음 -CREATE POLICY "Users can create their own files" ON public.files - FOR INSERT WITH CHECK (auth.uid() = user_id); - --- 사용자는 자신의 파일만 수정할 수 있음 -CREATE POLICY "Users can update their own files" ON public.files - FOR UPDATE USING (auth.uid() = user_id); - --- 사용자는 자신의 파일만 삭제할 수 있음 -CREATE POLICY "Users can delete their own files" ON public.files - FOR DELETE USING (auth.uid() = user_id); - --- 5. file_attachments 테이블 RLS 정책 --- 사용자는 자신의 파일 첨부만 조회할 수 있음 -CREATE POLICY "Users can view their own file attachments" ON public.file_attachments - FOR SELECT USING ( - auth.uid() = ( - SELECT user_id FROM public.files WHERE id = file_attachments.file_id - ) - ); - --- 사용자는 자신의 파일에만 첨부를 생성할 수 있음 -CREATE POLICY "Users can create attachments for their own files" ON public.file_attachments - FOR INSERT WITH CHECK ( - auth.uid() = ( - SELECT user_id FROM public.files WHERE id = file_attachments.file_id - ) - ); - --- 사용자는 자신의 파일 첨부만 삭제할 수 있음 -CREATE POLICY "Users can delete their own file attachments" ON public.file_attachments - FOR DELETE USING ( - auth.uid() = ( - SELECT user_id FROM public.files WHERE id = file_attachments.file_id - ) - ); - --- 6. 인덱스 생성 (성능 최적화) -CREATE INDEX IF NOT EXISTS idx_files_user_id ON public.files(user_id); -CREATE INDEX IF NOT EXISTS idx_files_created_at ON public.files(created_at DESC); -CREATE INDEX IF NOT EXISTS idx_files_category ON public.files(category); -CREATE INDEX IF NOT EXISTS idx_files_tags ON public.files USING GIN(tags); -CREATE INDEX IF NOT EXISTS idx_file_attachments_file_id ON public.file_attachments(file_id); - --- 7. 업데이트 트리거 함수 (updated_at 자동 갱신) -CREATE OR REPLACE FUNCTION update_updated_at_column() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = NOW(); - RETURN NEW; -END; -$$ language 'plpgsql'; - --- 8. updated_at 자동 갱신 트리거 -CREATE TRIGGER update_files_updated_at - BEFORE UPDATE ON public.files - FOR EACH ROW - EXECUTE FUNCTION update_updated_at_column(); - --- 9. Storage 버킷 생성 (실제로는 Supabase Dashboard에서 생성) --- 버킷 이름: 'files' --- 공개 액세스: false (인증된 사용자만 접근) --- --- Storage 정책은 Supabase Dashboard에서 다음과 같이 설정: --- SELECT: 사용자는 자신의 파일만 조회 가능 --- INSERT: 사용자는 자신의 폴더에만 업로드 가능 --- UPDATE: 사용자는 자신의 파일만 수정 가능 --- DELETE: 사용자는 자신의 파일만 삭제 가능 - --- 10. 유용한 뷰 생성 (파일과 첨부 정보 조인) --- 주의: 뷰는 자동으로 기본 테이블의 RLS 정책을 상속받으므로 별도 정책 설정 불필요 -CREATE OR REPLACE VIEW public.files_with_attachments AS -SELECT - f.*, - COALESCE( - JSON_AGG( - JSON_BUILD_OBJECT( - 'id', fa.id, - 'original_name', fa.original_name, - 'storage_path', fa.storage_path, - 'file_size', fa.file_size, - 'mime_type', fa.mime_type, - 'created_at', fa.created_at - ) - ) FILTER (WHERE fa.id IS NOT NULL), - '[]'::json - ) AS attachments -FROM public.files f -LEFT JOIN public.file_attachments fa ON f.id = fa.file_id -GROUP BY f.id, f.title, f.description, f.category, f.tags, f.user_id, f.created_at, f.updated_at; - --- 설정 완료 메시지 -SELECT 'Supabase 스키마 설정이 완료되었습니다!' as message; \ No newline at end of file diff --git a/backup/supabase/temp-public-policy.sql b/backup/supabase/temp-public-policy.sql deleted file mode 100644 index e0813fa..0000000 --- a/backup/supabase/temp-public-policy.sql +++ /dev/null @@ -1,16 +0,0 @@ --- 임시 공개 접근 정책 (테스트용만 사용!) --- 보안상 권장하지 않음 - 운영환경에서는 사용하지 마세요 - --- 모든 사용자가 files 버킷에 업로드 가능 (임시) -CREATE POLICY "Public upload for testing" -ON storage.objects -FOR INSERT -WITH CHECK (bucket_id = 'files'); - --- 모든 사용자가 files 버킷 파일 조회 가능 (임시) -CREATE POLICY "Public read for testing" -ON storage.objects -FOR SELECT -USING (bucket_id = 'files'); - --- 주의: 이 정책들은 테스트 후 반드시 삭제하고 위의 사용자별 정책으로 교체하세요! \ No newline at end of file diff --git a/cookies.txt b/cookies.txt deleted file mode 100644 index c153b4c..0000000 --- a/cookies.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Netscape HTTP Cookie File -# https://curl.se/docs/http-cookies.html -# This file was generated by libcurl! Edit at your own risk. - -#HttpOnly_localhost FALSE / FALSE 1755826306 connect.sid s%3Alkct8oX-9zlTMoD6Mu3BP0RwCz0CFR-X.Mad5GaxzMugYjbnKEOxUq9mnbJkkJY3O79f3q%2BaE%2BJ4 diff --git a/create-git-repo.sh b/create-git-repo.sh deleted file mode 100644 index 0657132..0000000 --- a/create-git-repo.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash - -# 시놀로지 NAS Git 저장소 생성 스크립트 (개선 버전) -# 사용법: ./create-git-repo.sh [repo-name] [git-dir] - -# 기본 설정 -DEFAULT_GIT_DIR="/volume1/git" -DEFAULT_REPO_NAME="jaryo-file-manager" - -# 매개변수 처리 -REPO_NAME="${1:-$DEFAULT_REPO_NAME}" -GIT_DIR="${2:-$DEFAULT_GIT_DIR}" -REPO_PATH="$GIT_DIR/$REPO_NAME.git" - -echo "=== 시놀로지 NAS Git 저장소 생성 ===" -echo "저장소 이름: $REPO_NAME" -echo "Git 디렉토리: $GIT_DIR" -echo "저장소 경로: $REPO_PATH" -echo "==========================================" - -# 권한 확인 -if [ "$EUID" -ne 0 ] && [ "$(whoami)" != "admin" ]; then - echo "⚠️ 경고: 관리자 권한이 필요할 수 있습니다." - echo "sudo 또는 admin 계정으로 실행하세요." -fi - -# Git 설치 확인 -if ! command -v git &> /dev/null; then - echo "❌ Git이 설치되지 않았습니다." - echo "패키지 센터에서 Git Server를 설치하거나 다음 명령어를 실행하세요:" - echo "sudo apt update && sudo apt install git" - exit 1 -fi - -# Git 디렉토리 확인 및 생성 -echo "📁 Git 디렉토리 확인 중..." -if [ ! -d "$GIT_DIR" ]; then - echo "Git 디렉토리가 없습니다. 생성 중..." - mkdir -p "$GIT_DIR" || { - echo "❌ Git 디렉토리 생성 실패. 권한을 확인하세요." - exit 1 - } - - # 권한 설정 - if command -v chown &> /dev/null; then - chown admin:users "$GIT_DIR" 2>/dev/null || echo "⚠️ chown 권한 부족" - fi - chmod 755 "$GIT_DIR" 2>/dev/null || echo "⚠️ chmod 권한 부족" - echo "✅ Git 디렉토리 생성 완료: $GIT_DIR" -else - echo "✅ Git 디렉토리 존재 확인: $GIT_DIR" -fi - -# 기존 저장소 확인 -if [ -d "$REPO_PATH" ]; then - echo "⚠️ 저장소가 이미 존재합니다: $REPO_PATH" - read -p "삭제 후 재생성하시겠습니까? (y/N): " confirm - if [[ $confirm =~ ^[Yy]$ ]]; then - rm -rf "$REPO_PATH" - echo "🗑️ 기존 저장소 삭제 완료" - else - echo "❌ 작업을 취소합니다." - exit 1 - fi -fi - -# 저장소 디렉토리 생성 -echo "📂 저장소 디렉토리 생성 중..." -mkdir -p "$REPO_PATH" || { - echo "❌ 저장소 디렉토리 생성 실패" - exit 1 -} - -# Git 저장소 초기화 -echo "🔧 Git 저장소 초기화 중..." -cd "$REPO_PATH" || exit 1 -git init --bare || { - echo "❌ Git 저장소 초기화 실패" - exit 1 -} - -# 권한 설정 -echo "🔐 권한 설정 중..." -if command -v chown &> /dev/null; then - chown -R admin:users "$REPO_PATH" 2>/dev/null || echo "⚠️ chown 권한 부족" -fi -chmod -R 755 "$REPO_PATH" 2>/dev/null || echo "⚠️ chmod 권한 부족" - -# Git hooks 설정 (선택사항) -echo "🪝 Git hooks 설정 중..." -cat > "$REPO_PATH/hooks/post-receive" << 'EOF' -#!/bin/bash -# 자동 배포 hook (선택사항) -echo "푸시 완료: $(date)" -echo "저장소: $PWD" -EOF -chmod +x "$REPO_PATH/hooks/post-receive" 2>/dev/null - -# 저장소 설명 파일 생성 -echo "📄 저장소 설명 파일 생성 중..." -cat > "$REPO_PATH/description" << EOF -Jaryo File Manager - 시놀로지 NAS 자료실 파일 관리 시스템 -EOF - -# Git 서비스 확인 및 시작 -echo "🔄 Git 서비스 상태 확인 중..." -NAS_IP=$(hostname -I | awk '{print $1}' | tr -d ' ') - -# 다양한 방법으로 IP 확인 -if [ -z "$NAS_IP" ]; then - NAS_IP=$(ip route get 1 | awk '{print $7; exit}' 2>/dev/null) -fi -if [ -z "$NAS_IP" ]; then - NAS_IP="your-nas-ip" -fi - -echo "✅ Git 저장소 생성 완료!" -echo "==========================================" -echo "📋 저장소 정보:" -echo " - 이름: $REPO_NAME" -echo " - 경로: $REPO_PATH" -echo " - 설명: 자료실 파일 관리 시스템" -echo "" -echo "🌐 연결 URL:" -echo " SSH: ssh://admin@$NAS_IP$REPO_PATH" -echo " HTTP: http://$NAS_IP:3000/git/$REPO_NAME.git" -echo "" -echo "🔗 로컬에서 연결하는 방법:" -echo " git remote add nas ssh://admin@$NAS_IP$REPO_PATH" -echo " git push nas master" -echo "" -echo "📝 다음 단계:" -echo " 1. 로컬 프로젝트에서 원격 저장소 추가" -echo " 2. 첫 번째 push 실행" -echo " 3. Git 서비스 동작 확인" -echo "" -echo "🔧 Git 서비스 수동 시작 (필요시):" -echo " sudo systemctl start git-daemon" -echo " sudo git daemon --base-path=$GIT_DIR --export-all --reuseaddr &" -echo "" -echo "📖 자세한 설정은 synology-git-diagnostic.md 파일을 참조하세요." diff --git a/debug-files.js b/debug-files.js deleted file mode 100644 index 5789cf8..0000000 --- a/debug-files.js +++ /dev/null @@ -1,68 +0,0 @@ -const DatabaseHelper = require('./database/db-helper'); -const fs = require('fs'); -const path = require('path'); - -async function debugFiles() { - const db = new DatabaseHelper(); - - try { - await db.connect(); - - console.log('\n📋 데이터베이스의 모든 파일:'); - const files = await db.getAllFiles(); - - files.forEach((file, index) => { - console.log(`\n${index + 1}. ${file.title} (ID: ${file.id})`); - console.log(` 카테고리: ${file.category}`); - console.log(` 첨부파일: ${file.files?.length || 0}개`); - - if (file.files && file.files.length > 0) { - file.files.forEach((attachment, idx) => { - console.log(` ${idx + 1}) ${attachment.original_name}`); - console.log(` - ID: ${attachment.id}`); - console.log(` - 경로: ${attachment.file_path}`); - console.log(` - 파일명: ${attachment.file_name}`); - console.log(` - 크기: ${attachment.file_size}`); - - // 실제 파일 존재 확인 - const fullPath = path.join(__dirname, attachment.file_path); - const exists = fs.existsSync(fullPath); - console.log(` - 실제 파일 존재: ${exists ? '✅' : '❌'} (${fullPath})`); - - if (!exists) { - // 다른 경로들 시도 - const paths = [ - path.join(__dirname, 'uploads', attachment.file_name), - path.join(__dirname, 'uploads', attachment.original_name), - attachment.file_path, - ]; - - console.log(` - 시도할 경로들:`); - paths.forEach(p => { - const pathExists = fs.existsSync(p); - console.log(` ${pathExists ? '✅' : '❌'} ${p}`); - }); - } - }); - } - }); - - console.log('\n📁 uploads 폴더의 실제 파일들:'); - const uploadsDir = path.join(__dirname, 'uploads'); - if (fs.existsSync(uploadsDir)) { - const actualFiles = fs.readdirSync(uploadsDir); - actualFiles.forEach(file => { - const filePath = path.join(uploadsDir, file); - const stats = fs.statSync(filePath); - console.log(` - ${file} (크기: ${stats.size})`); - }); - } - - } catch (error) { - console.error('❌ 오류:', error.message); - } finally { - await db.close(); - } -} - -debugFiles(); \ No newline at end of file diff --git a/deploy-manual.sh b/deploy-manual.sh deleted file mode 100644 index b865fb9..0000000 --- a/deploy-manual.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# 수동 배포 스크립트 - 각 단계를 개별 실행 -NAS_IP="119.64.1.86" -NAS_USER="vibsin9322" -DEPLOY_DIR="/volume1/web/jaryo" -GITEA_URL="http://119.64.1.86:3000/vibsin9322/jaryo.git" - -echo "==========================================" -echo "🔧 수동 배포 가이드" -echo "==========================================" -echo "다음 명령들을 하나씩 실행하세요:" -echo "" - -echo "1️⃣ SSH 연결 테스트:" -echo "ssh -p 2222 $NAS_USER@$NAS_IP" -echo "" - -echo "2️⃣ 기존 배포 백업 (있는 경우):" -echo "ssh -p 2222 $NAS_USER@$NAS_IP 'sudo cp -r $DEPLOY_DIR ${DEPLOY_DIR}_backup_\$(date +%Y%m%d_%H%M%S) 2>/dev/null || true'" -echo "" - -echo "3️⃣ 배포 디렉토리 준비:" -echo "ssh -p 2222 $NAS_USER@$NAS_IP 'sudo rm -rf $DEPLOY_DIR && sudo mkdir -p $DEPLOY_DIR && sudo chown $NAS_USER:users $DEPLOY_DIR'" -echo "" - -echo "4️⃣ Git 클론:" -echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && git clone $GITEA_URL .'" -echo "" - -echo "5️⃣ 의존성 설치:" -echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && npm install'" -echo "" - -echo "6️⃣ 데이터베이스 처리:" -echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && if [ -f data/database.db ]; then echo \"기존 DB 유지\"; else npm run init-db; fi'" -echo "" - -echo "7️⃣ 서비스 시작:" -echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && PORT=3005 nohup node server.js > logs/app.log 2>&1 & echo \$! > jaryo.pid'" -echo "" - -echo "8️⃣ 서비스 확인:" -echo "curl http://$NAS_IP:3005" -echo "" -echo "==========================================" \ No newline at end of file diff --git a/enhanced-server.js b/enhanced-server.js deleted file mode 100644 index c8d9cc0..0000000 --- a/enhanced-server.js +++ /dev/null @@ -1,234 +0,0 @@ -const http = require("http"); -const fs = require("fs"); -const path = require("path"); -const url = require("url"); - -const PORT = 3005; -const DATA_FILE = path.join(__dirname, 'data.json'); -const UPLOAD_DIR = path.join(__dirname, 'uploads'); - -// 데이터 파일 초기화 -function initializeData() { - const defaultData = { - users: [ - { - id: '1', - email: 'admin@jaryo.com', - password: 'admin123', - name: '관리자', - role: 'admin' - } - ], - files: [ - { - id: '1', - title: '샘플 문서', - description: '자료실 테스트용 샘플 파일입니다.', - category: '문서', - tags: ['샘플', '테스트'], - user_id: '1', - created_at: new Date().toISOString(), - updated_at: new Date().toISOString(), - attachments: [] - } - ], - categories: ['문서', '이미지', '동영상', '프레젠테이션', '기타'] - }; - - if (!fs.existsSync(DATA_FILE)) { - fs.writeFileSync(DATA_FILE, JSON.stringify(defaultData, null, 2)); - } - - if (!fs.existsSync(UPLOAD_DIR)) { - fs.mkdirSync(UPLOAD_DIR, { recursive: true }); - } -} - -// 데이터 읽기/쓰기 -function readData() { - try { - const data = fs.readFileSync(DATA_FILE, 'utf8'); - return JSON.parse(data); - } catch (error) { - console.error('데이터 읽기 오류:', error); - return { users: [], files: [], categories: [] }; - } -} - -function writeData(data) { - try { - fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2)); - return true; - } catch (error) { - console.error('데이터 쓰기 오류:', error); - return false; - } -} - -// MIME 타입 -const mimeTypes = { - ".html": "text/html; charset=utf-8", - ".css": "text/css", - ".js": "application/javascript", - ".json": "application/json", - ".png": "image/png", - ".jpg": "image/jpeg" -}; - -// API 요청 처리 -async function handleApiRequest(req, res, pathname, query) { - const data = readData(); - - if (pathname === "/api/files/public" && req.method === "GET") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: true, - data: data.files, - total: data.files.length - })); - return; - } - - if (pathname === "/api/files" && req.method === "GET") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: true, - data: data.files, - total: data.files.length - })); - return; - } - - if (pathname === "/api/auth/login" && req.method === "POST") { - let body = ''; - req.on('data', chunk => body += chunk); - req.on('end', () => { - try { - const { email, password } = JSON.parse(body); - const user = data.users.find(u => u.email === email && u.password === password); - - if (user) { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: true, - user: { - id: user.id, - email: user.email, - name: user.name, - role: user.role - } - })); - } else { - res.writeHead(401, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: false, - error: '이메일 또는 비밀번호가 올바르지 않습니다.' - })); - } - } catch (error) { - res.writeHead(400, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: false, - error: '잘못된 요청입니다.' - })); - } - }); - return; - } - - // 기본 응답 - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: true, - message: "자료실 API 서버 실행 중", - timestamp: new Date().toISOString(), - path: pathname - })); -} - -// 정적 파일 서빙 -async function serveStaticFile(req, res, pathname) { - const filePath = path.join(__dirname, pathname); - - fs.readFile(filePath, (err, data) => { - if (err) { - res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" }); - res.end(` - - 404 Not Found - -

404 - 파일을 찾을 수 없습니다

-

요청한 파일: ${pathname}

-

홈으로 돌아가기

- - - `); - return; - } - - const ext = path.extname(filePath); - const contentType = mimeTypes[ext] || "text/plain"; - - res.writeHead(200, { "Content-Type": contentType }); - res.end(data); - }); -} - -// HTTP 서버 -const server = http.createServer(async (req, res) => { - res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With"); - - if (req.method === "OPTIONS") { - res.writeHead(200); - res.end(); - return; - } - - const parsedUrl = url.parse(req.url, true); - let pathname = parsedUrl.pathname; - const query = parsedUrl.query; - - console.log(`📨 ${req.method} ${pathname}`); - - if (pathname.startsWith("/api/")) { - try { - await handleApiRequest(req, res, pathname, query); - } catch (error) { - console.error('API 처리 오류:', error); - res.writeHead(500, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - success: false, - error: '서버 내부 오류가 발생했습니다.' - })); - } - return; - } - - if (pathname === "/" || pathname === "/index.html") { - pathname = "/index.html"; - } else if (pathname === "/admin" || pathname === "/admin/") { - pathname = "/admin/index.html"; - } - - await serveStaticFile(req, res, pathname); -}); - -server.listen(PORT, () => { - console.log(`🚀 향상된 자료실 서버가 포트 ${PORT}에서 실행 중입니다`); - console.log(`📍 접속 URL: http://119.64.1.86:${PORT}`); - console.log(`🔧 관리자 URL: http://119.64.1.86:${PORT}/admin`); - console.log(`⏰ 시작 시간: ${new Date().toLocaleString("ko-KR")}`); - - initializeData(); - console.log(`✅ 데이터 파일 초기화 완료`); -}); - -process.on("SIGINT", () => { - console.log("\n🛑 서버를 종료합니다..."); - server.close(() => { - console.log("✅ 서버가 정상적으로 종료되었습니다"); - process.exit(0); - }); -}); \ No newline at end of file diff --git a/manual-nas-deployment-guide.md b/manual-nas-deployment-guide.md deleted file mode 100644 index 3f36a5c..0000000 --- a/manual-nas-deployment-guide.md +++ /dev/null @@ -1,328 +0,0 @@ -# 시놀로지 NAS 수동 배포 가이드 - -## 🚀 시놀로지 NAS에서 자료실 서비스 배포하기 - -### 사전 준비사항 ✅ - -1. **DSM 패키지 설치 확인** - - Node.js v16+ (패키지 센터에서 설치) - - Git Server (패키지 센터에서 설치) - - SSH 서비스 활성화 (제어판 > 터미널 및 SNMP) - -2. **방화벽 설정** - - SSH 포트: 2222 허용 - - 서비스 포트: 3005 허용 - - Gitea 포트: 3000 허용 - -### 1단계: SSH 접속 🔗 - -```bash -# Windows에서 NAS 접속 -ssh -p 2222 admin@119.64.1.86 - -# 접속 후 관리자 권한 확인 -sudo whoami -``` - -### 2단계: 배포 디렉토리 준비 📁 - -```bash -# 웹 디렉토리로 이동 -cd /volume1/web - -# 기존 jaryo 폴더가 있다면 백업 -if [ -d "jaryo" ]; then - sudo mv jaryo jaryo_backup_$(date +%Y%m%d_%H%M%S) -fi - -# 새 디렉토리 생성 -sudo mkdir -p jaryo -sudo chown admin:users jaryo -cd jaryo -``` - -### 3단계: 소스 코드 클론 📥 - -```bash -# Gitea에서 소스 코드 클론 -git clone http://119.64.1.86:3000/vibsin9322/jaryo.git . - -# 클론 성공 확인 -ls -la -``` - -### 4단계: 의존성 설치 📦 - -```bash -# 기존 node_modules 제거 (있다면) -rm -rf node_modules package-lock.json - -# npm 의존성 설치 -npm install - -# 설치 확인 -ls -la node_modules -``` - -### 5단계: 데이터베이스 초기화 🗄️ - -```bash -# SQLite 데이터베이스 초기화 -npm run init-db - -# 데이터베이스 파일 확인 -ls -la *.db -``` - -### 6단계: 서비스 시작 스크립트 생성 📝 - -```bash -# 시작 스크립트 생성 -cat > start-jaryo.sh << 'EOF' -#!/bin/bash - -# 자료실 서비스 시작 스크립트 -PROJECT_DIR="/volume1/web/jaryo" -SERVICE_PORT="3005" -PID_FILE="$PROJECT_DIR/jaryo.pid" -LOG_FILE="$PROJECT_DIR/jaryo.log" - -# 로그 디렉토리 생성 -mkdir -p "$PROJECT_DIR/logs" - -# 기존 프로세스 확인 및 종료 -if [ -f "$PID_FILE" ]; then - OLD_PID=$(cat "$PID_FILE") - if ps -p "$OLD_PID" > /dev/null; then - echo "기존 서비스 종료 중... (PID: $OLD_PID)" - kill "$OLD_PID" - sleep 2 - fi - rm -f "$PID_FILE" -fi - -# 포트 사용 확인 -if netstat -tulpn | grep ":$SERVICE_PORT " > /dev/null; then - echo "⚠️ 포트 $SERVICE_PORT가 이미 사용 중입니다." - echo "사용 중인 프로세스:" - netstat -tulpn | grep ":$SERVICE_PORT " - exit 1 -fi - -# 서비스 시작 -echo "🚀 자료실 서비스 시작 중..." -cd "$PROJECT_DIR" -PORT="$SERVICE_PORT" nohup node server.js > "$LOG_FILE" 2>&1 & -echo $! > "$PID_FILE" - -sleep 2 - -# 시작 확인 -if ps -p $(cat "$PID_FILE") > /dev/null; then - echo "✅ 자료실 서비스 시작 완료!" - echo "📍 접속 URL: http://119.64.1.86:$SERVICE_PORT" - echo "📋 PID: $(cat "$PID_FILE")" - echo "📄 로그: $LOG_FILE" -else - echo "❌ 서비스 시작 실패" - echo "로그 확인:" - tail -20 "$LOG_FILE" - exit 1 -fi -EOF - -# 실행 권한 부여 -chmod +x start-jaryo.sh -``` - -### 7단계: 중지 스크립트 생성 🛑 - -```bash -# 중지 스크립트 생성 -cat > stop-jaryo.sh << 'EOF' -#!/bin/bash - -# 자료실 서비스 중지 스크립트 -PROJECT_DIR="/volume1/web/jaryo" -PID_FILE="$PROJECT_DIR/jaryo.pid" - -if [ -f "$PID_FILE" ]; then - PID=$(cat "$PID_FILE") - if ps -p "$PID" > /dev/null; then - echo "🛑 자료실 서비스 중지 중... (PID: $PID)" - kill "$PID" - sleep 2 - - # 강제 종료 확인 - if ps -p "$PID" > /dev/null; then - echo "⚡ 강제 종료 중..." - kill -9 "$PID" - fi - - rm -f "$PID_FILE" - echo "✅ 자료실 서비스 중지 완료" - else - echo "⚠️ 프로세스가 이미 종료됨" - rm -f "$PID_FILE" - fi -else - echo "⚠️ PID 파일이 없습니다. 수동으로 프로세스를 확인하세요." - echo "실행 중인 Node.js 프로세스:" - ps aux | grep 'node.*server.js' | grep -v grep -fi -EOF - -# 실행 권한 부여 -chmod +x stop-jaryo.sh -``` - -### 8단계: 서비스 시작 🎬 - -```bash -# 서비스 시작 -./start-jaryo.sh - -# 로그 확인 (별도 터미널에서) -tail -f jaryo.log -``` - -### 9단계: 접속 테스트 🧪 - -**브라우저에서 접속:** -- **메인 페이지**: `http://119.64.1.86:3005` -- **관리자 페이지**: `http://119.64.1.86:3005/admin` - -**명령줄에서 테스트:** -```bash -# 서비스 상태 확인 -curl -s http://119.64.1.86:3005 - -# 프로세스 확인 -ps aux | grep 'node.*server.js' | grep -v grep - -# 포트 확인 -netstat -tulpn | grep :3005 -``` - -## 🔧 서비스 관리 - -### 일상적인 관리 명령어 - -```bash -# 서비스 시작 -/volume1/web/jaryo/start-jaryo.sh - -# 서비스 중지 -/volume1/web/jaryo/stop-jaryo.sh - -# 서비스 재시작 -/volume1/web/jaryo/stop-jaryo.sh && /volume1/web/jaryo/start-jaryo.sh - -# 로그 확인 -tail -f /volume1/web/jaryo/jaryo.log - -# 실시간 로그 보기 -ssh -p 2222 admin@119.64.1.86 'tail -f /volume1/web/jaryo/jaryo.log' -``` - -### 상태 모니터링 - -```bash -# 서비스 상태 스크립트 -cat > status-jaryo.sh << 'EOF' -#!/bin/bash - -PROJECT_DIR="/volume1/web/jaryo" -PID_FILE="$PROJECT_DIR/jaryo.pid" -LOG_FILE="$PROJECT_DIR/jaryo.log" - -echo "=== 자료실 서비스 상태 ===" - -if [ -f "$PID_FILE" ]; then - PID=$(cat "$PID_FILE") - if ps -p "$PID" > /dev/null; then - echo "✅ 서비스 실행 중 (PID: $PID)" - echo "📊 메모리 사용량:" - ps -o pid,ppid,cmd,%mem,%cpu -p "$PID" - echo "" - echo "🌐 포트 상태:" - netstat -tulpn | grep :3005 - else - echo "❌ 서비스 중지됨 (PID 파일 존재하지만 프로세스 없음)" - fi -else - echo "❌ 서비스 중지됨 (PID 파일 없음)" -fi - -echo "" -echo "📄 최근 로그 (최근 5줄):" -if [ -f "$LOG_FILE" ]; then - tail -5 "$LOG_FILE" -else - echo "로그 파일이 없습니다." -fi -EOF - -chmod +x status-jaryo.sh -``` - -## 🔄 자동 시작 설정 (선택사항) - -### DSM 작업 스케줄러 사용 - -1. **DSM 로그인** → **제어판** → **작업 스케줄러** -2. **생성** → **예약된 작업** → **사용자 정의 스크립트** -3. 설정: - - **작업 이름**: Jaryo 자료실 자동 시작 - - **사용자**: root - - **스케줄**: 시스템 부팅 시 - - **스크립트**: `/volume1/web/jaryo/start-jaryo.sh` - -## 🚨 문제 해결 - -### 일반적인 문제들 - -**1. 포트 충돌** -```bash -# 포트 사용 확인 -netstat -tulpn | grep :3005 - -# 다른 포트 사용시 (예: 3006) -PORT=3006 node server.js -``` - -**2. 권한 문제** -```bash -# 디렉토리 권한 수정 -sudo chown -R admin:users /volume1/web/jaryo -chmod -R 755 /volume1/web/jaryo -``` - -**3. Node.js 버전 문제** -```bash -# Node.js 버전 확인 -node --version - -# 최소 요구 버전: v16.0.0 -``` - -**4. 데이터베이스 문제** -```bash -# 데이터베이스 재초기화 -rm -f jaryo.db -npm run init-db -``` - -## 📱 최종 확인 - -배포 완료 후 다음 URL들이 정상 작동하는지 확인: - -- ✅ **메인 페이지**: http://119.64.1.86:3005 -- ✅ **관리자 페이지**: http://119.64.1.86:3005/admin -- ✅ **API 상태**: http://119.64.1.86:3005/api/files -- ✅ **Gitea 저장소**: http://119.64.1.86:3000/vibsin9322/jaryo - -## 🎉 배포 완료! - -시놀로지 NAS에서 자료실 서비스가 성공적으로 실행되고 있습니다. -서비스 관리는 위의 스크립트들을 사용하여 쉽게 할 수 있습니다. \ No newline at end of file diff --git a/nas-git-connection-test.md b/nas-git-connection-test.md deleted file mode 100644 index c231768..0000000 --- a/nas-git-connection-test.md +++ /dev/null @@ -1,257 +0,0 @@ -# 시놀로지 NAS Git 서버 연결 테스트 가이드 - -## 🧪 연결 테스트 단계별 가이드 - -### 1단계: 기본 연결 테스트 - -#### 1.1 SSH 연결 확인 -```bash -# NAS SSH 연결 테스트 -ssh admin@your-nas-ip - -# 성공시 NAS 터미널에 접속됨 -# 실패시 확인사항: -# - SSH 서비스 활성화 여부 -# - 방화벽 설정 -# - IP 주소 정확성 -``` - -#### 1.2 Git 설치 확인 -```bash -# NAS에서 Git 명령어 확인 -which git -git --version - -# Git 서비스 상태 확인 -sudo systemctl status git-daemon -ps aux | grep git -``` - -### 2단계: 저장소 생성 및 설정 - -#### 2.1 자동 스크립트 실행 -```bash -# 로컬에서 NAS로 스크립트 복사 -scp create-git-repo.sh admin@your-nas-ip:/tmp/ - -# NAS에서 스크립트 실행 -ssh admin@your-nas-ip -cd /tmp -chmod +x create-git-repo.sh -./create-git-repo.sh jaryo-file-manager -``` - -#### 2.2 수동 저장소 생성 (스크립트 실패시) -```bash -# NAS에서 직접 실행 -ssh admin@your-nas-ip - -# Git 디렉토리 생성 -sudo mkdir -p /volume1/git -sudo chown admin:users /volume1/git -cd /volume1/git - -# Bare 저장소 생성 -mkdir jaryo-file-manager.git -cd jaryo-file-manager.git -git init --bare -sudo chown -R admin:users . -``` - -### 3단계: 로컬에서 연결 테스트 - -#### 3.1 기존 프로젝트에 원격 저장소 추가 -```bash -# 현재 jaryo 프로젝트 디렉토리에서 -cd /c/Users/COMTREE/claude_code/jaryo - -# NAS Git 원격 저장소 추가 -git remote add nas ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git - -# 원격 저장소 확인 -git remote -v -``` - -#### 3.2 첫 번째 Push 테스트 -```bash -# 모든 변경사항 커밋 (필요시) -git add . -git commit -m "Initial commit for NAS deployment" - -# NAS로 푸시 -git push nas master - -# 성공시 출력 예시: -# Enumerating objects: X, done. -# Counting objects: 100% (X/X), done. -# Delta compression using up to Y threads -# Compressing objects: 100% (X/X), done. -# Writing objects: 100% (X/X), X.XX KiB | X.XX MiB/s, done. -# Total X (delta X), reused X (delta X), pack-reused 0 -# To ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git -# * [new branch] master -> master -``` - -### 4단계: 클론 테스트 - -#### 4.1 다른 디렉토리에서 클론 테스트 -```bash -# 테스트용 디렉토리 생성 -mkdir /tmp/git-test -cd /tmp/git-test - -# NAS에서 클론 -git clone ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git - -# 성공시 프로젝트 파일들이 다운로드됨 -cd jaryo-file-manager -ls -la -``` - -#### 4.2 HTTP 클론 테스트 (Git HTTP 서버 실행시) -```bash -# Git HTTP 서버가 실행 중인 경우 -git clone http://your-nas-ip:3000/jaryo-file-manager.git -``` - -### 5단계: 웹 인터페이스 테스트 - -#### 5.1 GitWeb 접속 테스트 -- 브라우저에서 `http://your-nas-ip/git` 접속 -- 또는 `http://your-nas-ip:3000` 접속 -- 저장소 목록에서 `jaryo-file-manager` 확인 - -#### 5.2 Git HTTP 서버 상태 확인 -```bash -# NAS에서 Git HTTP 서버 실행 확인 -sudo netstat -tulpn | grep :3000 -ps aux | grep git-daemon -``` - -## 🚨 문제 해결 - -### 연결 실패 시 체크리스트 - -#### ❌ "Connection refused" 오류 -```bash -# 1. SSH 서비스 확인 -ssh -v admin@your-nas-ip - -# 2. 포트 확인 (기본: 22) -ssh -p 22 admin@your-nas-ip - -# 3. 방화벽 확인 -# DSM > 제어판 > 보안 > 방화벽 -``` - -#### ❌ "Permission denied" 오류 -```bash -# 1. 사용자 권한 확인 -# DSM > 제어판 > 사용자 및 그룹 > admin > 애플리케이션 - -# 2. SSH 키 설정 (선택사항) -ssh-keygen -t rsa -ssh-copy-id admin@your-nas-ip -``` - -#### ❌ "Repository not found" 오류 -```bash -# 1. 저장소 경로 확인 -ssh admin@your-nas-ip -ls -la /volume1/git/ -ls -la /volume1/git/jaryo-file-manager.git/ - -# 2. 권한 확인 -sudo chown -R admin:users /volume1/git/jaryo-file-manager.git -chmod -R 755 /volume1/git/jaryo-file-manager.git -``` - -#### ❌ Git 명령어 없음 -```bash -# Git 설치 확인 -which git - -# 패키지 센터에서 Git Server 설치 -# 또는 수동 설치: -sudo apt update -sudo apt install git -``` - -### 네트워크 설정 문제 - -#### 내부 네트워크 접속 실패 -```bash -# IP 주소 확인 -ping your-nas-ip -nslookup your-nas-ip - -# 포트 스캔 -nmap -p 22,3000 your-nas-ip -``` - -#### 외부 네트워크 접속 설정 -```bash -# 라우터 포트 포워딩 설정 -# 22 (SSH) -> NAS_IP:22 -# 3000 (Git HTTP) -> NAS_IP:3000 - -# 동적 DNS 설정 (선택사항) -# your-domain.dyndns.org -> your-public-ip -``` - -## 📊 연결 성공 확인 - -### ✅ 성공 지표들 - -1. **SSH 연결**: `ssh admin@your-nas-ip` 성공 -2. **저장소 존재**: `/volume1/git/jaryo-file-manager.git` 확인 -3. **Push 성공**: `git push nas master` 완료 -4. **Clone 성공**: 다른 위치에서 클론 가능 -5. **웹 접속**: 브라우저에서 Git 저장소 확인 - -### 📈 성능 테스트 - -```bash -# 대용량 파일 Push 테스트 -dd if=/dev/zero of=test-large-file.bin bs=1M count=10 -git add test-large-file.bin -git commit -m "Large file test" -time git push nas master - -# 클론 속도 테스트 -time git clone ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git test-clone -``` - -## 🔧 고급 설정 - -### Git Hooks 활용 -```bash -# NAS에서 post-receive hook 설정 -ssh admin@your-nas-ip -cd /volume1/git/jaryo-file-manager.git/hooks - -# 자동 배포 hook -cat > post-receive << 'EOF' -#!/bin/bash -echo "코드 푸시 완료: $(date)" -# 자동 배포 로직 추가 가능 -# cd /volume1/web/jaryo && git pull -EOF - -chmod +x post-receive -``` - -### 백업 설정 -```bash -# 저장소 백업 스크립트 -#!/bin/bash -BACKUP_DIR="/volume1/backup/git" -REPO_DIR="/volume1/git" -DATE=$(date +%Y%m%d_%H%M%S) - -mkdir -p "$BACKUP_DIR" -tar -czf "$BACKUP_DIR/git-repos-$DATE.tar.gz" -C "$REPO_DIR" . -echo "백업 완료: $BACKUP_DIR/git-repos-$DATE.tar.gz" -``` - -이 가이드를 따라하면 시놀로지 NAS Git 서버와의 연결을 성공적으로 테스트하고 설정할 수 있습니다. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fcf1fa0..de23ebd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,26 +1,116 @@ { "name": "jaryo-file-manager", - "version": "1.0.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jaryo-file-manager", - "version": "1.0.0", + "version": "2.0.0", "license": "MIT", "dependencies": { "bcrypt": "^5.1.1", "cors": "^2.8.5", "express": "^4.18.2", "express-session": "^1.17.3", - "fs": "^0.0.1-security", "multer": "^1.4.5-lts.1", - "path": "^0.12.7", "sqlite3": "^5.1.6", "uuid": "^9.0.1" }, "devDependencies": { - "nodemon": "^3.0.1" + "vercel": "^32.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edge-runtime/cookies": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/cookies/-/cookies-3.4.1.tgz", + "integrity": "sha512-z27BvgPxI73CgSlxU/NAUf1Q/shnqi6cobHEowf6VuLdSjGR3NjI2Y5dZUIBbK2zOJVZbXcHsVzJjz8LklteFQ==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/format": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/format/-/format-2.2.0.tgz", + "integrity": "sha512-gPrS6AVw/qJJL0vcxMXv4kFXCU3ZTCD1uuJpwX15YxHV8BgU9OG5v9LrkkXcr96PBT/9epypfNJMhlWADuEziw==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/node-utils": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/node-utils/-/node-utils-2.2.1.tgz", + "integrity": "sha512-RUl/439BHKshkhSGFRlZ1kzy68wL4mn8VNKDSZr3p0tciyZ33Mjfpl+vofqnHqXRmDI6nLnZpfJvhY3D88o0pA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@edge-runtime/cookies": "3.4.1" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/ponyfill": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@edge-runtime/ponyfill/-/ponyfill-2.4.1.tgz", + "integrity": "sha512-ZbR/EViY3gg2rmEAQTKPa6mXl4aR1/+cFcQe4r1segCjEbTAxT6PWu40odbu/KlZKSysEb2O/BWIC2lJgSJOMQ==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/primitives": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-4.0.5.tgz", + "integrity": "sha512-t7QiN5d/KpXgCvIfSt6Nm9Hj3WVdNgc5CpOD73jasY+9EvTI7Ngdj5cXvjcHrPcmYWJZMySPgeEeoL/1N/Llag==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@edge-runtime/vm": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-3.1.7.tgz", + "integrity": "sha512-hUMFbDQ/nZN+1TLMi6iMO1QFz9RSV8yGG8S42WFPFma1d7VSNE0eMdJUmwjmtav22/iQkzHMmu6oTSfAvRGS8g==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@edge-runtime/primitives": "4.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" } }, "node_modules/@gar/promisify": { @@ -30,6 +120,34 @@ "license": "MIT", "optional": true }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -112,6 +230,44 @@ "node": ">= 6" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@npmcli/fs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", @@ -151,6 +307,27 @@ "node": ">=10" } }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -161,6 +338,559 @@ "node": ">= 6" } }, + "node_modules/@ts-morph/common": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", + "integrity": "sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.7", + "minimatch": "^3.0.4", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/build-utils": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-7.3.0.tgz", + "integrity": "sha512-RJwqrGYSk75auHZqWmlSL+a5JsWv+4SF1AxNQJ+KpF3XWZ/8yThkN/jHBfNxMmW6VvNczSVtMaXI0/2Sess6Eg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/error-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vercel/error-utils/-/error-utils-2.0.2.tgz", + "integrity": "sha512-Sj0LFafGpYr6pfCqrQ82X6ukRl5qpmVrHM/191kNYFqkkB9YkjlMAj6QcEsvCG259x4QZ7Tya++0AB85NDPbKQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/fun": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vercel/fun/-/fun-1.1.0.tgz", + "integrity": "sha512-SpuPAo+MlAYMtcMcC0plx7Tv4Mp7SQhJJj1iIENlOnABL24kxHpL09XLQMGzZIzIW7upR8c3edwgfpRtp+dhVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@tootallnate/once": "2.0.0", + "async-listen": "1.2.0", + "debug": "4.1.1", + "execa": "3.2.0", + "fs-extra": "8.1.0", + "generic-pool": "3.4.2", + "micro": "9.3.5-canary.3", + "ms": "2.1.1", + "node-fetch": "2.6.7", + "path-match": "1.2.4", + "promisepipe": "3.0.0", + "semver": "7.3.5", + "stat-mode": "0.3.0", + "stream-to-promise": "2.2.0", + "tar": "4.4.18", + "tree-kill": "1.2.2", + "uid-promise": "1.0.0", + "uuid": "3.3.2", + "xdg-app-paths": "5.1.0", + "yauzl-promise": "2.1.3" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@vercel/fun/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@vercel/fun/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vercel/fun/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@vercel/fun/node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/@vercel/fun/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/@vercel/fun/node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/@vercel/fun/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/fun/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@vercel/fun/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vercel/fun/node_modules/tar": { + "version": "4.4.18", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.18.tgz", + "integrity": "sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg==", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/@vercel/fun/node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/@vercel/fun/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vercel/gatsby-plugin-vercel-analytics": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@vercel/gatsby-plugin-vercel-analytics/-/gatsby-plugin-vercel-analytics-1.0.11.tgz", + "integrity": "sha512-iTEA0vY6RBPuEzkwUTVzSHDATo1aF6bdLLspI68mQ/BTbi5UQEGjpjyzdKOVcSYApDtFU6M6vypZ1t4vIEnHvw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "web-vitals": "0.2.4" + } + }, + "node_modules/@vercel/gatsby-plugin-vercel-builder": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@vercel/gatsby-plugin-vercel-builder/-/gatsby-plugin-vercel-builder-2.0.12.tgz", + "integrity": "sha512-S1RkywrUItewqg06T3L4cgYfiwi2BFngHIIerhOYhVuD9A+yfMgxnH5dkbu6nujmV1SEws+Q92wSiPfLPmO0eA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "0.25.24", + "@vercel/build-utils": "7.3.0", + "@vercel/routing-utils": "3.1.0", + "esbuild": "0.14.47", + "etag": "1.8.1", + "fs-extra": "11.1.0" + } + }, + "node_modules/@vercel/gatsby-plugin-vercel-builder/node_modules/fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@vercel/gatsby-plugin-vercel-builder/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@vercel/gatsby-plugin-vercel-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@vercel/go": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vercel/go/-/go-3.0.4.tgz", + "integrity": "sha512-hMIJm2xwU1HT56YRNF8HNOnIFNH7WnGl1l2D6lc6UJk7XdCCh1Dm0nsqLqki2SprTUh3I+53pTQaqgRsFGf06A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/hydrogen": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vercel/hydrogen/-/hydrogen-1.0.1.tgz", + "integrity": "sha512-4PYk4LeIWPTjGtgnxvB0Hdw7aqCau843/96K2xX3z9pa0Hn//pUnZBMz2jrs5MRseCm1Li1LdQAK3u8/vaUnVQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@vercel/static-config": "3.0.0", + "ts-morph": "12.0.0" + } + }, + "node_modules/@vercel/next": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vercel/next/-/next-4.0.15.tgz", + "integrity": "sha512-BxMxIJrya7MS6IWrQIaQaYHPmq7WoZFLX909RBpNoAG5wgzrTrW756d2EsibBwGo7sQYBv2atyI5GqBIHzYbWg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@vercel/nft": "0.24.2" + } + }, + "node_modules/@vercel/nft": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.24.2.tgz", + "integrity": "sha512-KhY3Ky/lCqE+fHpOXiKOLnXYJ49PZh1dyDSfVtZhmYtmica0NQgyO6kPOAGDNWqD9IOBx8hb65upxxjfnfa1JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.5", + "@rollup/pluginutils": "^4.0.0", + "acorn": "^8.6.0", + "async-sema": "^3.1.1", + "bindings": "^1.4.0", + "estree-walker": "2.0.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.2", + "node-gyp-build": "^4.2.2", + "resolve-from": "^5.0.0" + }, + "bin": { + "nft": "out/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@vercel/node": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@vercel/node/-/node-3.0.12.tgz", + "integrity": "sha512-OiNHiUe1LX/CfDrQ07ntPsoYhJiC38mEeErYeqA6YNVAz3QGdX3pthiaIig2KPqeeYkEx5bSkVIqQtQOTJBuLQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@edge-runtime/node-utils": "2.2.1", + "@edge-runtime/primitives": "4.0.5", + "@edge-runtime/vm": "3.1.7", + "@types/node": "14.18.33", + "@vercel/build-utils": "7.3.0", + "@vercel/error-utils": "2.0.2", + "@vercel/nft": "0.24.2", + "@vercel/static-config": "3.0.0", + "async-listen": "3.0.0", + "edge-runtime": "2.5.7", + "esbuild": "0.14.47", + "etag": "1.8.1", + "exit-hook": "2.2.1", + "node-fetch": "2.6.9", + "path-to-regexp": "6.2.1", + "ts-morph": "12.0.0", + "ts-node": "10.9.1", + "typescript": "4.9.5", + "undici": "5.26.5" + } + }, + "node_modules/@vercel/node/node_modules/async-listen": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.0.tgz", + "integrity": "sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@vercel/node/node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@vercel/node/node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/python": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vercel/python/-/python-4.1.0.tgz", + "integrity": "sha512-EIQXK5zL6fce0Barh74gc7xyLtRyvgmLZDIVQ8yJLtFxPlPCRY3GXkdJ7Jdcw8Pd0uuVF0vIHatv18xSLbcwtg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/redwood": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vercel/redwood/-/redwood-2.0.5.tgz", + "integrity": "sha512-9iWTxfMkC7yNnwN2xxOdptiIDAgXe1V1fh3aw92MWt5PBRcFY9RqgIPF7Q3Qa7yzQFgpbHwCnSTqWO+HCEuFtw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@vercel/nft": "0.24.2", + "@vercel/routing-utils": "3.1.0", + "semver": "6.3.1" + } + }, + "node_modules/@vercel/redwood/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@vercel/remix-builder": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@vercel/remix-builder/-/remix-builder-2.0.14.tgz", + "integrity": "sha512-c+ILERSRq404sf6kt0qWhYhuxWkkoTEm2FdLoUnVs21K6kzGtJMJbUExEHoPZvN9a0tq86ZU86jVvRZV6WL0cQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@vercel/nft": "0.24.2", + "@vercel/static-config": "3.0.0", + "ts-morph": "12.0.0" + } + }, + "node_modules/@vercel/routing-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vercel/routing-utils/-/routing-utils-3.1.0.tgz", + "integrity": "sha512-Ci5xTjVTJY/JLZXpCXpLehMft97i9fH34nu9PGav6DtwkVUF6TOPX86U0W0niQjMZ5n6/ZP0BwcJK2LOozKaGw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "path-to-regexp": "6.1.0" + }, + "optionalDependencies": { + "ajv": "^6.0.0" + } + }, + "node_modules/@vercel/routing-utils/node_modules/path-to-regexp": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.1.0.tgz", + "integrity": "sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vercel/ruby": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vercel/ruby/-/ruby-2.0.4.tgz", + "integrity": "sha512-EpZyfF6wFGzFDmubFIh/EZtYpKindmXx/69xSfKEBTVU0afgljyOOICbyZePe5tvigfOEBLSLgrt/2nN+MlLtA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@vercel/static-build": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@vercel/static-build/-/static-build-2.0.14.tgz", + "integrity": "sha512-l5eQtJbk5Pc+P8XARDnpcbX4LnK3bGy7uf6S1aFOD4h6F8iBdg0agWTufZnq5BI91pcPVICPazM5BYhigIEznQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@vercel/gatsby-plugin-vercel-analytics": "1.0.11", + "@vercel/gatsby-plugin-vercel-builder": "2.0.12", + "@vercel/static-config": "3.0.0", + "ts-morph": "12.0.0" + } + }, + "node_modules/@vercel/static-config": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@vercel/static-config/-/static-config-3.0.0.tgz", + "integrity": "sha512-2qtvcBJ1bGY0dYGYh3iM7yGKkk971FujLEDXzuW5wcZsPr1GSEjO/w2iSr3qve6nDDtBImsGoDEnus5FI4+fIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ajv": "8.6.3", + "json-schema-to-ts": "1.6.4", + "ts-morph": "12.0.0" + } + }, + "node_modules/@vercel/static-config/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@vercel/static-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -180,6 +910,32 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -242,6 +998,24 @@ "node": ">=8" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -251,6 +1025,13 @@ "node": ">=8" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -307,12 +1088,33 @@ "node": ">= 6" } }, + "node_modules/arg": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", + "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "dev": true, + "license": "MIT" + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/async-listen": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-1.2.0.tgz", + "integrity": "sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -477,6 +1279,16 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -575,31 +1387,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -619,6 +1406,13 @@ "node": ">=6" } }, + "node_modules/code-block-writer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz", + "integrity": "sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==", + "dev": true, + "license": "MIT" + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -676,6 +1470,16 @@ "node": ">= 0.6" } }, + "node_modules/convert-hrtime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-3.0.0.tgz", + "integrity": "sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cookie": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", @@ -710,6 +1514,28 @@ "node": ">= 0.10" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -777,6 +1603,16 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -791,6 +1627,53 @@ "node": ">= 0.4" } }, + "node_modules/edge-runtime": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.5.7.tgz", + "integrity": "sha512-gA4qSVP0sNwJlkdQ2nahDPASlSl8twUd17o+JolPa1EtXpLTGzIpOETvodgJwXIxa+zaD8bnAXCdsWrx2PhlVQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@edge-runtime/format": "2.2.0", + "@edge-runtime/ponyfill": "2.4.1", + "@edge-runtime/vm": "3.1.7", + "async-listen": "3.0.1", + "mri": "1.2.0", + "picocolors": "1.0.0", + "pretty-ms": "7.0.1", + "signal-exit": "4.0.2", + "time-span": "4.0.0" + }, + "bin": { + "edge-runtime": "dist/cli/index.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/edge-runtime/node_modules/async-listen": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/async-listen/-/async-listen-3.0.1.tgz", + "integrity": "sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/edge-runtime/node_modules/signal-exit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -891,12 +1774,395 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", + "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.47", + "esbuild-android-arm64": "0.14.47", + "esbuild-darwin-64": "0.14.47", + "esbuild-darwin-arm64": "0.14.47", + "esbuild-freebsd-64": "0.14.47", + "esbuild-freebsd-arm64": "0.14.47", + "esbuild-linux-32": "0.14.47", + "esbuild-linux-64": "0.14.47", + "esbuild-linux-arm": "0.14.47", + "esbuild-linux-arm64": "0.14.47", + "esbuild-linux-mips64le": "0.14.47", + "esbuild-linux-ppc64le": "0.14.47", + "esbuild-linux-riscv64": "0.14.47", + "esbuild-linux-s390x": "0.14.47", + "esbuild-netbsd-64": "0.14.47", + "esbuild-openbsd-64": "0.14.47", + "esbuild-sunos-64": "0.14.47", + "esbuild-windows-32": "0.14.47", + "esbuild-windows-64": "0.14.47", + "esbuild-windows-arm64": "0.14.47" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", + "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", + "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", + "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", + "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", + "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", + "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", + "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", + "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", + "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", + "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", + "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", + "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", + "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", + "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", + "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", + "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", + "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", + "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", + "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", + "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -906,6 +2172,48 @@ "node": ">= 0.6" } }, + "node_modules/events-intercept": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/events-intercept/-/events-intercept-2.0.0.tgz", + "integrity": "sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz", + "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": "^8.12.0 || >=9.7.0" + } + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -995,6 +2303,58 @@ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -1050,18 +2410,27 @@ "node": ">= 0.6" } }, - "node_modules/fs": { - "version": "0.0.1-security", - "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", - "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==", - "license": "ISC" - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "license": "MIT" }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -1080,21 +2449,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1125,6 +2479,16 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/generic-pool": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.4.2.tgz", + "integrity": "sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -1162,6 +2526,22 @@ "node": ">= 0.4" } }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -1218,18 +2598,8 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC", - "optional": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } + "devOptional": true, + "license": "ISC" }, "node_modules/has-symbols": { "version": "1.1.0", @@ -1360,6 +2730,16 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -1402,13 +2782,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true, - "license": "ISC" - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1540,6 +2913,19 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1550,15 +2936,44 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC", + "devOptional": true, + "license": "ISC" + }, + "node_modules/json-schema-to-ts": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-1.6.4.tgz", + "integrity": "sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.6", + "ts-toolbelt": "^6.15.5" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT", "optional": true }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "devOptional": true, "license": "ISC", - "optional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -1590,6 +3005,13 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -1645,6 +3067,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -1654,6 +3093,128 @@ "node": ">= 0.6" } }, + "node_modules/micro": { + "version": "9.3.5-canary.3", + "resolved": "https://registry.npmjs.org/micro/-/micro-9.3.5-canary.3.tgz", + "integrity": "sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "arg": "4.1.0", + "content-type": "1.0.4", + "raw-body": "2.4.1" + }, + "bin": { + "micro": "bin/micro.js" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/micro/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/micro/node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro/node_modules/raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/micro/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true, + "license": "ISC" + }, + "node_modules/micro/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro/node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -1687,6 +3248,16 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -1833,6 +3404,16 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1936,60 +3517,18 @@ "node": ">= 10.12.0" } }, - "node_modules/nodemon": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", - "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "dev": true, "license": "MIT", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -2015,6 +3554,19 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npmlog": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", @@ -2083,6 +3635,42 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-paths": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz", + "integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0" + } + }, + "node_modules/p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", @@ -2099,6 +3687,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2108,15 +3706,12 @@ "node": ">= 0.8" } }, - "node_modules/path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", - "license": "MIT", - "dependencies": { - "process": "^0.11.1", - "util": "^0.10.3" - } + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" }, "node_modules/path-is-absolute": { "version": "1.0.1", @@ -2127,12 +3722,96 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-match": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/path-match/-/path-match-1.2.4.tgz", + "integrity": "sha512-UWlehEdqu36jmh4h5CWJ7tARp1OEVKGHKm6+dg9qMq5RKUTV5WJrGgaZ3dN2m7WFAXDbjlHzvJvL/IUpy84Ktw==", + "deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions", + "dev": true, + "license": "MIT", + "dependencies": { + "http-errors": "~1.4.0", + "path-to-regexp": "^1.0.0" + } + }, + "node_modules/path-match/node_modules/http-errors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz", + "integrity": "sha512-oLjPqve1tuOl5aRhv8GK5eHpqP1C9fb+Ol+XTLjKfLltE44zdDbEdjPSbU7Ch5rSNsVFqZn97SrMmZLdu1/YMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.1", + "statuses": ">= 1.2.1 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/path-match/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-match/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-match/node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-match/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -2172,13 +3851,20 @@ "node": ">=10" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, "license": "MIT", + "dependencies": { + "parse-ms": "^2.1.0" + }, "engines": { - "node": ">= 0.6.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/process-nextick-args": { @@ -2208,6 +3894,13 @@ "node": ">=10" } }, + "node_modules/promisepipe": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/promisepipe/-/promisepipe-3.0.0.tgz", + "integrity": "sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==", + "dev": true, + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2221,13 +3914,6 @@ "node": ">= 0.10" } }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true, - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", @@ -2238,6 +3924,16 @@ "once": "^1.3.1" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -2253,6 +3949,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -2322,17 +4039,24 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/retry": { @@ -2345,6 +4069,17 @@ "node": ">= 4" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2361,6 +4096,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2465,6 +4224,29 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -2588,19 +4370,6 @@ "simple-concat": "^1.0.0" } }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -2704,6 +4473,13 @@ "node": ">= 8" } }, + "node_modules/stat-mode": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.3.0.tgz", + "integrity": "sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2713,6 +4489,48 @@ "node": ">= 0.8" } }, + "node_modules/stream-to-array": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", + "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.1.0" + } + }, + "node_modules/stream-to-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-to-promise/-/stream-to-promise-2.2.0.tgz", + "integrity": "sha512-HAGUASw8NT0k8JvIVutB2Y/9iBk7gpgEyAudXwNJmZERdMITGdajOa4VJfD/kNiA3TppQpTP4J+CtcHwdzKBAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "~1.3.0", + "end-of-stream": "~1.1.0", + "stream-to-array": "~2.3.0" + } + }, + "node_modules/stream-to-promise/node_modules/end-of-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz", + "integrity": "sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "~1.3.0" + } + }, + "node_modules/stream-to-promise/node_modules/once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -2762,6 +4580,16 @@ "node": ">=8" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -2771,19 +4599,6 @@ "node": ">=0.10.0" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", @@ -2870,6 +4685,22 @@ "node": ">=10" } }, + "node_modules/time-span": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-4.0.0.tgz", + "integrity": "sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-hrtime": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2892,22 +4723,84 @@ "node": ">=0.6" } }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "dev": true, - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-morph": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-12.0.0.tgz", + "integrity": "sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.11.0", + "code-block-writer": "^10.1.1" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -2939,6 +4832,27 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uid-promise": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uid-promise/-/uid-promise-1.0.0.tgz", + "integrity": "sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==", + "dev": true, + "license": "MIT" + }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -2951,12 +4865,18 @@ "node": ">= 0.8" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "node_modules/undici": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", + "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } }, "node_modules/unique-filename": { "version": "1.1.1", @@ -2978,6 +4898,16 @@ "imurmurhash": "^0.1.4" } }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2987,13 +4917,14 @@ "node": ">= 0.8" } }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "license": "MIT", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "inherits": "2.0.3" + "punycode": "^2.1.0" } }, "node_modules/util-deprecate": { @@ -3002,12 +4933,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "license": "ISC" - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -3030,6 +4955,13 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3039,6 +4971,91 @@ "node": ">= 0.8" } }, + "node_modules/vercel": { + "version": "32.7.2", + "resolved": "https://registry.npmjs.org/vercel/-/vercel-32.7.2.tgz", + "integrity": "sha512-esyeo67OZ/f7usKFCrx6NSjsvpo/BP/C8Mfron2uiCb4vXVcjkwOM7TwliHx6b0DbXjpzomdGVUHKRs34VNn2Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@vercel/build-utils": "7.3.0", + "@vercel/fun": "1.1.0", + "@vercel/go": "3.0.4", + "@vercel/hydrogen": "1.0.1", + "@vercel/next": "4.0.15", + "@vercel/node": "3.0.12", + "@vercel/python": "4.1.0", + "@vercel/redwood": "2.0.5", + "@vercel/remix-builder": "2.0.14", + "@vercel/ruby": "2.0.4", + "@vercel/static-build": "2.0.14", + "chokidar": "3.3.1" + }, + "bin": { + "vc": "dist/index.js", + "vercel": "dist/index.js" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/vercel/node_modules/chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/vercel/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vercel/node_modules/readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.0.7" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/web-vitals": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-0.2.4.tgz", + "integrity": "sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -3059,8 +5076,8 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, "license": "ISC", - "optional": true, "dependencies": { "isexe": "^2.0.0" }, @@ -3086,6 +5103,32 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/xdg-app-paths": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.1.0.tgz", + "integrity": "sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xdg-portable": "^7.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/xdg-portable": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz", + "integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-paths": "^4.0.1" + }, + "engines": { + "node": ">= 6.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -3100,6 +5143,54 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yauzl-clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/yauzl-clone/-/yauzl-clone-1.0.4.tgz", + "integrity": "sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-intercept": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yauzl-promise": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-2.1.3.tgz", + "integrity": "sha512-A1pf6fzh6eYkK0L4Qp7g9jzJSDrM6nN0bOn5T0IbY4Yo3w+YkWlHFkJP7mzknMXjqusHFHlKsK2N+4OLsK2MRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "yauzl": "^2.9.1", + "yauzl-clone": "^1.0.4" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } } } } diff --git a/package.json b/package.json index e7e4075..7d9c0e4 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,26 @@ { "name": "jaryo-file-manager", "version": "2.0.0", - "description": "자료실 파일 관리 시스템 - Vercel Serverless", + "description": "자료실 파일 관리 시스템", + "main": "server.js", "scripts": { - "dev": "vercel dev", - "build": "echo 'Build complete'", - "start": "vercel dev" + "start": "node server.js", + "dev": "node server.js", + "build": "echo 'Build complete'" + }, + "dependencies": { + "express": "^4.18.2", + "cors": "^2.8.5", + "multer": "^1.4.5-lts.1", + "bcrypt": "^5.1.1", + "express-session": "^1.17.3", + "uuid": "^9.0.1", + "sqlite3": "^5.1.6" }, - "dependencies": {}, "devDependencies": { "vercel": "^32.0.0" }, - "keywords": ["file-manager", "vercel", "serverless", "admin"], + "keywords": ["file-manager", "admin"], "author": "Claude Code", "license": "MIT", "engines": { diff --git a/pm2-ecosystem.config.js b/pm2-ecosystem.config.js deleted file mode 100644 index 2e4d0f0..0000000 --- a/pm2-ecosystem.config.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = { - apps: [{ - name: 'jaryo-file-manager', - script: 'server.js', - cwd: '/volume1/web/jaryo', - instances: 1, - autorestart: true, - watch: false, - max_memory_restart: '1G', - env: { - NODE_ENV: 'production', - PORT: 3005 - }, - env_production: { - NODE_ENV: 'production', - PORT: 3005 - }, - log_file: '/volume1/web/jaryo/logs/combined.log', - out_file: '/volume1/web/jaryo/logs/out.log', - error_file: '/volume1/web/jaryo/logs/error.log', - log_date_format: 'YYYY-MM-DD HH:mm:ss Z', - merge_logs: true, - time: true - }] -}; diff --git a/pm2-start.sh b/pm2-start.sh deleted file mode 100644 index f399990..0000000 --- a/pm2-start.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -# PM2를 사용한 시놀로지 NAS 서비스 시작 스크립트 -# 사용법: ./pm2-start.sh - -PROJECT_DIR="/volume1/web/jaryo" -LOG_DIR="/volume1/web/jaryo/logs" - -echo "=== PM2로 Jaryo File Manager 서비스 시작 ===" - -# 로그 디렉토리 생성 -mkdir -p "$LOG_DIR" - -# 프로젝트 디렉토리로 이동 -cd "$PROJECT_DIR" || { - echo "오류: 프로젝트 디렉토리를 찾을 수 없습니다: $PROJECT_DIR" - exit 1 -} - -# PM2 설치 확인 및 설치 -if ! command -v pm2 &> /dev/null; then - echo "PM2 설치 중..." - npm install -g pm2 -fi - -# 의존성 설치 확인 -if [ ! -d "node_modules" ]; then - echo "의존성 설치 중..." - npm install -fi - -# 데이터베이스 초기화 -echo "데이터베이스 초기화 중..." -node scripts/init-database.js - -# 기존 PM2 프로세스 중지 -echo "기존 프로세스 정리 중..." -pm2 delete jaryo-file-manager 2>/dev/null || true - -# PM2로 서비스 시작 -echo "PM2로 서비스 시작 중..." -pm2 start pm2-ecosystem.config.js --env production - -# PM2 시작 스크립트 생성 -pm2 startup -pm2 save - -echo "서비스가 PM2로 시작되었습니다." -echo "상태 확인: pm2 status" -echo "로그 확인: pm2 logs jaryo-file-manager" -echo "서비스 중지: pm2 stop jaryo-file-manager" diff --git a/render.yaml b/render.yaml deleted file mode 100644 index b230060..0000000 --- a/render.yaml +++ /dev/null @@ -1,12 +0,0 @@ -services: - - type: web - name: jaryo-file-manager - env: node - plan: free - buildCommand: npm install - startCommand: npm start - envVars: - - key: NODE_ENV - value: production - - key: PORT - value: 10000 diff --git a/scripts/init-database.js b/scripts/init-database.js deleted file mode 100644 index 7ec2682..0000000 --- a/scripts/init-database.js +++ /dev/null @@ -1,73 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const sqlite3 = require('sqlite3').verbose(); - -// 데이터베이스 파일 경로 -const dbPath = path.join(__dirname, '../database/jaryo.db'); -const schemaPath = path.join(__dirname, '../database/schema.sql'); - -// database 폴더가 없으면 생성 -const dbDir = path.dirname(dbPath); -if (!fs.existsSync(dbDir)) { - fs.mkdirSync(dbDir, { recursive: true }); -} - -// uploads 폴더도 생성 -const uploadsDir = path.join(__dirname, '../uploads'); -if (!fs.existsSync(uploadsDir)) { - fs.mkdirSync(uploadsDir, { recursive: true }); -} - -console.log('🔧 SQLite 데이터베이스 초기화 시작...'); - -// 데이터베이스 연결 -const db = new sqlite3.Database(dbPath, (err) => { - if (err) { - console.error('❌ 데이터베이스 연결 오류:', err.message); - return; - } - console.log('✅ SQLite 데이터베이스 연결 성공'); -}); - -// 스키마 파일 읽기 및 실행 -fs.readFile(schemaPath, 'utf8', (err, schema) => { - if (err) { - console.error('❌ 스키마 파일 읽기 오류:', err.message); - return; - } - - // 여러 SQL 문을 분리하여 실행 - const statements = schema.split(';').filter(stmt => stmt.trim().length > 0); - - db.serialize(() => { - statements.forEach((statement, index) => { - if (statement.trim()) { - db.run(statement + ';', (err) => { - if (err) { - console.error(`❌ SQL 실행 오류 (${index + 1}):`, err.message); - console.error('실행하려던 SQL:', statement); - } - }); - } - }); - - console.log('✅ 데이터베이스 스키마 생성 완료'); - - // 데이터 확인 - db.all('SELECT COUNT(*) as count FROM files', (err, rows) => { - if (err) { - console.error('❌ 데이터 확인 오류:', err.message); - } else { - console.log(`📊 파일 테이블 레코드 수: ${rows[0].count}`); - } - - db.close((err) => { - if (err) { - console.error('❌ 데이터베이스 종료 오류:', err.message); - } else { - console.log('🏁 데이터베이스 초기화 완료'); - } - }); - }); - }); -}); \ No newline at end of file diff --git a/simple.html b/simple.html deleted file mode 100644 index fac682a..0000000 --- a/simple.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - Jaryo File Manager - 테스트 - - - -
-

🚀 Jaryo File Manager

- -
-

✅ 정적 페이지 테스트

-

이 페이지가 보인다면 Vercel 배포가 성공한 것입니다!

-

시간:

-
- -
-

🔧 테스트 버튼들

- 메인 페이지 - API 테스트 - 파일 API -
- -
-

📡 AJAX 테스트

- -
-
-
- - - - \ No newline at end of file diff --git a/ssh-connect.sh b/ssh-connect.sh deleted file mode 100644 index 2142941..0000000 --- a/ssh-connect.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# SSH 연결 헬퍼 스크립트 -NAS_IP="${1:-119.64.1.86}" -NAS_USER="${2:-vibsin9322}" -COMMAND="${3:-echo 'SSH 연결 성공'}" - -# 비밀번호를 입력받아 SSH 연결 -echo "🔑 SSH 연결 시도: $NAS_USER@$NAS_IP:2222" -echo "📝 비밀번호를 입력하세요:" - -ssh -p 2222 -o StrictHostKeyChecking=no "$NAS_USER@$NAS_IP" "$COMMAND" \ No newline at end of file diff --git a/styles.css b/styles.css index e89fe78..61e686f 100644 --- a/styles.css +++ b/styles.css @@ -619,7 +619,7 @@ header p { /* 제목 스타일 */ .board-title { color: #667eea; - font-weight: 500; + font-weight: 700; text-decoration: none; cursor: pointer; display: block; diff --git a/synology-git-diagnostic.md b/synology-git-diagnostic.md deleted file mode 100644 index e480777..0000000 --- a/synology-git-diagnostic.md +++ /dev/null @@ -1,203 +0,0 @@ -# 시놀로지 NAS Git Server 진단 및 해결 가이드 - -## 🔍 1단계: Git Server 패키지 상태 확인 - -### 1.1 DSM 패키지 센터 점검 -1. **DSM 로그인** → **패키지 센터** -2. **설치됨** 탭에서 "Git Server" 검색 -3. 상태 확인: - - ✅ **실행 중**: 정상 동작 - - ⚠️ **중지됨**: 서비스 시작 필요 - - ❌ **미설치**: 패키지 설치 필요 - -### 1.2 Git Server 서비스 시작 -```bash -# SSH로 NAS 접속 후 -sudo systemctl status git-daemon -sudo systemctl start git-daemon -sudo systemctl enable git-daemon -``` - -## 🛠️ 2단계: 기본 설정 확인 - -### 2.1 SSH 서비스 활성화 -1. **DSM 제어판** → **터미널 및 SNMP** -2. **SSH 서비스 활성화** 체크 -3. 포트 번호 확인 (기본: 22) - -### 2.2 사용자 권한 설정 -1. **DSM 제어판** → **사용자 및 그룹** -2. 사용자 선택 → **편집** → **애플리케이션** -3. **Git Server** 권한 부여 - -### 2.3 방화벽 설정 -1. **DSM 제어판** → **보안** → **방화벽** -2. 다음 포트 허용: - - SSH: 22 - - Git HTTP: 3000 - - Git HTTPS: 3001 - -## 📁 3단계: Git 디렉토리 구조 확인 - -### 3.1 기본 경로 확인 -```bash -# SSH 접속 후 확인 -ls -la /volume1/ -ls -la /volume1/git/ - -# Git 설정 디렉토리 확인 -ls -la /usr/local/git/ -``` - -### 3.2 권한 문제 해결 -```bash -# Git 디렉토리 생성 -sudo mkdir -p /volume1/git -sudo chown -R admin:users /volume1/git -sudo chmod 755 /volume1/git - -# Git Server 사용자 추가 (필요시) -sudo adduser git -sudo usermod -a -G users git -``` - -## 🔧 4단계: 레포지토리 수동 생성 - -### 4.1 Bare 레포지토리 생성 -```bash -# SSH로 NAS 접속 -ssh admin@your-nas-ip - -# 프로젝트 디렉토리 생성 -cd /volume1/git -sudo mkdir jaryo-file-manager.git -cd jaryo-file-manager.git - -# Bare 레포지토리 초기화 -sudo git init --bare -sudo chown -R admin:users . -``` - -### 4.2 웹 인터페이스 활성화 -```bash -# Git HTTP 서버 시작 -cd /volume1/git -sudo git daemon --reuseaddr --base-path=. --export-all --verbose --enable=receive-pack -``` - -## 🌐 5단계: 웹 인터페이스 설정 - -### 5.1 Git Web 설정 -```bash -# CGit 또는 GitWeb 설치 -sudo apt update -sudo apt install gitweb - -# Apache 설정 (Web Station 사용시) -sudo ln -s /usr/share/gitweb /volume1/web/git -``` - -### 5.2 브라우저에서 접속 -- URL: `http://your-nas-ip/git` -- 또는: `http://your-nas-ip:3000` - -## 🚨 6단계: 문제 해결 - -### 6.1 "레포지토리 설정이 안보임" 해결 -**원인 1: Git Server 패키지 미설치** -```bash -# 패키지 센터에서 Git Server 재설치 -# 또는 수동 Git 설치 -sudo apt update -sudo apt install git git-daemon-run -``` - -**원인 2: 서비스 시작 실패** -```bash -# 서비스 상태 확인 -sudo systemctl status git-daemon -sudo journalctl -u git-daemon - -# 수동 재시작 -sudo systemctl restart git-daemon -``` - -**원인 3: 권한 문제** -```bash -# 권한 재설정 -sudo chown -R www-data:www-data /volume1/git -sudo chmod -R 755 /volume1/git -``` - -### 6.2 포트 충돌 해결 -```bash -# 포트 사용 확인 -sudo netstat -tulpn | grep :3000 -sudo netstat -tulpn | grep :22 - -# 다른 포트로 변경 -sudo git daemon --port=3001 --reuseaddr --base-path=/volume1/git --export-all -``` - -## 📋 7단계: 연결 테스트 - -### 7.1 로컬에서 연결 테스트 -```bash -# SSH 연결 테스트 -ssh admin@your-nas-ip - -# Git 클론 테스트 -git clone ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git - -# 또는 HTTP 연결 -git clone http://your-nas-ip:3000/jaryo-file-manager.git -``` - -### 7.2 기존 프로젝트 푸시 -```bash -# 기존 프로젝트에서 -git remote add nas ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git -git push nas master -``` - -## 🔄 8단계: 자동화 설정 - -### 8.1 systemd 서비스 생성 -```bash -# /etc/systemd/system/git-daemon.service -sudo tee /etc/systemd/system/git-daemon.service << EOF -[Unit] -Description=Git Daemon -After=network.target - -[Service] -ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/volume1/git --export-all --verbose --enable=receive-pack -Restart=always -User=git -Group=git - -[Install] -WantedBy=multi-user.target -EOF - -sudo systemctl enable git-daemon -sudo systemctl start git-daemon -``` - -## 📊 요약 - -레포지토리 설정이 보이지 않는 주요 원인: -1. ❌ Git Server 패키지 미설치/미실행 -2. ❌ SSH 서비스 비활성화 -3. ❌ 사용자 권한 부족 -4. ❌ 방화벽 차단 -5. ❌ Git 디렉토리 부재 - -해결 순서: -1. 패키지 설치/재시작 -2. SSH 및 권한 설정 -3. 수동 레포지토리 생성 -4. 연결 테스트 -5. 자동화 설정 - -이 가이드를 따라하면 시놀로지 NAS에서 Git 레포지토리를 성공적으로 설정할 수 있습니다. \ No newline at end of file diff --git a/synology-setup.md b/synology-setup.md deleted file mode 100644 index f5722ce..0000000 --- a/synology-setup.md +++ /dev/null @@ -1,248 +0,0 @@ -# 시놀로지 NAS에서 Jaryo File Manager 서비스 실행 가이드 - -## 1. 사전 준비사항 - -### 1.1 DSM 패키지 설치 -1. **DSM 제어판** → **패키지 센터** 접속 -2. 다음 패키지들을 설치: - - **Node.js** (최신 LTS 버전 권장) - - **Git Server** (선택사항, 소스코드 관리용) - - **Web Station** (선택사항, 웹 서버 프록시용) - -### 1.2 SSH 활성화 -1. **DSM 제어판** → **터미널 및 SNMP** → **SSH 서비스 활성화** -2. 포트 번호 확인 (기본: 22) - -## 2. 프로젝트 배포 - -### 2.1 방법 1: 직접 파일 업로드 (간단한 방법) - -1. **File Station**에서 `/volume1/web/` 폴더 생성 -2. 프로젝트 파일들을 `jaryo` 폴더에 업로드 -3. SSH로 접속하여 설정 - -### 2.2 방법 2: Git을 통한 배포 (권장) - -```bash -# NAS에 SSH 접속 -ssh admin@your-nas-ip - -# 프로젝트 디렉토리 생성 -mkdir -p /volume1/web/jaryo -cd /volume1/web/jaryo - -# Git 저장소 클론 (로컬에서 push한 경우) -git clone [your-repository-url] . - -# 또는 로컬에서 직접 파일 복사 -# scp -r ./jaryo/* admin@your-nas-ip:/volume1/web/jaryo/ -``` - -## 3. 서비스 설정 및 실행 - -### 3.1 스크립트 권한 설정 - -```bash -# SSH로 NAS 접속 -ssh admin@your-nas-ip - -# 프로젝트 디렉토리로 이동 -cd /volume1/web/jaryo - -# 스크립트 실행 권한 부여 -chmod +x start-service.sh -chmod +x stop-service.sh -``` - -### 3.2 서비스 시작 - -```bash -# 서비스 시작 -./start-service.sh - -# 로그 확인 -tail -f logs/app.log - -# 프로세스 상태 확인 -ps aux | grep "node server.js" -``` - -### 3.3 서비스 중지 - -```bash -# 서비스 중지 -./stop-service.sh -``` - -## 4. 자동 시작 설정 (선택사항) - -### 4.1 Task Scheduler 사용 - -1. **DSM 제어판** → **작업 스케줄러** -2. **작업 생성** → **사용자 정의 스크립트** -3. 설정: - - **작업 이름**: Jaryo Service Start - - **사용자**: root - - **스케줄**: 시스템 부팅 시 - - **작업 설정**: `/volume1/web/jaryo/start-service.sh` - -### 4.2 rc.local 사용 (고급 사용자) - -```bash -# /etc/rc.local 파일 편집 -sudo vi /etc/rc.local - -# 다음 라인 추가 -/volume1/web/jaryo/start-service.sh & - -# 파일 저장 후 권한 설정 -chmod +x /etc/rc.local -``` - -## 5. 방화벽 및 포트 설정 - -### 5.1 DSM 방화벽 설정 - -1. **DSM 제어판** → **보안** → **방화벽** -2. **방화벽 규칙 편집** → **규칙 생성** -3. 설정: - - **포트**: 3005 (애플리케이션 포트) - - **프로토콜**: TCP - - **소스**: 허용할 IP 범위 - -### 5.2 라우터 포트 포워딩 (외부 접속용) - -라우터에서 포트 3005를 NAS의 IP로 포워딩 설정 - -## 6. 웹 서버 프록시 설정 (Web Station 사용) - -### 6.1 Web Station 설정 - -1. **Web Station** → **가상 호스트** → **생성** -2. 설정: - - **도메인 이름**: your-domain.com (또는 IP) - - **포트**: 80 (또는 443 for HTTPS) - - **문서 루트**: `/volume1/web/jaryo` - - **HTTP 백엔드 서버**: `http://localhost:3005` - -### 6.2 Apache 설정 (고급) - -```apache -# /volume1/web/apache/conf/vhost/VirtualHost.conf - - ServerName your-domain.com - DocumentRoot /volume1/web/jaryo - - ProxyPreserveHost On - ProxyPass / http://localhost:3005/ - ProxyPassReverse / http://localhost:3005/ - - - AllowOverride All - Require all granted - - -``` - -## 7. 모니터링 및 유지보수 - -### 7.1 로그 모니터링 - -```bash -# 실시간 로그 확인 -tail -f /volume1/web/jaryo/logs/app.log - -# 로그 파일 크기 확인 -du -h /volume1/web/jaryo/logs/app.log - -# 로그 로테이션 설정 (logrotate 사용) -``` - -### 7.2 서비스 상태 확인 - -```bash -# 프로세스 확인 -ps aux | grep "node server.js" - -# 포트 사용 확인 -netstat -tlnp | grep :3005 - -# 메모리 사용량 확인 -top -p $(cat /volume1/web/jaryo/app.pid) -``` - -### 7.3 백업 설정 - -1. **Hyper Backup** 패키지 설치 -2. `/volume1/web/jaryo` 폴더 백업 스케줄 설정 -3. 데이터베이스 파일 (`jaryo.db`) 별도 백업 권장 - -## 8. 문제 해결 - -### 8.1 일반적인 문제들 - -**서비스가 시작되지 않는 경우:** -```bash -# Node.js 설치 확인 -which node -node --version - -# 의존성 재설치 -cd /volume1/web/jaryo -rm -rf node_modules package-lock.json -npm install - -# 권한 문제 확인 -ls -la /volume1/web/jaryo/ -chown -R admin:users /volume1/web/jaryo/ -``` - -**포트 충돌 문제:** -```bash -# 포트 사용 확인 -netstat -tlnp | grep :3005 - -# 다른 포트로 변경 (server.js 수정) -# const PORT = process.env.PORT || 3006; -``` - -**메모리 부족 문제:** -```bash -# 메모리 사용량 확인 -free -h - -# Node.js 메모리 제한 설정 -# node --max-old-space-size=512 server.js -``` - -### 8.2 로그 분석 - -```bash -# 에러 로그만 확인 -grep -i error /volume1/web/jaryo/logs/app.log - -# 최근 100줄 확인 -tail -100 /volume1/web/jaryo/logs/app.log - -# 특정 시간대 로그 확인 -grep "2024-01-15" /volume1/web/jaryo/logs/app.log -``` - -## 9. 보안 고려사항 - -1. **HTTPS 설정**: Let's Encrypt 인증서 사용 -2. **방화벽 강화**: 필요한 포트만 개방 -3. **정기 업데이트**: Node.js 및 패키지 업데이트 -4. **백업**: 정기적인 데이터 백업 -5. **모니터링**: 로그 모니터링 및 알림 설정 - -## 10. 성능 최적화 - -1. **PM2 사용**: 프로세스 관리자로 PM2 사용 고려 -2. **캐싱**: 정적 파일 캐싱 설정 -3. **압축**: gzip 압축 활성화 -4. **CDN**: 정적 파일 CDN 사용 고려 - ---- - -**참고**: 이 가이드는 시놀로지 DSM 7.x 기준으로 작성되었습니다. 버전에 따라 일부 설정이 다를 수 있습니다. diff --git a/vercel.json b/vercel.json deleted file mode 100644 index 58ac9fe..0000000 --- a/vercel.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": 2, - "routes": [ - { - "src": "/simple", - "dest": "/simple.html" - }, - { - "src": "/api/test", - "dest": "/api/test.js" - }, - { - "src": "/api/files/public", - "dest": "/api/files.js" - }, - { - "src": "/api/files", - "dest": "/api/files.js" - }, - { - "src": "/(.*\\.(css|js|json|svg|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|html))", - "dest": "/$1" - }, - { - "src": "/admin/(.*)", - "dest": "/admin/$1" - }, - { - "src": "/", - "dest": "/simple.html" - } - ] -} diff --git a/게시판.png b/게시판.png deleted file mode 100644 index 099b68d4f1d8d5e3467e48f4f08158e97b1754a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33458 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 diff --git a/오류.png b/오류.png deleted file mode 100644 index 7b98a61f45803a42c268b2a9140f6a7867f4158d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30735 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