mirror of
https://github.com/beilunyang/moemail.git
synced 2025-09-26 19:41:22 +08:00
chore: Update deploy script
This commit is contained in:
10
.env.example
10
.env.example
@@ -1,3 +1,11 @@
|
||||
AUTH_GITHUB_ID = ""
|
||||
AUTH_GITHUB_SECRET = ""
|
||||
AUTH_SECRET = ""
|
||||
AUTH_SECRET = ""
|
||||
|
||||
CLOUDFLARE_API_TOKEN = ""
|
||||
CLOUDFLARE_ACCOUNT_ID = ""
|
||||
DATABASE_NAME = ""
|
||||
DATABASE_ID = ""
|
||||
KV_NAMESPACE_ID = ""
|
||||
|
||||
PROJECT_URL = ""
|
6
.gitignore
vendored
6
.gitignore
vendored
@@ -46,4 +46,8 @@ wrangler.email.toml
|
||||
wrangler.cleanup.toml
|
||||
|
||||
public/workbox-*.js
|
||||
public/sw.js
|
||||
public/sw.js
|
||||
|
||||
wrangler.json
|
||||
wrangler.cleanup.json
|
||||
wrangler.email.json
|
@@ -12,10 +12,10 @@
|
||||
"db:migrate-remote": "bun run scripts/migrate.ts remote",
|
||||
"webhook-test-server": "bun run scripts/webhook-test-server.ts",
|
||||
"generate-test-data": "wrangler dev scripts/generate-test-data.ts",
|
||||
"dev:cleanup": "wrangler dev --config wrangler.cleanup.toml --test-scheduled",
|
||||
"dev:cleanup": "wrangler dev --config wrangler.cleanup.json --test-scheduled",
|
||||
"test:cleanup": "curl http://localhost:8787/__scheduled",
|
||||
"deploy:email": "wrangler deploy --config wrangler.email.toml",
|
||||
"deploy:cleanup": "wrangler deploy --config wrangler.cleanup.toml",
|
||||
"deploy:email": "wrangler deploy --config wrangler.email.json",
|
||||
"deploy:cleanup": "wrangler deploy --config wrangler.cleanup.json",
|
||||
"deploy:pages": "npm run build:pages && wrangler pages deploy .vercel/output/static --branch main"
|
||||
},
|
||||
"type": "module",
|
||||
@@ -60,6 +60,8 @@
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"bun": "^1.1.39",
|
||||
"cloudflare": "^4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"drizzle-kit": "^0.28.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.3",
|
||||
|
199
pnpm-lock.yaml
generated
199
pnpm-lock.yaml
generated
@@ -123,6 +123,12 @@ importers:
|
||||
bun:
|
||||
specifier: ^1.1.39
|
||||
version: 1.1.39
|
||||
cloudflare:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
dotenv:
|
||||
specifier: ^16.4.7
|
||||
version: 16.4.7
|
||||
drizzle-kit:
|
||||
specifier: ^0.28.1
|
||||
version: 0.28.1
|
||||
@@ -2226,12 +2232,18 @@ packages:
|
||||
'@types/next-pwa@5.6.9':
|
||||
resolution: {integrity: sha512-KcymH+MtFYB5KVKIOH1DMqd0wUb8VLCxzHtsaRQQ7S8sGOaTH24Lo2vGZf6/0Ok9e+xWCKhqsSt6cgDJTk91Iw==}
|
||||
|
||||
'@types/node-fetch@2.6.12':
|
||||
resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
|
||||
|
||||
'@types/node-forge@1.3.11':
|
||||
resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
|
||||
|
||||
'@types/node@16.18.11':
|
||||
resolution: {integrity: sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==}
|
||||
|
||||
'@types/node@18.19.78':
|
||||
resolution: {integrity: sha512-m1ilZCTwKLkk9rruBJXFeYN0Bc5SbjirwYX/Td3MqPfioYbgun3IvK/m8dQxMCnrPGZPg1kvXjp3SIekCN/ynw==}
|
||||
|
||||
'@types/node@20.12.14':
|
||||
resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==}
|
||||
|
||||
@@ -2429,6 +2441,10 @@ packages:
|
||||
abbrev@1.1.1:
|
||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
|
||||
acorn-import-attributes@1.9.5:
|
||||
resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==}
|
||||
peerDependencies:
|
||||
@@ -2452,6 +2468,10 @@ packages:
|
||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
|
||||
agentkeepalive@4.6.0:
|
||||
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
|
||||
ajv-keywords@3.5.2:
|
||||
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
|
||||
peerDependencies:
|
||||
@@ -2587,6 +2607,9 @@ packages:
|
||||
async@3.2.6:
|
||||
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
||||
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
at-least-node@1.0.0:
|
||||
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
||||
engines: {node: '>= 4.0.0'}
|
||||
@@ -2686,6 +2709,10 @@ packages:
|
||||
resolution: {integrity: sha512-CCKAP2tkPau7D3GE8+V8R6sQubA9R5foIzGp+85EXCVSCivuxBNAWqcpn72PKYiIcqoViv/kcUDpaEIMBVi1lQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
call-bind-apply-helpers@1.0.2:
|
||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
call-bind@1.0.8:
|
||||
resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2750,6 +2777,9 @@ packages:
|
||||
client-only@0.0.1:
|
||||
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
||||
|
||||
cloudflare@4.1.0:
|
||||
resolution: {integrity: sha512-TySwSEGGQhuVHFVjKRUHkzZum0MSGJkgfVjep+KBJxuxScEvjoTckQFbxlYThPp5kLm8IUi4C7oJeVr5e9etVw==}
|
||||
|
||||
clsx@2.1.1:
|
||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -2775,6 +2805,10 @@ packages:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
engines: {node: '>=12.5.0'}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
commander@11.1.0:
|
||||
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||
engines: {node: '>=16'}
|
||||
@@ -2913,6 +2947,10 @@ packages:
|
||||
resolution: {integrity: sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
delegates@1.0.0:
|
||||
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
||||
|
||||
@@ -2949,6 +2987,10 @@ packages:
|
||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
dotenv@16.4.7:
|
||||
resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
drizzle-kit@0.28.1:
|
||||
resolution: {integrity: sha512-JimOV+ystXTWMgZkLHYHf2w3oS28hxiH1FR0dkmJLc7GHzdGJoJAQtQS5DRppnabsRZwE2U1F6CuezVBgmsBBQ==}
|
||||
hasBin: true
|
||||
@@ -3049,6 +3091,10 @@ packages:
|
||||
resolution: {integrity: sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
@@ -3111,10 +3157,18 @@ packages:
|
||||
resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-set-tostringtag@2.0.3:
|
||||
resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-set-tostringtag@2.1.0:
|
||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-shim-unscopables@1.0.2:
|
||||
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
|
||||
|
||||
@@ -3532,6 +3586,10 @@ packages:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
events-intercept@2.0.0:
|
||||
resolution: {integrity: sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==}
|
||||
|
||||
@@ -3613,6 +3671,17 @@ packages:
|
||||
resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
form-data-encoder@1.7.2:
|
||||
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||
|
||||
form-data@4.0.2:
|
||||
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
formdata-node@4.4.1:
|
||||
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
||||
engines: {node: '>= 12.20'}
|
||||
|
||||
fs-extra@11.1.0:
|
||||
resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==}
|
||||
engines: {node: '>=14.14'}
|
||||
@@ -3666,6 +3735,10 @@ packages:
|
||||
resolution: {integrity: sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-intrinsic@1.3.0:
|
||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-nonce@1.0.1:
|
||||
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -3673,6 +3746,10 @@ packages:
|
||||
get-own-enumerable-property-symbols@3.0.2:
|
||||
resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==}
|
||||
|
||||
get-proto@1.0.1:
|
||||
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-source@2.0.12:
|
||||
resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
|
||||
|
||||
@@ -3780,6 +3857,9 @@ packages:
|
||||
resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
|
||||
engines: {node: '>=8.12.0'}
|
||||
|
||||
humanize-ms@1.2.1:
|
||||
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -4142,6 +4222,10 @@ packages:
|
||||
make-error@1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
|
||||
math-intrinsics@1.1.0:
|
||||
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
|
||||
@@ -4322,6 +4406,10 @@ packages:
|
||||
sass:
|
||||
optional: true
|
||||
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
|
||||
node-fetch@2.6.7:
|
||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
@@ -5394,6 +5482,10 @@ packages:
|
||||
resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3:
|
||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
web-vitals@0.2.4:
|
||||
resolution: {integrity: sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==}
|
||||
|
||||
@@ -7566,12 +7658,21 @@ snapshots:
|
||||
- sass
|
||||
- supports-color
|
||||
|
||||
'@types/node-fetch@2.6.12':
|
||||
dependencies:
|
||||
'@types/node': 20.17.9
|
||||
form-data: 4.0.2
|
||||
|
||||
'@types/node-forge@1.3.11':
|
||||
dependencies:
|
||||
'@types/node': 20.17.9
|
||||
|
||||
'@types/node@16.18.11': {}
|
||||
|
||||
'@types/node@18.19.78':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/node@20.12.14':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
@@ -7914,6 +8015,10 @@ snapshots:
|
||||
|
||||
abbrev@1.1.1: {}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
||||
acorn-import-attributes@1.9.5(acorn@8.14.0):
|
||||
dependencies:
|
||||
acorn: 8.14.0
|
||||
@@ -7934,6 +8039,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
agentkeepalive@4.6.0:
|
||||
dependencies:
|
||||
humanize-ms: 1.2.1
|
||||
|
||||
ajv-keywords@3.5.2(ajv@6.12.6):
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
@@ -8090,6 +8199,8 @@ snapshots:
|
||||
|
||||
async@3.2.6: {}
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
at-least-node@1.0.0: {}
|
||||
|
||||
available-typed-arrays@1.0.7:
|
||||
@@ -8201,6 +8312,11 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
|
||||
call-bind-apply-helpers@1.0.2:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
|
||||
call-bind@1.0.8:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.0
|
||||
@@ -8267,6 +8383,18 @@ snapshots:
|
||||
|
||||
client-only@0.0.1: {}
|
||||
|
||||
cloudflare@4.1.0:
|
||||
dependencies:
|
||||
'@types/node': 18.19.78
|
||||
'@types/node-fetch': 2.6.12
|
||||
abort-controller: 3.0.0
|
||||
agentkeepalive: 4.6.0
|
||||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
code-block-writer@10.1.1: {}
|
||||
@@ -8291,6 +8419,10 @@ snapshots:
|
||||
color-string: 1.9.1
|
||||
optional: true
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
commander@11.1.0: {}
|
||||
|
||||
commander@2.20.3: {}
|
||||
@@ -8365,7 +8497,7 @@ snapshots:
|
||||
|
||||
debug@4.1.1:
|
||||
dependencies:
|
||||
ms: 2.1.1
|
||||
ms: 2.1.3
|
||||
|
||||
debug@4.4.0:
|
||||
dependencies:
|
||||
@@ -8399,6 +8531,8 @@ snapshots:
|
||||
pify: 4.0.1
|
||||
rimraf: 2.7.1
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
delegates@1.0.0: {}
|
||||
|
||||
depd@1.1.2: {}
|
||||
@@ -8425,6 +8559,8 @@ snapshots:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
|
||||
dotenv@16.4.7: {}
|
||||
|
||||
drizzle-kit@0.28.1:
|
||||
dependencies:
|
||||
'@drizzle-team/brocli': 0.10.2
|
||||
@@ -8447,6 +8583,12 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
gopd: 1.2.0
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
es-errors: 1.3.0
|
||||
gopd: 1.2.0
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
edge-runtime@2.5.9:
|
||||
@@ -8565,12 +8707,23 @@ snapshots:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
||||
es-set-tostringtag@2.0.3:
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.5
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.2
|
||||
|
||||
es-set-tostringtag@2.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.2
|
||||
|
||||
es-shim-unscopables@1.0.2:
|
||||
dependencies:
|
||||
hasown: 2.0.2
|
||||
@@ -9050,6 +9203,8 @@ snapshots:
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
event-target-shim@5.0.1: {}
|
||||
|
||||
events-intercept@2.0.0: {}
|
||||
|
||||
events@3.3.0: {}
|
||||
@@ -9148,6 +9303,20 @@ snapshots:
|
||||
cross-spawn: 7.0.6
|
||||
signal-exit: 4.1.0
|
||||
|
||||
form-data-encoder@1.7.2: {}
|
||||
|
||||
form-data@4.0.2:
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
es-set-tostringtag: 2.1.0
|
||||
mime-types: 2.1.35
|
||||
|
||||
formdata-node@4.4.1:
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 4.0.0-beta.3
|
||||
|
||||
fs-extra@11.1.0:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@@ -9218,10 +9387,28 @@ snapshots:
|
||||
has-symbols: 1.1.0
|
||||
hasown: 2.0.2
|
||||
|
||||
get-intrinsic@1.3.0:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
es-define-property: 1.0.1
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
function-bind: 1.1.2
|
||||
get-proto: 1.0.1
|
||||
gopd: 1.2.0
|
||||
has-symbols: 1.1.0
|
||||
hasown: 2.0.2
|
||||
math-intrinsics: 1.1.0
|
||||
|
||||
get-nonce@1.0.1: {}
|
||||
|
||||
get-own-enumerable-property-symbols@3.0.2: {}
|
||||
|
||||
get-proto@1.0.1:
|
||||
dependencies:
|
||||
dunder-proto: 1.0.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
get-source@2.0.12:
|
||||
dependencies:
|
||||
data-uri-to-buffer: 2.0.2
|
||||
@@ -9349,6 +9536,10 @@ snapshots:
|
||||
|
||||
human-signals@1.1.1: {}
|
||||
|
||||
humanize-ms@1.2.1:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
@@ -9684,6 +9875,8 @@ snapshots:
|
||||
|
||||
make-error@1.3.6: {}
|
||||
|
||||
math-intrinsics@1.1.0: {}
|
||||
|
||||
merge-stream@2.0.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
@@ -9872,6 +10065,8 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-fetch@2.6.7:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
@@ -10982,6 +11177,8 @@ snapshots:
|
||||
glob-to-regexp: 0.4.1
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3: {}
|
||||
|
||||
web-vitals@0.2.4: {}
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
112
scripts/deploy/cloudflare.ts
Normal file
112
scripts/deploy/cloudflare.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import Cloudflare from "cloudflare";
|
||||
import "dotenv/config";
|
||||
|
||||
const CF_ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID!;
|
||||
const CF_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN;
|
||||
const PROJECT_URL = process.env.PROJECT_URL;
|
||||
const PROJECT_NAME = process.env.PROJECT_NAME || "moemail";
|
||||
const DB_NAME = process.env.DATABASE_NAME || "moemail-db";
|
||||
const KV_NAMESPACE_NAME = process.env.KV_NAME || "moemail-kv";
|
||||
|
||||
const client = new Cloudflare({
|
||||
apiKey: CF_API_TOKEN,
|
||||
});
|
||||
|
||||
export const getPages = async () => {
|
||||
try {
|
||||
const projectInfo = await client.pages.projects.get(PROJECT_NAME, {
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
});
|
||||
|
||||
return projectInfo;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createPages = async () => {
|
||||
try {
|
||||
console.log(`🆕 Creating new Cloudflare Pages project: "${PROJECT_NAME}"`);
|
||||
|
||||
const project = await client.pages.projects.create({
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
name: PROJECT_NAME,
|
||||
production_branch: "main",
|
||||
});
|
||||
|
||||
if (PROJECT_URL) {
|
||||
console.log("🔗 Setting pages domain...");
|
||||
|
||||
await client.pages.projects.domains.create(PROJECT_NAME, {
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
name: PROJECT_URL?.split("://")[1],
|
||||
});
|
||||
|
||||
console.log("✅ Pages domain set successfully");
|
||||
}
|
||||
|
||||
console.log("✅ Project created successfully");
|
||||
|
||||
return project;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getDatabase = async () => {
|
||||
try {
|
||||
const database = await client.d1.database.get(DB_NAME, {
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
});
|
||||
|
||||
return database;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createDatabase = async () => {
|
||||
try {
|
||||
console.log(`🆕 Creating new D1 database: "${DB_NAME}"`);
|
||||
const database = await client.d1.database.create({
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
name: DB_NAME,
|
||||
});
|
||||
console.log("✅ Database created successfully");
|
||||
|
||||
return database;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getKVNamespace = async (namespaceId: string) => {
|
||||
if (!namespaceId) {
|
||||
throw new Error("KV namespace ID is required");
|
||||
}
|
||||
|
||||
try {
|
||||
const kvNamespace = await client.kv.namespaces.get(namespaceId, {
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
});
|
||||
|
||||
return kvNamespace;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createKVNamespace = async () => {
|
||||
try {
|
||||
console.log(`🆕 Creating new KV namespace: "${KV_NAMESPACE_NAME}"`);
|
||||
const kvNamespace = await client.kv.namespaces.create({
|
||||
account_id: CF_ACCOUNT_ID,
|
||||
title: KV_NAMESPACE_NAME,
|
||||
});
|
||||
console.log("✅ KV namespace created successfully");
|
||||
|
||||
return kvNamespace;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
422
scripts/deploy/index.ts
Normal file
422
scripts/deploy/index.ts
Normal file
@@ -0,0 +1,422 @@
|
||||
import { NotFoundError } from "cloudflare";
|
||||
import "dotenv/config";
|
||||
import { execSync } from "node:child_process";
|
||||
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import {
|
||||
createDatabase,
|
||||
createKVNamespace,
|
||||
createPages,
|
||||
getDatabase,
|
||||
getKVNamespace,
|
||||
getPages,
|
||||
} from "./cloudflare";
|
||||
|
||||
const PROJECT_NAME = process.env.PROJECT_NAME || "moemail";
|
||||
const DATABASE_NAME = process.env.DATABASE_NAME || "moemail-db";
|
||||
const KV_NAMESPACE_NAME = process.env.KV_NAME || "moemail-kv";
|
||||
const PROJECT_URL = process.env.PROJECT_URL;
|
||||
const DATABASE_ID = process.env.DATABASE_ID || "";
|
||||
const KV_NAMESPACE_ID = process.env.KV_NAMESPACE_ID || "";
|
||||
|
||||
/**
|
||||
* 验证必要的环境变量
|
||||
*/
|
||||
const validateEnvironment = () => {
|
||||
const requiredEnvVars = ["CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"];
|
||||
const missing = requiredEnvVars.filter((varName) => !process.env[varName]);
|
||||
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
`Missing required environment variables: ${missing.join(", ")}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理JSON配置文件
|
||||
*/
|
||||
const setupConfigFile = (examplePath: string, targetPath: string) => {
|
||||
try {
|
||||
// 如果目标文件已存在,则跳过
|
||||
if (existsSync(targetPath)) {
|
||||
console.log(`✨ Configuration ${targetPath} already exists.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!existsSync(examplePath)) {
|
||||
console.log(`⚠️ Example file ${examplePath} does not exist, skipping...`);
|
||||
return;
|
||||
}
|
||||
|
||||
const configContent = readFileSync(examplePath, "utf-8");
|
||||
const json = JSON.parse(configContent);
|
||||
|
||||
// 处理数据库配置
|
||||
if (json.d1_databases && json.d1_databases.length > 0) {
|
||||
json.d1_databases[0].database_name = DATABASE_NAME;
|
||||
if (DATABASE_ID) {
|
||||
json.d1_databases[0].database_id = DATABASE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理KV配置
|
||||
if (json.kv_namespaces && json.kv_namespaces.length > 0 && KV_NAMESPACE_ID) {
|
||||
json.kv_namespaces[0].id = KV_NAMESPACE_ID;
|
||||
}
|
||||
|
||||
// 写入配置文件
|
||||
writeFileSync(targetPath, JSON.stringify(json, null, 2));
|
||||
console.log(`✅ Configuration ${targetPath} setup successfully.`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to setup ${targetPath}:`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置所有Wrangler配置文件
|
||||
*/
|
||||
const setupWranglerConfigs = () => {
|
||||
console.log("🔧 Setting up Wrangler configuration files...");
|
||||
|
||||
const configs = [
|
||||
{ example: "wrangler.example.json", target: "wrangler.json" },
|
||||
{ example: "wrangler.email.example.json", target: "wrangler.email.json" },
|
||||
{ example: "wrangler.cleanup.example.json", target: "wrangler.cleanup.json" },
|
||||
];
|
||||
|
||||
// 处理每个配置文件
|
||||
for (const config of configs) {
|
||||
setupConfigFile(
|
||||
resolve(config.example),
|
||||
resolve(config.target)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新数据库ID到所有配置文件
|
||||
*/
|
||||
const updateDatabaseConfig = (dbId: string) => {
|
||||
console.log(`📝 Updating database ID (${dbId}) in configurations...`);
|
||||
|
||||
// 更新环境变量
|
||||
updateEnvVar("DATABASE_ID", dbId);
|
||||
|
||||
// 更新所有配置文件
|
||||
const configFiles = [
|
||||
"wrangler.json",
|
||||
"wrangler.email.json",
|
||||
"wrangler.cleanup.json",
|
||||
];
|
||||
|
||||
for (const filename of configFiles) {
|
||||
const configPath = resolve(filename);
|
||||
if (!existsSync(configPath)) continue;
|
||||
|
||||
try {
|
||||
const json = JSON.parse(readFileSync(configPath, "utf-8"));
|
||||
if (json.d1_databases && json.d1_databases.length > 0) {
|
||||
json.d1_databases[0].database_id = dbId;
|
||||
}
|
||||
writeFileSync(configPath, JSON.stringify(json, null, 2));
|
||||
console.log(`✅ Updated database ID in ${filename}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to update ${filename}:`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新KV命名空间ID到所有配置文件
|
||||
*/
|
||||
const updateKVConfig = (namespaceId: string) => {
|
||||
console.log(`📝 Updating KV namespace ID (${namespaceId}) in configurations...`);
|
||||
|
||||
// 更新环境变量
|
||||
updateEnvVar("KV_NAMESPACE_ID", namespaceId);
|
||||
|
||||
// KV命名空间只在主wrangler.json中使用
|
||||
const wranglerPath = resolve("wrangler.json");
|
||||
if (existsSync(wranglerPath)) {
|
||||
try {
|
||||
const json = JSON.parse(readFileSync(wranglerPath, "utf-8"));
|
||||
if (json.kv_namespaces && json.kv_namespaces.length > 0) {
|
||||
json.kv_namespaces[0].id = namespaceId;
|
||||
}
|
||||
writeFileSync(wranglerPath, JSON.stringify(json, null, 2));
|
||||
console.log(`✅ Updated KV namespace ID in wrangler.json`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to update wrangler.json:`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查并创建数据库
|
||||
*/
|
||||
const checkAndCreateDatabase = async () => {
|
||||
console.log(`🔍 Checking if database "${DATABASE_NAME}" exists...`);
|
||||
|
||||
try {
|
||||
const database = await getDatabase();
|
||||
|
||||
if (!database || !database.uuid) {
|
||||
throw new Error('Database object is missing a valid UUID');
|
||||
}
|
||||
|
||||
updateDatabaseConfig(database.uuid);
|
||||
console.log(`✅ Database "${DATABASE_NAME}" already exists (ID: ${database.uuid})`);
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) {
|
||||
console.log(`⚠️ Database not found, creating new database...`);
|
||||
try {
|
||||
const database = await createDatabase();
|
||||
|
||||
if (!database || !database.uuid) {
|
||||
throw new Error('Database object is missing a valid UUID');
|
||||
}
|
||||
|
||||
updateDatabaseConfig(database.uuid);
|
||||
console.log(`✅ Database "${DATABASE_NAME}" created successfully (ID: ${database.uuid})`);
|
||||
} catch (createError) {
|
||||
console.error(`❌ Failed to create database:`, createError);
|
||||
throw createError;
|
||||
}
|
||||
} else {
|
||||
console.error(`❌ An error occurred while checking the database:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 迁移数据库
|
||||
*/
|
||||
const migrateDatabase = () => {
|
||||
console.log("📝 Migrating remote database...");
|
||||
try {
|
||||
execSync("pnpm run db:migrate-remote", { stdio: "inherit" });
|
||||
console.log("✅ Database migration completed successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Database migration failed:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查并创建KV命名空间
|
||||
*/
|
||||
const checkAndCreateKVNamespace = async () => {
|
||||
console.log(`🔍 Checking if KV namespace "${KV_NAMESPACE_NAME}" exists...`);
|
||||
|
||||
try {
|
||||
if (!KV_NAMESPACE_ID) {
|
||||
console.log("⚠️ KV_NAMESPACE_ID is not set, creating a new KV namespace...");
|
||||
const namespace = await createKVNamespace();
|
||||
updateKVConfig(namespace.id);
|
||||
console.log(`✅ KV namespace "${KV_NAMESPACE_NAME}" created successfully (ID: ${namespace.id})`);
|
||||
return;
|
||||
}
|
||||
|
||||
const namespace = await getKVNamespace(KV_NAMESPACE_ID);
|
||||
console.log(`✅ KV namespace "${KV_NAMESPACE_NAME}" already exists (ID: ${namespace.id})`);
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError || (error instanceof Error && error.message?.includes("required"))) {
|
||||
console.log(`⚠️ KV namespace not found or invalid, creating new KV namespace...`);
|
||||
try {
|
||||
const namespace = await createKVNamespace();
|
||||
updateKVConfig(namespace.id);
|
||||
console.log(`✅ KV namespace "${KV_NAMESPACE_NAME}" created successfully (ID: ${namespace.id})`);
|
||||
} catch (createError) {
|
||||
console.error(`❌ Failed to create KV namespace:`, createError);
|
||||
throw createError;
|
||||
}
|
||||
} else {
|
||||
console.error(`❌ An error occurred while checking the KV namespace:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查并创建Pages项目
|
||||
*/
|
||||
const checkAndCreatePages = async () => {
|
||||
console.log(`🔍 Checking if project "${PROJECT_NAME}" exists...`);
|
||||
|
||||
try {
|
||||
await getPages();
|
||||
console.log("✅ Project already exists, proceeding with update...");
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) {
|
||||
console.log("⚠️ Project not found, creating new project...");
|
||||
const pages = await createPages();
|
||||
|
||||
if (!PROJECT_URL && pages.subdomain) {
|
||||
console.log("⚠️ PROJECT_URL is empty, using pages default domain...");
|
||||
console.log("📝 Updating environment variables...");
|
||||
|
||||
// 更新环境变量为默认的Pages域名
|
||||
const appUrl = `https://${pages.subdomain}`;
|
||||
updateEnvVar("PROJECT_URL", appUrl);
|
||||
}
|
||||
} else {
|
||||
console.error(`❌ An error occurred while checking the project:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 推送Pages密钥
|
||||
*/
|
||||
const pushPagesSecret = () => {
|
||||
console.log("🔐 Pushing environment secrets to Pages...");
|
||||
|
||||
try {
|
||||
// 确保.env文件存在
|
||||
if (!existsSync(resolve('.env'))) {
|
||||
setupEnvFile();
|
||||
}
|
||||
|
||||
execSync(`pnpm dlx wrangler pages secret bulk .env`, { stdio: "inherit" });
|
||||
console.log("✅ Secrets pushed successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Failed to push secrets:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 部署Pages应用
|
||||
*/
|
||||
const deployPages = () => {
|
||||
console.log("🚧 Deploying to Cloudflare Pages...");
|
||||
try {
|
||||
execSync("pnpm run build:pages && pnpm dlx wrangler pages deploy .vercel/output/static --branch main", { stdio: "inherit" });
|
||||
console.log("✅ Pages deployment completed successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Pages deployment failed:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 部署Email Worker
|
||||
*/
|
||||
const deployEmailWorker = () => {
|
||||
console.log("🚧 Deploying Email Worker...");
|
||||
try {
|
||||
execSync("pnpm dlx wrangler deploy --config wrangler.email.json", { stdio: "inherit" });
|
||||
console.log("✅ Email Worker deployed successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Email Worker deployment failed:", error);
|
||||
// 继续执行而不中断
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 部署Cleanup Worker
|
||||
*/
|
||||
const deployCleanupWorker = () => {
|
||||
console.log("🚧 Deploying Cleanup Worker...");
|
||||
try {
|
||||
execSync("pnpm dlx wrangler deploy --config wrangler.cleanup.json", { stdio: "inherit" });
|
||||
console.log("✅ Cleanup Worker deployed successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Cleanup Worker deployment failed:", error);
|
||||
// 继续执行而不中断
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建或更新环境变量文件
|
||||
*/
|
||||
const setupEnvFile = () => {
|
||||
console.log("📄 Setting up environment file...");
|
||||
const envFilePath = resolve(".env");
|
||||
const envExamplePath = resolve(".env.example");
|
||||
|
||||
// 如果.env文件不存在,则从.env.example复制创建
|
||||
if (!existsSync(envFilePath) && existsSync(envExamplePath)) {
|
||||
console.log("⚠️ .env file does not exist, creating from example...");
|
||||
|
||||
// 从示例文件复制
|
||||
let envContent = readFileSync(envExamplePath, "utf-8");
|
||||
|
||||
// 填充当前的环境变量
|
||||
const envVarMatches = envContent.match(/^([A-Z_]+)\s*=\s*".*?"/gm);
|
||||
if (envVarMatches) {
|
||||
for (const match of envVarMatches) {
|
||||
const varName = match.split("=")[0].trim();
|
||||
if (process.env[varName]) {
|
||||
const regex = new RegExp(`${varName}\\s*=\\s*".*?"`, "g");
|
||||
envContent = envContent.replace(regex, `${varName} = "${process.env[varName]}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(envFilePath, envContent);
|
||||
console.log("✅ .env file created from example");
|
||||
} else if (existsSync(envFilePath)) {
|
||||
console.log("✨ .env file already exists");
|
||||
} else {
|
||||
console.error("❌ .env.example file not found!");
|
||||
throw new Error(".env.example file not found");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新环境变量
|
||||
*/
|
||||
const updateEnvVar = (name: string, value: string) => {
|
||||
// 首先更新进程环境变量
|
||||
process.env[name] = value;
|
||||
|
||||
// 然后尝试更新.env文件
|
||||
const envFilePath = resolve(".env");
|
||||
if (!existsSync(envFilePath)) {
|
||||
setupEnvFile();
|
||||
}
|
||||
|
||||
let envContent = readFileSync(envFilePath, "utf-8");
|
||||
const regex = new RegExp(`^${name}\\s*=\\s*".*?"`, "m");
|
||||
|
||||
if (envContent.match(regex)) {
|
||||
envContent = envContent.replace(regex, `${name} = "${value}"`);
|
||||
} else {
|
||||
envContent += `\n${name} = "${value}"`;
|
||||
}
|
||||
|
||||
writeFileSync(envFilePath, envContent);
|
||||
console.log(`✅ Updated ${name} in .env file`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 主函数
|
||||
*/
|
||||
const main = async () => {
|
||||
try {
|
||||
console.log("🚀 Starting deployment process...");
|
||||
validateEnvironment();
|
||||
setupEnvFile();
|
||||
setupWranglerConfigs();
|
||||
await checkAndCreateDatabase();
|
||||
migrateDatabase();
|
||||
await checkAndCreateKVNamespace();
|
||||
await checkAndCreatePages();
|
||||
pushPagesSecret();
|
||||
deployPages();
|
||||
deployEmailWorker();
|
||||
deployCleanupWorker();
|
||||
|
||||
console.log("🎉 Deployment completed successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Deployment failed:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
18
wrangler.cleanup.example.json
Normal file
18
wrangler.cleanup.example.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "cleanup-worker",
|
||||
"main": "workers/cleanup.ts",
|
||||
"compatibility_date": "2024-03-20",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
"triggers": {
|
||||
"crons": ["0 * * * *"]
|
||||
},
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"migrations_dir": "drizzle",
|
||||
"database_name": "${DATABASE_NAME}",
|
||||
"database_id": "${DATABASE_ID}"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
name = "cleanup-worker"
|
||||
main = "workers/cleanup.ts"
|
||||
compatibility_date = "2024-03-20"
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
|
||||
# 每 1 小时运行一次
|
||||
[triggers]
|
||||
crons = ["0 * * * *"]
|
||||
|
||||
[[d1_databases]]
|
||||
binding = "DB"
|
||||
migrations_dir = "drizzle"
|
||||
database_name = ""
|
||||
database_id = ""
|
15
wrangler.email.example.json
Normal file
15
wrangler.email.example.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "email-receiver-worker",
|
||||
"compatibility_date": "2024-03-20",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
"main": "workers/email-receiver.ts",
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"migrations_dir": "drizzle",
|
||||
"database_name": "${DATABASE_NAME}",
|
||||
"database_id": "${DATABASE_ID}"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
name = "email-receiver-worker"
|
||||
compatibility_date = "2024-03-20"
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
main = "workers/email-receiver.ts"
|
||||
|
||||
|
||||
[[d1_databases]]
|
||||
binding = "DB"
|
||||
migrations_dir = "drizzle"
|
||||
database_name = ""
|
||||
database_id = ""
|
21
wrangler.example.json
Normal file
21
wrangler.example.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "moemail",
|
||||
"compatibility_date": "2024-03-20",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
"pages_build_output_dir": ".vercel/output/static",
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "${DATABASE_NAME}",
|
||||
"database_id": "${DATABASE_ID}",
|
||||
"migrations_dir": "drizzle"
|
||||
}
|
||||
],
|
||||
"kv_namespaces": [
|
||||
{
|
||||
"binding": "SITE_CONFIG",
|
||||
"id": "${KV_NAMESPACE_ID}"
|
||||
}
|
||||
]
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
name = "moemail"
|
||||
compatibility_date = "2024-03-20"
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
pages_build_output_dir = ".vercel/output/static"
|
||||
|
||||
[[d1_databases]]
|
||||
binding = "DB"
|
||||
migrations_dir = "drizzle"
|
||||
database_name = ""
|
||||
database_id = ""
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "SITE_CONFIG"
|
||||
id = ""
|
Reference in New Issue
Block a user