feature: add /user_api/mails with filter params address and keyword (#639)

This commit is contained in:
Dream Hunter
2025-04-24 02:01:21 +08:00
committed by GitHub
parent c6afc5d425
commit 95f361743b
19 changed files with 1124 additions and 887 deletions

View File

@@ -1,7 +1,11 @@
<!-- markdownlint-disable-file MD004 MD024 MD034 MD036 -->
# CHANGE LOG
## main(v0.9.1)
## v0.10.0
- feat: 支持 User 查看收件箱,`/user_api/mails` 接口, 支持 `address``keyword` 过滤
## v0.9.1
- feat: |UI| support google ads
- feat: |UI| 使用 shadow DOM 防止样式污染

View File

@@ -1,6 +1,6 @@
{
"name": "cloudflare_temp_email",
"version": "0.9.1",
"version": "0.10.9",
"private": true,
"type": "module",
"scripts": {
@@ -40,13 +40,13 @@
"@vicons/material": "^0.13.0",
"@vitejs/plugin-vue": "^5.2.3",
"unplugin-auto-import": "^19.1.2",
"unplugin-vue-components": "^28.4.1",
"vite": "^6.2.6",
"unplugin-vue-components": "^28.5.0",
"vite": "^6.3.2",
"vite-plugin-pwa": "^1.0.0",
"vite-plugin-top-level-await": "^1.5.0",
"vite-plugin-wasm": "^3.4.1",
"workbox-build": "^7.3.0",
"workbox-window": "^7.3.0",
"wrangler": "^4.10.0"
"wrangler": "^4.13.0"
}
}

565
frontend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ import AddressMangement from './user/AddressManagement.vue';
import UserSettingsPage from './user/UserSettings.vue';
import UserBar from './user/UserBar.vue';
import BindAddress from './user/BindAddress.vue';
import UserMailBox from './user/UserMailBox.vue';
const {
userTab, globalTabplacement, userSettings
@@ -16,11 +17,13 @@ const { t } = useI18n({
messages: {
en: {
address_management: 'Address Management',
user_mail_box_tab: 'Mail Box',
user_settings: 'User Settings',
bind_address: 'Bind Mail Address',
},
zh: {
address_management: '地址管理',
user_mail_box_tab: '收件箱',
user_settings: '用户设置',
bind_address: '绑定邮箱地址',
}
@@ -36,6 +39,9 @@ const { t } = useI18n({
<n-tab-pane name="address_management" :tab="t('address_management')">
<AddressMangement />
</n-tab-pane>
<n-tab-pane name="user_mail_box_tab" :tab="t('user_mail_box_tab')">
<UserMailBox />
</n-tab-pane>
<n-tab-pane name="user_settings" :tab="t('user_settings')">
<UserSettingsPage />
</n-tab-pane>

View File

@@ -0,0 +1,90 @@
<script setup>
import { onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'
import { api } from '../../api'
import MailBox from '../../components/MailBox.vue';
const { t } = useI18n({
messages: {
en: {
addressQueryTip: 'Leave blank to query all addresses',
keywordQueryTip: 'Leave blank to not query by keyword',
query: 'Query',
},
zh: {
addressQueryTip: '留空查询所有地址',
keywordQueryTip: '留空不按关键字查询',
query: '查询',
}
}
});
const mailBoxKey = ref("")
const addressFilter = ref();
const mailKeyword = ref("")
const addressFilterOptions = ref([]);
const queryMail = () => {
addressFilter.value = addressFilter.value.trim();
mailKeyword.value = mailKeyword.value.trim();
mailBoxKey.value = Date.now();
}
const fetchMailData = async (limit, offset) => {
return await api.fetch(
`/user_api/mails`
+ `?limit=${limit}`
+ `&offset=${offset}`
+ (addressFilter.value ? `&address=${addressFilter.value}` : '')
+ (mailKeyword.value ? `&keyword=${mailKeyword.value}` : '')
);
}
const fetchAddresData = async () => {
try {
const { results } = await api.fetch(
`/user_api/bind_address`
);
addressFilterOptions.value = results.map((item) => {
return {
label: item.name,
value: item.name
}
});
} catch (error) {
console.log(error)
message.error(error.message || "error");
}
}
const deleteMail = async (curMailId) => {
await api.fetch(`/user_api/mails/${curMailId}`, { method: 'DELETE' });
};
watch(addressFilter, async (newValue) => {
console.log("addressFilter", newValue);
queryMail();
});
onMounted(() => {
fetchAddresData();
});
</script>
<template>
<div style="margin-top: 10px;">
<n-input-group>
<n-select v-model:value="addressFilter" :options="addressFilterOptions" clearable
:placeholder="t('addressQueryTip')" />
<n-input v-model:value="mailKeyword" :placeholder="t('keywordQueryTip')" @keydown.enter="queryMail" />
<n-button @click="queryMail" type="primary" tertiary>
{{ t('query') }}
</n-button>
</n-input-group>
<div style="margin-top: 10px;"></div>
<MailBox :key="mailBoxKey" :enableUserDeleteEmail="true" :fetchMailData="fetchMailData"
:deleteMail="deleteMail" />
</div>
</template>

View File

@@ -1,6 +1,6 @@
{
"name": "temp-email-pages",
"version": "0.9.1",
"version": "0.10.9",
"description": "",
"main": "index.js",
"scripts": {
@@ -11,6 +11,6 @@
"author": "",
"license": "ISC",
"devDependencies": {
"wrangler": "^4.10.0"
"wrangler": "^4.13.0"
}
}

View File

@@ -1,6 +1,6 @@
# 查看邮件 API
## 通过 HTTP API 查看邮件
## 通过 邮件 API 查看邮件
这是一个 `python` 的例子,使用 `requests` 库查看邮件。
@@ -8,7 +8,7 @@
limit = 10
offset = 0
res = requests.get(
f"http://localhost:8787/api/mails?limit={limit}&offset={offset}",
f"https://<你的worker地址>/api/mails?limit={limit}&offset={offset}",
headers={
"Authorization": f"Bearer {你的JWT密码}",
# "x-custom-auth": "<你的网站密码>", # 如果启用了自定义密码
@@ -16,3 +16,51 @@ res = requests.get(
}
)
```
## admin 邮件 API
支持 `address` filter 和 `keyword` filter
```python
import requests
url = "https://<你的worker地址>/admin/mails"
querystring = {
"limit":"20",
"offset":"0",
# adress 和 keyword 为可选参数
"address":"xxxx@awsl.uk",
"keyword":"xxxx"
}
headers = {"x-admin-auth": "<你的Admin密码>"}
response = requests.get(url, headers=headers, params=querystring)
print(response.json())
```
## user 邮件 API
支持 `address` filter 和 `keyword` filter
```python
import requests
url = "https://<你的worker地址>/user_api/mails"
querystring = {
"limit":"20",
"offset":"0",
# adress 和 keyword 为可选参数
"address":"xxxx@awsl.uk",
"keyword":"xxxx"
}
headers = {"x-admin-auth": "<你的Admin密码>"}
response = requests.get(url, headers=headers, params=querystring)
print(response.json())
```

View File

@@ -1,12 +1,12 @@
{
"name": "temp-mail-docs",
"private": true,
"version": "0.9.1",
"version": "0.10.9",
"type": "module",
"devDependencies": {
"@types/node": "^22.14.1",
"vitepress": "^1.6.3",
"wrangler": "^4.10.0"
"wrangler": "^4.13.0"
},
"scripts": {
"dev": "vitepress dev docs",

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cloudflare_temp_email",
"version": "0.9.1",
"version": "0.10.9",
"private": true,
"type": "module",
"scripts": {
@@ -11,25 +11,25 @@
"build": "wrangler deploy --dry-run --outdir dist --minify"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250412.0",
"@cloudflare/workers-types": "^4.20250423.0",
"@eslint/js": "9.18.0",
"@simplewebauthn/types": "10.0.0",
"eslint": "9.18.0",
"globals": "^15.15.0",
"typescript-eslint": "^8.29.1",
"wrangler": "^4.10.0"
"typescript-eslint": "^8.31.0",
"wrangler": "^4.13.0"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.787.0",
"@aws-sdk/s3-request-presigner": "^3.787.0",
"@simplewebauthn/server": "10.0.1",
"hono": "^4.7.6",
"hono": "^4.7.7",
"jsonpath-plus": "^10.3.0",
"mimetext": "^3.0.27",
"postal-mime": "^2.4.3",
"resend": "^4.2.0",
"resend": "^4.4.0",
"telegraf": "4.16.3",
"worker-mailer": "^1.1.1"
"worker-mailer": "^1.1.3"
},
"pnpm": {
"patchedDependencies": {

478
worker/pnpm-lock.yaml generated
View File

@@ -23,8 +23,8 @@ importers:
specifier: 10.0.1
version: 10.0.1
hono:
specifier: ^4.7.6
version: 4.7.6
specifier: ^4.7.7
version: 4.7.7
jsonpath-plus:
specifier: ^10.3.0
version: 10.3.0
@@ -35,18 +35,18 @@ importers:
specifier: ^2.4.3
version: 2.4.3
resend:
specifier: ^4.2.0
version: 4.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
specifier: ^4.4.0
version: 4.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
telegraf:
specifier: 4.16.3
version: 4.16.3(patch_hash=7d0a1784bb35f50fee25f26a14017734b9461612c635e71734b59527280c9563)
worker-mailer:
specifier: ^1.1.1
version: 1.1.1
specifier: ^1.1.3
version: 1.1.3
devDependencies:
'@cloudflare/workers-types':
specifier: ^4.20250412.0
version: 4.20250412.0
specifier: ^4.20250423.0
version: 4.20250423.0
'@eslint/js':
specifier: 9.18.0
version: 9.18.0
@@ -60,11 +60,11 @@ importers:
specifier: ^15.15.0
version: 15.15.0
typescript-eslint:
specifier: ^8.29.1
version: 8.29.1(eslint@9.18.0)(typescript@5.4.5)
specifier: ^8.31.0
version: 8.31.0(eslint@9.18.0)(typescript@5.4.5)
wrangler:
specifier: ^4.10.0
version: 4.10.0(@cloudflare/workers-types@4.20250412.0)
specifier: ^4.13.0
version: 4.13.0(@cloudflare/workers-types@4.20250423.0)
packages:
@@ -248,198 +248,198 @@ packages:
workerd:
optional: true
'@cloudflare/workerd-darwin-64@1.20250409.0':
resolution: {integrity: sha512-smA9yq77xsdQ1NMLhFz3JZxMHGd01lg0bE+X3dTFmIUs+hHskJ+HJ/IkMFInkCCeEFlUkoL4yO7ilaU/fin/xA==}
'@cloudflare/workerd-darwin-64@1.20250422.0':
resolution: {integrity: sha512-2FWl8TLpC4Knuyw8GmNgUSoJCNJNNGJ7Xv90j2n8FiXR5Clp9jSpm2ovK8RP9P751yX1/iIp8e7QufR/XDB6ow==}
engines: {node: '>=16'}
cpu: [x64]
os: [darwin]
'@cloudflare/workerd-darwin-arm64@1.20250409.0':
resolution: {integrity: sha512-oLVcf+Y5Qun8JHcy1VcR/YnbA5U2ne0czh3XNhDqdHZFK8+vKeC7MnVPX+kEqQA3+uLcMM1/FsIDU1U4Na0h1g==}
'@cloudflare/workerd-darwin-arm64@1.20250422.0':
resolution: {integrity: sha512-GY3W74ivqxsYldacEbMtcSbG7LsS9hPo5UybKIw4RO9GzP7UC5WGnPfuI4PE2SnJOnw7nwSrBLuhGRPe/QQHkQ==}
engines: {node: '>=16'}
cpu: [arm64]
os: [darwin]
'@cloudflare/workerd-linux-64@1.20250409.0':
resolution: {integrity: sha512-D31B4kdC3a0RD5yfpdIa89//kGHbYsYihZmejm1k4S4NHOho3MUDHAEh4aHtafQNXbZdydGHlSyiVYjTdQ9ILQ==}
'@cloudflare/workerd-linux-64@1.20250422.0':
resolution: {integrity: sha512-mtNkEygKtlRq9pMRlm9J4nX4uVHU1AtJ3mSkdNwPwhisTpo989O5Zd0SH9CYwAk8+NmlZsXELpODUVQxQ7FJgw==}
engines: {node: '>=16'}
cpu: [x64]
os: [linux]
'@cloudflare/workerd-linux-arm64@1.20250409.0':
resolution: {integrity: sha512-Sr59P0TREayil5OQ7kcbjuIn6L6OTSRLI91LKu0D8vi1hss2q9FUwBcwxg0+Yd/x+ty/x7IISiAK5QBkAMeITQ==}
'@cloudflare/workerd-linux-arm64@1.20250422.0':
resolution: {integrity: sha512-ILlW4/kAoFJvSryrr/QJsiHBdMTf/fjUrIM0hxeuQue8zIEvAVqM1tzpUh8bPJT6AQEbk5ziwkfucA939Z6Tnw==}
engines: {node: '>=16'}
cpu: [arm64]
os: [linux]
'@cloudflare/workerd-windows-64@1.20250409.0':
resolution: {integrity: sha512-dK9I8zBX5rR7MtaaP2AhICQTEw3PVzHcsltN8o46w7JsbYlMvFOj27FfYH5dhs3IahgmIfw2e572QXW2o/dbpg==}
'@cloudflare/workerd-windows-64@1.20250422.0':
resolution: {integrity: sha512-O2f6f7oxU/oaWX/3/5d/9qvzNSKsw72RsQFjpew2va7KwnnUciI2LnbYR6KYOqRGYrEoiMJxpWPQaYaFVj8t1w==}
engines: {node: '>=16'}
cpu: [x64]
os: [win32]
'@cloudflare/workers-types@4.20250412.0':
resolution: {integrity: sha512-ukQE+TRc5HNkM6VvGfTNC9x54TLQKjdcm624F8Qh1ZRe0iJrW2/j1eYgvJABJPexDousYCR7VzCGteShLcBJYQ==}
'@cloudflare/workers-types@4.20250423.0':
resolution: {integrity: sha512-uzy7fvgYIs9YCEaPScC+RnZvd+yJJCqLCEe/n/6p2PZTxWbDmiZjtJQiP5Zx6G0p64ZD/0ZRmtALfDZDNYBDHg==}
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
'@emnapi/runtime@1.4.1':
resolution: {integrity: sha512-LMshMVP0ZhACNjQNYXiU1iZJ6QCcv0lUdPDPugqGvCGXt5xtRVBPdtA0qU12pEXZzpWAhWlZYptfdAFq10DOVQ==}
'@emnapi/runtime@1.4.3':
resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
'@esbuild/aix-ppc64@0.24.2':
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
'@esbuild/aix-ppc64@0.25.2':
resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.24.2':
resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
'@esbuild/android-arm64@0.25.2':
resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.24.2':
resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
'@esbuild/android-arm@0.25.2':
resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.24.2':
resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
'@esbuild/android-x64@0.25.2':
resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.24.2':
resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
'@esbuild/darwin-arm64@0.25.2':
resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.24.2':
resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
'@esbuild/darwin-x64@0.25.2':
resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.24.2':
resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
'@esbuild/freebsd-arm64@0.25.2':
resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.24.2':
resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
'@esbuild/freebsd-x64@0.25.2':
resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.24.2':
resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
'@esbuild/linux-arm64@0.25.2':
resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.24.2':
resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
'@esbuild/linux-arm@0.25.2':
resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.24.2':
resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
'@esbuild/linux-ia32@0.25.2':
resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.24.2':
resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
'@esbuild/linux-loong64@0.25.2':
resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.24.2':
resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
'@esbuild/linux-mips64el@0.25.2':
resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.24.2':
resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
'@esbuild/linux-ppc64@0.25.2':
resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.24.2':
resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
'@esbuild/linux-riscv64@0.25.2':
resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.24.2':
resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
'@esbuild/linux-s390x@0.25.2':
resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.24.2':
resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
'@esbuild/linux-x64@0.25.2':
resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.24.2':
resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
'@esbuild/netbsd-arm64@0.25.2':
resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.24.2':
resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
'@esbuild/netbsd-x64@0.25.2':
resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.24.2':
resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
'@esbuild/openbsd-arm64@0.25.2':
resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.24.2':
resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
'@esbuild/openbsd-x64@0.25.2':
resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.24.2':
resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
'@esbuild/sunos-x64@0.25.2':
resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.24.2':
resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
'@esbuild/win32-arm64@0.25.2':
resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.24.2':
resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
'@esbuild/win32-ia32@0.25.2':
resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.24.2':
resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
'@esbuild/win32-x64@0.25.2':
resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@eslint-community/eslint-utils@4.5.1':
resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
'@eslint-community/eslint-utils@4.6.1':
resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
@@ -660,8 +660,8 @@ packages:
'@peculiar/asn1-x509@2.3.15':
resolution: {integrity: sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==}
'@react-email/render@1.0.5':
resolution: {integrity: sha512-CA69HYXPk21HhtAXATIr+9JJwpDNmAFCvdMUjWmeoD1+KhJ9NAxusMRxKNeibdZdslmq3edaeOKGbdQ9qjK8LQ==}
'@react-email/render@1.0.6':
resolution: {integrity: sha512-zNueW5Wn/4jNC1c5LFgXzbUdv5Lhms+FWjOvWAhal7gx5YVf0q6dPJ0dnR70+ifo59gcMLwCZEaTS9EEuUhKvQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
react: ^18.0 || ^19.0 || ^19.0.0-rc
@@ -898,51 +898,51 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@typescript-eslint/eslint-plugin@8.29.1':
resolution: {integrity: sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==}
'@typescript-eslint/eslint-plugin@8.31.0':
resolution: {integrity: sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/parser@8.29.1':
resolution: {integrity: sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==}
'@typescript-eslint/parser@8.31.0':
resolution: {integrity: sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/scope-manager@8.29.1':
resolution: {integrity: sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==}
'@typescript-eslint/scope-manager@8.31.0':
resolution: {integrity: sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.29.1':
resolution: {integrity: sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==}
'@typescript-eslint/type-utils@8.31.0':
resolution: {integrity: sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/types@8.29.1':
resolution: {integrity: sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==}
'@typescript-eslint/types@8.31.0':
resolution: {integrity: sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.29.1':
resolution: {integrity: sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==}
'@typescript-eslint/typescript-estree@8.31.0':
resolution: {integrity: sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/utils@8.29.1':
resolution: {integrity: sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==}
'@typescript-eslint/utils@8.31.0':
resolution: {integrity: sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/visitor-keys@8.29.1':
resolution: {integrity: sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==}
'@typescript-eslint/visitor-keys@8.31.0':
resolution: {integrity: sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
abort-controller@3.0.0:
@@ -1074,8 +1074,8 @@ packages:
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
detect-libc@2.0.3:
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
detect-libc@2.0.4:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'}
dom-serializer@2.0.0:
@@ -1095,8 +1095,8 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
esbuild@0.24.2:
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
esbuild@0.25.2:
resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==}
engines: {node: '>=18'}
hasBin: true
@@ -1154,8 +1154,8 @@ packages:
resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
engines: {node: '>=6'}
exsolve@1.0.4:
resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==}
exsolve@1.0.5:
resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==}
fast-deep-equal@2.0.1:
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
@@ -1233,8 +1233,8 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
hono@4.7.6:
resolution: {integrity: sha512-564rVzELU+9BRqqx5k8sT2NFwGD3I3Vifdb6P7CmM6FiarOSY+fDC+6B+k9wcCb86ReoayteZP2ki0cRLN1jbw==}
hono@4.7.7:
resolution: {integrity: sha512-2PCpQRbN87Crty8/L/7akZN3UyZIAopSoRxCwRbJgUuV1+MHNFHzYFxZTg4v/03cXUm+jce/qa2VSBZpKBm3Qw==}
engines: {node: '>=16.9.0'}
html-to-text@9.0.5:
@@ -1347,8 +1347,8 @@ packages:
mimetext@3.0.27:
resolution: {integrity: sha512-mUhWAsZD1N/K6dbN4+a5Yq78OPnYQw1ubOSMasBntsLQ2S7KVNlvDEA8dwpr4a7PszWMzeslKahAprtwYMgaBA==}
miniflare@4.20250409.0:
resolution: {integrity: sha512-Hu02dYZvFR+MyrI57O6rSrOUTofcO9EIvcodgq2SAHzAeWSJw2E0oq9lylOrcckFwPMcwxUAb/cQN1LIoCyySw==}
miniflare@4.20250422.0:
resolution: {integrity: sha512-3frXK9EZEWQkHMDyppeIbUKwd7OQkNOm2gBtQQzjQ4gtzQmh+yxkyJiiylf+fGbz86djQTLKKQdQ1FC4yM3AMg==}
engines: {node: '>=18.0.0'}
hasBin: true
@@ -1436,8 +1436,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier@3.4.2:
resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==}
prettier@3.5.3:
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
hasBin: true
@@ -1473,8 +1473,8 @@ packages:
regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
resend@4.2.0:
resolution: {integrity: sha512-s6ogU+BBYH1H6Zl926cpddtLRAJWeFv5cIKcuHLWk1QYhFTbpFJlhqx31pnN2f0CB075KFSrc1Xf6HG690wzuw==}
resend@4.4.0:
resolution: {integrity: sha512-SmVI3JCpgPNt4/m3Uy403LjoSeeleUE2X+KwPYQZcw+jiBCFsqL6vdf1r/XuQ7yOjvxYmlI8GD/oIWonFF9t9w==}
engines: {node: '>=18'}
resolve-from@4.0.0:
@@ -1568,8 +1568,8 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
typescript-eslint@8.29.1:
resolution: {integrity: sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w==}
typescript-eslint@8.31.0:
resolution: {integrity: sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1612,20 +1612,20 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
worker-mailer@1.1.1:
resolution: {integrity: sha512-UPPd48aBMVuAE2j9ha7wDEhBakM23zKBk8wd9lLUhChExPeq8B8cO6C1ur4hMOypmJO7mZ+xTZff1KoCKprvGA==}
worker-mailer@1.1.3:
resolution: {integrity: sha512-8jkbf843tAV9KMWQESrduMt6LKolYXJ9rmWO0W8ZM3CW0Mb+qaVaktXhqvAo7cLvYnYSxYBS8oJl0pgr75XipQ==}
workerd@1.20250409.0:
resolution: {integrity: sha512-hqjX9swiHvrkOI3jlH9lrZsZRRv9lddUwcMe8Ua76jnyQz+brybWznNjHu8U5oswwcrFwvky1A4CcLjcLY31gQ==}
workerd@1.20250422.0:
resolution: {integrity: sha512-q3ws6MIa9GJQqq1Q52qoD7vCx1203fjKNPmtRV1vvplrsfYphjr5pOAnZGUODFB1BnsDWypr71Luy7OonT0vug==}
engines: {node: '>=16'}
hasBin: true
wrangler@4.10.0:
resolution: {integrity: sha512-fTE4hZ79msEUt8+HEjl/8Q72haCyzPLu4PgrU3L81ysmjrMEdiYfUPqnvCkBUVtJvrDNdctTEimkufT1Y0ipNg==}
wrangler@4.13.0:
resolution: {integrity: sha512-CVRNL0unLmzhVeUkW+9neZHFITSo7UDROz8VYxi8YhitV9Rr1xMojS1cGjQTaQX8F3nAEsTRJXTwwTZ0JoJm6g==}
engines: {node: '>=18.0.0'}
hasBin: true
peerDependencies:
'@cloudflare/workers-types': ^4.20250409.0
'@cloudflare/workers-types': ^4.20250422.0
peerDependenciesMeta:
'@cloudflare/workers-types':
optional: true
@@ -2143,114 +2143,114 @@ snapshots:
dependencies:
mime: 3.0.0
'@cloudflare/unenv-preset@2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250409.0)':
'@cloudflare/unenv-preset@2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250422.0)':
dependencies:
unenv: 2.0.0-rc.15
optionalDependencies:
workerd: 1.20250409.0
workerd: 1.20250422.0
'@cloudflare/workerd-darwin-64@1.20250409.0':
'@cloudflare/workerd-darwin-64@1.20250422.0':
optional: true
'@cloudflare/workerd-darwin-arm64@1.20250409.0':
'@cloudflare/workerd-darwin-arm64@1.20250422.0':
optional: true
'@cloudflare/workerd-linux-64@1.20250409.0':
'@cloudflare/workerd-linux-64@1.20250422.0':
optional: true
'@cloudflare/workerd-linux-arm64@1.20250409.0':
'@cloudflare/workerd-linux-arm64@1.20250422.0':
optional: true
'@cloudflare/workerd-windows-64@1.20250409.0':
'@cloudflare/workerd-windows-64@1.20250422.0':
optional: true
'@cloudflare/workers-types@4.20250412.0': {}
'@cloudflare/workers-types@4.20250423.0': {}
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
'@emnapi/runtime@1.4.1':
'@emnapi/runtime@1.4.3':
dependencies:
tslib: 2.8.1
optional: true
'@esbuild/aix-ppc64@0.24.2':
'@esbuild/aix-ppc64@0.25.2':
optional: true
'@esbuild/android-arm64@0.24.2':
'@esbuild/android-arm64@0.25.2':
optional: true
'@esbuild/android-arm@0.24.2':
'@esbuild/android-arm@0.25.2':
optional: true
'@esbuild/android-x64@0.24.2':
'@esbuild/android-x64@0.25.2':
optional: true
'@esbuild/darwin-arm64@0.24.2':
'@esbuild/darwin-arm64@0.25.2':
optional: true
'@esbuild/darwin-x64@0.24.2':
'@esbuild/darwin-x64@0.25.2':
optional: true
'@esbuild/freebsd-arm64@0.24.2':
'@esbuild/freebsd-arm64@0.25.2':
optional: true
'@esbuild/freebsd-x64@0.24.2':
'@esbuild/freebsd-x64@0.25.2':
optional: true
'@esbuild/linux-arm64@0.24.2':
'@esbuild/linux-arm64@0.25.2':
optional: true
'@esbuild/linux-arm@0.24.2':
'@esbuild/linux-arm@0.25.2':
optional: true
'@esbuild/linux-ia32@0.24.2':
'@esbuild/linux-ia32@0.25.2':
optional: true
'@esbuild/linux-loong64@0.24.2':
'@esbuild/linux-loong64@0.25.2':
optional: true
'@esbuild/linux-mips64el@0.24.2':
'@esbuild/linux-mips64el@0.25.2':
optional: true
'@esbuild/linux-ppc64@0.24.2':
'@esbuild/linux-ppc64@0.25.2':
optional: true
'@esbuild/linux-riscv64@0.24.2':
'@esbuild/linux-riscv64@0.25.2':
optional: true
'@esbuild/linux-s390x@0.24.2':
'@esbuild/linux-s390x@0.25.2':
optional: true
'@esbuild/linux-x64@0.24.2':
'@esbuild/linux-x64@0.25.2':
optional: true
'@esbuild/netbsd-arm64@0.24.2':
'@esbuild/netbsd-arm64@0.25.2':
optional: true
'@esbuild/netbsd-x64@0.24.2':
'@esbuild/netbsd-x64@0.25.2':
optional: true
'@esbuild/openbsd-arm64@0.24.2':
'@esbuild/openbsd-arm64@0.25.2':
optional: true
'@esbuild/openbsd-x64@0.24.2':
'@esbuild/openbsd-x64@0.25.2':
optional: true
'@esbuild/sunos-x64@0.24.2':
'@esbuild/sunos-x64@0.25.2':
optional: true
'@esbuild/win32-arm64@0.24.2':
'@esbuild/win32-arm64@0.25.2':
optional: true
'@esbuild/win32-ia32@0.24.2':
'@esbuild/win32-ia32@0.25.2':
optional: true
'@esbuild/win32-x64@0.24.2':
'@esbuild/win32-x64@0.25.2':
optional: true
'@eslint-community/eslint-utils@4.5.1(eslint@9.18.0)':
'@eslint-community/eslint-utils@4.6.1(eslint@9.18.0)':
dependencies:
eslint: 9.18.0
eslint-visitor-keys: 3.4.3
@@ -2379,7 +2379,7 @@ snapshots:
'@img/sharp-wasm32@0.33.5':
dependencies:
'@emnapi/runtime': 1.4.1
'@emnapi/runtime': 1.4.3
optional: true
'@img/sharp-win32-ia32@0.33.5':
@@ -2452,10 +2452,10 @@ snapshots:
pvtsutils: 1.3.6
tslib: 2.8.1
'@react-email/render@1.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
'@react-email/render@1.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
html-to-text: 9.0.5
prettier: 3.4.2
prettier: 3.5.3
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-promise-suspense: 0.3.4
@@ -2818,14 +2818,14 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.18.0)(typescript@5.4.5))(eslint@9.18.0)(typescript@5.4.5)':
'@typescript-eslint/eslint-plugin@8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.18.0)(typescript@5.4.5))(eslint@9.18.0)(typescript@5.4.5)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 8.29.1(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/scope-manager': 8.29.1
'@typescript-eslint/type-utils': 8.29.1(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/utils': 8.29.1(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 8.29.1
'@typescript-eslint/parser': 8.31.0(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/scope-manager': 8.31.0
'@typescript-eslint/type-utils': 8.31.0(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/utils': 8.31.0(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 8.31.0
eslint: 9.18.0
graphemer: 1.4.0
ignore: 5.3.2
@@ -2835,27 +2835,27 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.29.1(eslint@9.18.0)(typescript@5.4.5)':
'@typescript-eslint/parser@8.31.0(eslint@9.18.0)(typescript@5.4.5)':
dependencies:
'@typescript-eslint/scope-manager': 8.29.1
'@typescript-eslint/types': 8.29.1
'@typescript-eslint/typescript-estree': 8.29.1(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 8.29.1
'@typescript-eslint/scope-manager': 8.31.0
'@typescript-eslint/types': 8.31.0
'@typescript-eslint/typescript-estree': 8.31.0(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 8.31.0
debug: 4.4.0
eslint: 9.18.0
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.29.1':
'@typescript-eslint/scope-manager@8.31.0':
dependencies:
'@typescript-eslint/types': 8.29.1
'@typescript-eslint/visitor-keys': 8.29.1
'@typescript-eslint/types': 8.31.0
'@typescript-eslint/visitor-keys': 8.31.0
'@typescript-eslint/type-utils@8.29.1(eslint@9.18.0)(typescript@5.4.5)':
'@typescript-eslint/type-utils@8.31.0(eslint@9.18.0)(typescript@5.4.5)':
dependencies:
'@typescript-eslint/typescript-estree': 8.29.1(typescript@5.4.5)
'@typescript-eslint/utils': 8.29.1(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/typescript-estree': 8.31.0(typescript@5.4.5)
'@typescript-eslint/utils': 8.31.0(eslint@9.18.0)(typescript@5.4.5)
debug: 4.4.0
eslint: 9.18.0
ts-api-utils: 2.1.0(typescript@5.4.5)
@@ -2863,12 +2863,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.29.1': {}
'@typescript-eslint/types@8.31.0': {}
'@typescript-eslint/typescript-estree@8.29.1(typescript@5.4.5)':
'@typescript-eslint/typescript-estree@8.31.0(typescript@5.4.5)':
dependencies:
'@typescript-eslint/types': 8.29.1
'@typescript-eslint/visitor-keys': 8.29.1
'@typescript-eslint/types': 8.31.0
'@typescript-eslint/visitor-keys': 8.31.0
debug: 4.4.0
fast-glob: 3.3.3
is-glob: 4.0.3
@@ -2879,20 +2879,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.29.1(eslint@9.18.0)(typescript@5.4.5)':
'@typescript-eslint/utils@8.31.0(eslint@9.18.0)(typescript@5.4.5)':
dependencies:
'@eslint-community/eslint-utils': 4.5.1(eslint@9.18.0)
'@typescript-eslint/scope-manager': 8.29.1
'@typescript-eslint/types': 8.29.1
'@typescript-eslint/typescript-estree': 8.29.1(typescript@5.4.5)
'@eslint-community/eslint-utils': 4.6.1(eslint@9.18.0)
'@typescript-eslint/scope-manager': 8.31.0
'@typescript-eslint/types': 8.31.0
'@typescript-eslint/typescript-estree': 8.31.0(typescript@5.4.5)
eslint: 9.18.0
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.29.1':
'@typescript-eslint/visitor-keys@8.31.0':
dependencies:
'@typescript-eslint/types': 8.29.1
'@typescript-eslint/types': 8.31.0
eslint-visitor-keys: 4.2.0
abort-controller@3.0.0:
@@ -3015,7 +3015,7 @@ snapshots:
defu@6.1.4: {}
detect-libc@2.0.3:
detect-libc@2.0.4:
optional: true
dom-serializer@2.0.0:
@@ -3038,33 +3038,33 @@ snapshots:
entities@4.5.0: {}
esbuild@0.24.2:
esbuild@0.25.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.24.2
'@esbuild/android-arm': 0.24.2
'@esbuild/android-arm64': 0.24.2
'@esbuild/android-x64': 0.24.2
'@esbuild/darwin-arm64': 0.24.2
'@esbuild/darwin-x64': 0.24.2
'@esbuild/freebsd-arm64': 0.24.2
'@esbuild/freebsd-x64': 0.24.2
'@esbuild/linux-arm': 0.24.2
'@esbuild/linux-arm64': 0.24.2
'@esbuild/linux-ia32': 0.24.2
'@esbuild/linux-loong64': 0.24.2
'@esbuild/linux-mips64el': 0.24.2
'@esbuild/linux-ppc64': 0.24.2
'@esbuild/linux-riscv64': 0.24.2
'@esbuild/linux-s390x': 0.24.2
'@esbuild/linux-x64': 0.24.2
'@esbuild/netbsd-arm64': 0.24.2
'@esbuild/netbsd-x64': 0.24.2
'@esbuild/openbsd-arm64': 0.24.2
'@esbuild/openbsd-x64': 0.24.2
'@esbuild/sunos-x64': 0.24.2
'@esbuild/win32-arm64': 0.24.2
'@esbuild/win32-ia32': 0.24.2
'@esbuild/win32-x64': 0.24.2
'@esbuild/aix-ppc64': 0.25.2
'@esbuild/android-arm': 0.25.2
'@esbuild/android-arm64': 0.25.2
'@esbuild/android-x64': 0.25.2
'@esbuild/darwin-arm64': 0.25.2
'@esbuild/darwin-x64': 0.25.2
'@esbuild/freebsd-arm64': 0.25.2
'@esbuild/freebsd-x64': 0.25.2
'@esbuild/linux-arm': 0.25.2
'@esbuild/linux-arm64': 0.25.2
'@esbuild/linux-ia32': 0.25.2
'@esbuild/linux-loong64': 0.25.2
'@esbuild/linux-mips64el': 0.25.2
'@esbuild/linux-ppc64': 0.25.2
'@esbuild/linux-riscv64': 0.25.2
'@esbuild/linux-s390x': 0.25.2
'@esbuild/linux-x64': 0.25.2
'@esbuild/netbsd-arm64': 0.25.2
'@esbuild/netbsd-x64': 0.25.2
'@esbuild/openbsd-arm64': 0.25.2
'@esbuild/openbsd-x64': 0.25.2
'@esbuild/sunos-x64': 0.25.2
'@esbuild/win32-arm64': 0.25.2
'@esbuild/win32-ia32': 0.25.2
'@esbuild/win32-x64': 0.25.2
escape-string-regexp@4.0.0: {}
@@ -3079,7 +3079,7 @@ snapshots:
eslint@9.18.0:
dependencies:
'@eslint-community/eslint-utils': 4.5.1(eslint@9.18.0)
'@eslint-community/eslint-utils': 4.6.1(eslint@9.18.0)
'@eslint-community/regexpp': 4.12.1
'@eslint/config-array': 0.19.2
'@eslint/core': 0.10.0
@@ -3138,7 +3138,7 @@ snapshots:
exit-hook@2.2.1: {}
exsolve@1.0.4: {}
exsolve@1.0.5: {}
fast-deep-equal@2.0.1: {}
@@ -3210,7 +3210,7 @@ snapshots:
has-flag@4.0.0: {}
hono@4.7.6: {}
hono@4.7.7: {}
html-to-text@9.0.5:
dependencies:
@@ -3314,7 +3314,7 @@ snapshots:
js-base64: 3.7.7
mime-types: 2.1.35
miniflare@4.20250409.0:
miniflare@4.20250422.0:
dependencies:
'@cspotcode/source-map-support': 0.8.1
acorn: 8.14.0
@@ -3323,7 +3323,7 @@ snapshots:
glob-to-regexp: 0.4.1
stoppable: 1.1.0
undici: 5.29.0
workerd: 1.20250409.0
workerd: 1.20250422.0
ws: 8.18.0
youch: 3.3.4
zod: 3.22.3
@@ -3397,7 +3397,7 @@ snapshots:
prelude-ls@1.2.1: {}
prettier@3.4.2: {}
prettier@3.5.3: {}
printable-characters@1.0.42: {}
@@ -3427,9 +3427,9 @@ snapshots:
regenerator-runtime@0.14.1: {}
resend@4.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
resend@4.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@react-email/render': 1.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@react-email/render': 1.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
transitivePeerDependencies:
- react
- react-dom
@@ -3461,7 +3461,7 @@ snapshots:
sharp@0.33.5:
dependencies:
color: 4.2.3
detect-libc: 2.0.3
detect-libc: 2.0.4
semver: 7.7.1
optionalDependencies:
'@img/sharp-darwin-arm64': 0.33.5
@@ -3543,11 +3543,11 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
typescript-eslint@8.29.1(eslint@9.18.0)(typescript@5.4.5):
typescript-eslint@8.31.0(eslint@9.18.0)(typescript@5.4.5):
dependencies:
'@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.18.0)(typescript@5.4.5))(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/parser': 8.29.1(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/utils': 8.29.1(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/eslint-plugin': 8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.18.0)(typescript@5.4.5))(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/parser': 8.31.0(eslint@9.18.0)(typescript@5.4.5)
'@typescript-eslint/utils': 8.31.0(eslint@9.18.0)(typescript@5.4.5)
eslint: 9.18.0
typescript: 5.4.5
transitivePeerDependencies:
@@ -3564,7 +3564,7 @@ snapshots:
unenv@2.0.0-rc.15:
dependencies:
defu: 6.1.4
exsolve: 1.0.4
exsolve: 1.0.5
ohash: 2.0.11
pathe: 2.0.3
ufo: 1.6.1
@@ -3588,28 +3588,28 @@ snapshots:
word-wrap@1.2.5: {}
worker-mailer@1.1.1: {}
worker-mailer@1.1.3: {}
workerd@1.20250409.0:
workerd@1.20250422.0:
optionalDependencies:
'@cloudflare/workerd-darwin-64': 1.20250409.0
'@cloudflare/workerd-darwin-arm64': 1.20250409.0
'@cloudflare/workerd-linux-64': 1.20250409.0
'@cloudflare/workerd-linux-arm64': 1.20250409.0
'@cloudflare/workerd-windows-64': 1.20250409.0
'@cloudflare/workerd-darwin-64': 1.20250422.0
'@cloudflare/workerd-darwin-arm64': 1.20250422.0
'@cloudflare/workerd-linux-64': 1.20250422.0
'@cloudflare/workerd-linux-arm64': 1.20250422.0
'@cloudflare/workerd-windows-64': 1.20250422.0
wrangler@4.10.0(@cloudflare/workers-types@4.20250412.0):
wrangler@4.13.0(@cloudflare/workers-types@4.20250423.0):
dependencies:
'@cloudflare/kv-asset-handler': 0.4.0
'@cloudflare/unenv-preset': 2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250409.0)
'@cloudflare/unenv-preset': 2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250422.0)
blake3-wasm: 2.1.5
esbuild: 0.24.2
miniflare: 4.20250409.0
esbuild: 0.25.2
miniflare: 4.20250422.0
path-to-regexp: 6.3.0
unenv: 2.0.0-rc.15
workerd: 1.20250409.0
workerd: 1.20250422.0
optionalDependencies:
'@cloudflare/workers-types': 4.20250412.0
'@cloudflare/workers-types': 4.20250423.0
fsevents: 2.3.3
sharp: 0.33.5
transitivePeerDependencies:

View File

@@ -0,0 +1,39 @@
import { Context } from "hono";
import { HonoCustomType } from "../types";
import { handleListQuery } from "../common";
export default {
getMails: async (c: Context<HonoCustomType>) => {
const { address, limit, offset, keyword } = c.req.query();
const addressQuery = address ? `address = ?` : "";
const addressParams = address ? [address] : [];
const keywordQuery = keyword ? `raw like ?` : "";
const keywordParams = keyword ? [`%${keyword}%`] : [];
const filterQuerys = [addressQuery, keywordQuery].filter((item) => item).join(" and ");
const finalQuery = filterQuerys.length > 0 ? `where ${filterQuerys}` : "";
const filterParams = [...addressParams, ...keywordParams]
return await handleListQuery(c,
`SELECT * FROM raw_mails ${finalQuery}`,
`SELECT count(*) as count FROM raw_mails ${finalQuery}`,
filterParams, limit, offset
);
},
getUnknowMails: async (c: Context<HonoCustomType>) => {
const { limit, offset } = c.req.query();
return await handleListQuery(c,
`SELECT * FROM raw_mails where address NOT IN (select name from address) `,
`SELECT count(*) as count FROM raw_mails`
+ ` where address NOT IN (select name from address) `,
[], limit, offset
);
},
deleteMail: async (c: Context<HonoCustomType>) => {
const { id } = c.req.param();
const { success } = await c.env.DB.prepare(
`DELETE FROM raw_mails WHERE id = ? `
).bind(id).run();
return c.json({
success: success
})
}
}

View File

@@ -6,6 +6,7 @@ import { UserSettings, GeoData, UserInfo } from "../models";
import { handleListQuery } from '../common'
import { HonoCustomType } from '../types';
import UserBindAddressModule from '../user_api/bind_address';
import i18n from '../i18n';
export default {
getSetting: async (c: Context<HonoCustomType>) => {
@@ -90,7 +91,8 @@ export default {
},
deleteUser: async (c: Context<HonoCustomType>) => {
const { user_id } = c.req.param();
if (!user_id) return c.text("Invalid user_id", 400);
const msgs = i18n.getMessagesbyContext(c);
if (!user_id) return c.text(msgs.UserNotFoundMsg, 400);
const { success } = await c.env.DB.prepare(
`DELETE FROM users WHERE id = ?`
).bind(user_id).run();
@@ -105,7 +107,8 @@ export default {
resetPassword: async (c: Context<HonoCustomType>) => {
const { user_id } = c.req.param();
const { password } = await c.req.json();
if (!user_id) return c.text("Invalid user_id", 400);
const msgs = i18n.getMessagesbyContext(c);
if (!user_id) return c.text(msgs.UserNotFoundMsg, 400);
try {
checkUserPassword(password);
const { success } = await c.env.DB.prepare(
@@ -159,6 +162,9 @@ export default {
},
getBindedAddresses: async (c: Context<HonoCustomType>) => {
const { user_id } = c.req.param();
return await UserBindAddressModule.getBindedAddressesById(c, user_id);
const results = await UserBindAddressModule.getBindedAddressesById(c, user_id);
return c.json({
results: results,
});
},
}

View File

@@ -12,6 +12,7 @@ import webhook_settings from './webhook_settings'
import mail_webhook_settings from './mail_webhook_settings'
import oauth2_settings from './oauth2_settings'
import worker_config from './worker_config'
import admin_mail_api from './admin_mail_api'
import { sendMailbyAdmin } from './send_mail'
export const api = new Hono<HonoCustomType>()
@@ -101,54 +102,10 @@ api.get('/admin/show_password/:id', async (c) => {
})
})
api.get('/admin/mails', async (c) => {
const { address, limit, offset, keyword } = c.req.query();
if (address && keyword) {
return await handleListQuery(c,
`SELECT * FROM raw_mails where address = ? and raw like ? `,
`SELECT count(*) as count FROM raw_mails where address = ? and raw like ? `,
[address, `%${keyword}%`], limit, offset
);
} else if (keyword) {
return await handleListQuery(c,
`SELECT * FROM raw_mails where raw like ? `,
`SELECT count(*) as count FROM raw_mails where raw like ? `,
[`%${keyword}%`], limit, offset
);
} else if (address) {
return await handleListQuery(c,
`SELECT * FROM raw_mails where address = ? `,
`SELECT count(*) as count FROM raw_mails where address = ? `,
[address], limit, offset
);
} else {
return await handleListQuery(c,
`SELECT * FROM raw_mails `,
`SELECT count(*) as count FROM raw_mails `,
[], limit, offset
);
}
});
api.get('/admin/mails_unknow', async (c) => {
const { limit, offset } = c.req.query();
return await handleListQuery(c,
`SELECT * FROM raw_mails where address NOT IN (select name from address) `,
`SELECT count(*) as count FROM raw_mails`
+ ` where address NOT IN (select name from address) `,
[], limit, offset
);
});
api.delete('/admin/mails/:id', async (c) => {
const { id } = c.req.param();
const { success } = await c.env.DB.prepare(
`DELETE FROM raw_mails WHERE id = ? `
).bind(id).run();
return c.json({
success: success
})
})
// mail api
api.get('/admin/mails', admin_mail_api.getMails);
api.get('/admin/mails_unknow', admin_mail_api.getUnknowMails);
api.delete('/admin/mails/:id', admin_mail_api.deleteMail)
api.get('/admin/address_sender', async (c) => {
const { address, limit, offset } = c.req.query();

View File

@@ -1,5 +1,5 @@
export const CONSTANTS = {
VERSION: 'v' + '0.9.1',
VERSION: 'v' + '0.10.9',
// DB settings
ADDRESS_BLOCK_LIST_KEY: 'address_block_list',

View File

@@ -1,6 +1,8 @@
import { LocaleMessages } from "./type";
import zh from "./zh";
import en from "./en";
import { HonoCustomType } from "../types";
import { Context } from "hono";
export default {
getMessages: (
@@ -10,6 +12,17 @@ export default {
if (locale === "en") return en;
if (locale === "zh") return zh;
// fallback language
return en;
},
getMessagesbyContext: (
c: Context<HonoCustomType>
): LocaleMessages => {
const locale = c.get("lang") || c.env.DEFAULT_LANG;
// multi-language support
if (locale === "en") return en;
if (locale === "zh") return zh;
// fallback language
return en;
}

View File

@@ -6,6 +6,7 @@ import { UserSettings } from "../models";
import { getJsonSetting } from "../utils"
import { CONSTANTS } from "../constants";
import { unbindTelegramByAddress } from '../telegram_api/common';
import i18n from '../i18n';
const UserBindAddressModule = {
bind: async (c: Context<HonoCustomType>) => {
@@ -102,13 +103,30 @@ const UserBindAddressModule = {
},
getBindedAddresses: async (c: Context<HonoCustomType>) => {
const { user_id } = c.get("userPayload");
return await UserBindAddressModule.getBindedAddressesById(c, user_id);
const results = await UserBindAddressModule.getBindedAddressesById(c, user_id);
return c.json({
results: results,
});
},
getBindedAddressListById: async (
c: Context<HonoCustomType>, user_id: number | string
): Promise<string[]> => {
const bindedAddressList = await UserBindAddressModule.getBindedAddressesById(c, user_id);
return bindedAddressList.map((item) => item.name);
},
getBindedAddressesById: async (
c: Context<HonoCustomType>, user_id: number | string
) => {
): Promise<{
id: number;
name: string;
mail_count: number;
send_count: number;
created_at: string;
updated_at: string;
}[]> => {
const msgs = i18n.getMessagesbyContext(c);
if (!user_id) {
return c.text("No user token", 400)
throw new Error(msgs.UserNotFoundMsg);
}
// select binded address
const { results } = await c.env.DB.prepare(
@@ -120,10 +138,15 @@ const UserBindAddressModule = {
+ ` ON ua.address_id = a.id `
+ ` WHERE ua.user_id = ?`
+ ` ORDER BY a.id DESC`
).bind(user_id).all();
return c.json({
results: results,
})
).bind(user_id).all<{
id: number;
name: string;
mail_count: number;
send_count: number;
created_at: string;
updated_at: string;
}>();
return results || [];
},
getBindedAddressJwt: async (c: Context<HonoCustomType>) => {
const { address_id } = c.req.param();
@@ -216,7 +239,7 @@ const UserBindAddressModule = {
throw new Error("Failed to create address")
}
// find new address id
let new_address_id = await c.env.DB.prepare(
const new_address_id = await c.env.DB.prepare(
`SELECT id FROM address WHERE name = ?`
).bind(address).first<number | null | undefined>("id");
if (!new_address_id) {

View File

@@ -6,6 +6,7 @@ import user from './user';
import bind_address from './bind_address';
import passkey from './passkey';
import oauth2 from './oauth2';
import user_mail_api from './user_mail_api';
export const api = new Hono<HonoCustomType>();
@@ -13,6 +14,10 @@ export const api = new Hono<HonoCustomType>();
api.get('/user_api/open_settings', settings.openSettings);
api.get('/user_api/settings', settings.settings);
// mail api
api.get('/user_api/mails', user_mail_api.getMails);
api.delete('/user_api/mails/:id', user_mail_api.deleteMail);
// user api
api.post('/user_api/login', user.login);
api.post('/user_api/verify_code', user.verifyCode);

View File

@@ -0,0 +1,43 @@
import { Context } from "hono";
import { handleListQuery } from "../common";
import { HonoCustomType } from "../types";
import UserBindAddressModule from "./bind_address";
export default {
getMails: async (c: Context<HonoCustomType>) => {
const { user_id } = c.get("userPayload");
const { address, limit, offset, keyword } = c.req.query();
const bindedAddressList = await UserBindAddressModule.getBindedAddressListById(c, user_id);
const addressList = address ? bindedAddressList.filter((item) => item == address) : bindedAddressList;
const addressQuery = `address IN (${addressList.map(() => "?").join(",")})`;
const addressParams = addressList;
const keywordQuery = keyword ? `raw like ?` : "";
const keywordParams = keyword ? [`%${keyword}%`] : [];
// user must have at least one binded address to query mails
if (addressList.length <= 0) {
return c.json({ results: [], count: 0 });
}
const filterQuerys = [addressQuery, keywordQuery].filter((item) => item).join(" and ");
const finalQuery = filterQuerys.length > 0 ? `where ${filterQuerys}` : "";
const filterParams = [...addressParams, ...keywordParams]
return await handleListQuery(c,
`SELECT * FROM raw_mails ${finalQuery}`,
`SELECT count(*) as count FROM raw_mails ${finalQuery}`,
filterParams, limit, offset
);
},
deleteMail: async (c: Context<HonoCustomType>) => {
const { id } = c.req.param();
const { user_id } = c.get("userPayload");
const bindedAddressList = await UserBindAddressModule.getBindedAddressListById(c, user_id);
const { success } = await c.env.DB.prepare(
`DELETE FROM raw_mails WHERE id = ?`
+ ` and address IN (${bindedAddressList.map(() => "?").join(",")})`
).bind(id, ...bindedAddressList).run();
return c.json({
success: success
})
}
}