enh
This commit is contained in:
parent
ba14653721
commit
64d4d26909
8 changed files with 426 additions and 597 deletions
|
|
@ -23,15 +23,13 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.888.0",
|
|
||||||
"@aws-sdk/s3-request-presigner": "^3.888.0",
|
|
||||||
"@hono/node-server": "^1.19.11",
|
"@hono/node-server": "^1.19.11",
|
||||||
"@hono/trpc-server": "^0.4.2",
|
"@hono/trpc-server": "^0.4.2",
|
||||||
"@trpc/server": "^11.6.0",
|
"@trpc/server": "^11.6.0",
|
||||||
"@turf/turf": "^7.2.0",
|
"@turf/boolean-point-in-polygon": "^7.2.0",
|
||||||
|
"@turf/helpers": "^7.2.0",
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"axios": "^1.11.0",
|
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"dayjs": "^1.11.18",
|
"dayjs": "^1.11.18",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.1",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Buffer } from 'buffer'
|
import { Buffer } from 'buffer'
|
||||||
import axios from 'axios'
|
|
||||||
import { scaffoldProducts } from '@/src/trpc/apis/common-apis/common'
|
import { scaffoldProducts } from '@/src/trpc/apis/common-apis/common'
|
||||||
import { scaffoldEssentialConsts } from '@/src/trpc/apis/common-apis/common-trpc-index'
|
import { scaffoldEssentialConsts } from '@/src/trpc/apis/common-apis/common-trpc-index'
|
||||||
import { scaffoldStores } from '@/src/trpc/apis/user-apis/apis/stores'
|
import { scaffoldStores } from '@/src/trpc/apis/user-apis/apis/stores'
|
||||||
|
|
@ -180,18 +179,19 @@ export async function clearUrlCache(urls: string[]): Promise<{ success: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const resp = await fetch(
|
||||||
`https://api.cloudflare.com/client/v4/zones/${cloudflareZoneId}/purge_cache`,
|
`https://api.cloudflare.com/client/v4/zones/${cloudflareZoneId}/purge_cache`,
|
||||||
{ files: urls },
|
|
||||||
{
|
{
|
||||||
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${cloudflareApiToken}`,
|
'Authorization': `Bearer ${cloudflareApiToken}`,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
|
body: JSON.stringify({ files: urls }),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const result = response.data as { success: boolean; errors?: { message: string }[] }
|
const result = await resp.json() as { success: boolean; errors?: { message: string }[] }
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
const errorMessages = result.errors?.map(e => e.message) || ['Unknown error']
|
const errorMessages = result.errors?.map(e => e.message) || ['Unknown error']
|
||||||
|
|
@ -218,18 +218,19 @@ export async function clearAllCache(): Promise<{ success: boolean; errors?: stri
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const resp = await fetch(
|
||||||
`https://api.cloudflare.com/client/v4/zones/${cloudflareZoneId}/purge_cache`,
|
`https://api.cloudflare.com/client/v4/zones/${cloudflareZoneId}/purge_cache`,
|
||||||
{ purge_everything: true },
|
|
||||||
{
|
{
|
||||||
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${cloudflareApiToken}`,
|
'Authorization': `Bearer ${cloudflareApiToken}`,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
|
body: JSON.stringify({ purge_everything: true }),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const result = response.data as { success: boolean; errors?: { message: string }[] }
|
const result = await resp.json() as { success: boolean; errors?: { message: string }[] }
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
const errorMessages = result.errors?.map(e => e.message) || ['Unknown error']
|
const errorMessages = result.errors?.map(e => e.message) || ['Unknown error']
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
export async function extractCoordsFromRedirectUrl(url: string): Promise<{ latitude: string; longitude: string } | null> {
|
export async function extractCoordsFromRedirectUrl(url: string): Promise<{ latitude: string; longitude: string } | null> {
|
||||||
try {
|
try {
|
||||||
await axios.get(url, { maxRedirects: 0 });
|
const response = await fetch(url, { redirect: 'manual' })
|
||||||
return null;
|
if (response.status === 301 || response.status === 302) {
|
||||||
} catch (error: any) {
|
const redirectUrl = response.headers.get('location')
|
||||||
if (error.response?.status === 302 || error.response?.status === 301) {
|
if (redirectUrl) {
|
||||||
const redirectUrl = error.response.headers.location;
|
const coordsMatch = redirectUrl.match(/!3d([-\d.]+)!4d([-\d.]+)/)
|
||||||
const coordsMatch = redirectUrl.match(/!3d([-\d.]+)!4d([-\d.]+)/);
|
|
||||||
if (coordsMatch) {
|
if (coordsMatch) {
|
||||||
return {
|
return {
|
||||||
latitude: coordsMatch[1],
|
latitude: coordsMatch[1],
|
||||||
longitude: coordsMatch[2],
|
longitude: coordsMatch[2],
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// import { Queue, Worker } from 'bullmq';
|
// import { Queue, Worker } from 'bullmq';
|
||||||
import { Expo } from 'expo-server-sdk';
|
|
||||||
// import { db } from '@/src/db/db_index'
|
// import { db } from '@/src/db/db_index'
|
||||||
import { scaffoldAssetUrl } from '@/src/lib/s3-client'
|
import { scaffoldAssetUrl } from '@/src/lib/s3-client'
|
||||||
import { queueDataPusher } from '@/src/lib/queue-data-pusher'
|
import { queueDataPusher } from '@/src/lib/queue-data-pusher'
|
||||||
|
|
@ -51,6 +50,7 @@ export async function sendAdminNotification(data: {
|
||||||
imageUrl: string | null;
|
imageUrl: string | null;
|
||||||
}) {
|
}) {
|
||||||
const { token, title, body, imageUrl } = data;
|
const { token, title, body, imageUrl } = data;
|
||||||
|
const { Expo } = await import('expo-server-sdk')
|
||||||
|
|
||||||
// Validate Expo push token
|
// Validate Expo push token
|
||||||
if (!Expo.isExpoPushToken(token)) {
|
if (!Expo.isExpoPushToken(token)) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
import axios from 'axios';
|
|
||||||
import { getIsDevMode, getTelegramBotToken, getTelegramChatIds } from '@/src/lib/env-exporter'
|
import { getIsDevMode, getTelegramBotToken, getTelegramChatIds } from '@/src/lib/env-exporter'
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message to Telegram bot
|
|
||||||
* @param message The message text to send
|
|
||||||
* @returns Promise<boolean | null> indicating success, failure, or null if dev mode
|
|
||||||
*/
|
|
||||||
export const sendTelegramMessage = async (message: string): Promise<boolean | null> => {
|
export const sendTelegramMessage = async (message: string): Promise<boolean | null> => {
|
||||||
if (getIsDevMode()) {
|
if (getIsDevMode()) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -21,33 +15,32 @@ export const sendTelegramMessage = async (message: string): Promise<boolean | nu
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
chatIds.map(async (chatId) => {
|
chatIds.map(async (chatId) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(`${telegramApiUrl}/sendMessage`, {
|
const response = await fetch(`${telegramApiUrl}/sendMessage`, {
|
||||||
chat_id: chatId,
|
method: 'POST',
|
||||||
text: message,
|
headers: { 'Content-Type': 'application/json' },
|
||||||
parse_mode: 'HTML',
|
body: JSON.stringify({ chat_id: chatId, text: message, parse_mode: 'HTML' }),
|
||||||
});
|
})
|
||||||
|
const data = await response.json() as { ok: boolean }
|
||||||
|
|
||||||
if (response.data && response.data.ok) {
|
if (data.ok) {
|
||||||
console.log(`Telegram message sent successfully to ${chatId}`);
|
console.log(`Telegram message sent successfully to ${chatId}`)
|
||||||
return true;
|
return true
|
||||||
} else {
|
} else {
|
||||||
console.error(`Telegram API error for ${chatId}:`, response.data);
|
console.error(`Telegram API error for ${chatId}:`, data)
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to send Telegram message to ${chatId}:`, error);
|
console.error(`Failed to send Telegram message to ${chatId}:`, error)
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
console.log('sent telegram message successfully')
|
console.log('sent telegram message successfully')
|
||||||
|
|
||||||
|
return results.some((result) => result)
|
||||||
// Return true if at least one message was sent successfully
|
|
||||||
return results.some((result) => result);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to send Telegram message:', error);
|
console.error('Failed to send Telegram message:', error)
|
||||||
return false;
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ import {
|
||||||
getCacheVersion,
|
getCacheVersion,
|
||||||
} from '@/src/dbService'
|
} from '@/src/dbService'
|
||||||
import type { StoresSummaryResponse } from '@packages/shared'
|
import type { StoresSummaryResponse } from '@packages/shared'
|
||||||
import * as turf from '@turf/turf';
|
import { polygon as turfPolygon, point as turfPoint } from '@turf/helpers';
|
||||||
|
import { booleanPointInPolygon } from '@turf/boolean-point-in-polygon';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { mbnrGeoJson } from '@/src/lib/mbnr-geojson'
|
import { mbnrGeoJson } from '@/src/lib/mbnr-geojson'
|
||||||
import { generateUploadUrl } from '@/src/lib/s3-client'
|
import { generateUploadUrl } from '@/src/lib/s3-client'
|
||||||
|
|
@ -15,7 +16,7 @@ import { getAllConstValues } from '@/src/lib/const-store'
|
||||||
import { CONST_KEYS } from '@/src/lib/const-keys'
|
import { CONST_KEYS } from '@/src/lib/const-keys'
|
||||||
import { getAssetsDomain, getApiCacheKey } from '@/src/lib/env-exporter'
|
import { getAssetsDomain, getApiCacheKey } from '@/src/lib/env-exporter'
|
||||||
|
|
||||||
const polygon = turf.polygon(mbnrGeoJson.features[0].geometry.coordinates);
|
const polygon = turfPolygon(mbnrGeoJson.features[0].geometry.coordinates);
|
||||||
|
|
||||||
export async function scaffoldEssentialConsts() {
|
export async function scaffoldEssentialConsts() {
|
||||||
const consts = await getAllConstValues();
|
const consts = await getAllConstValues();
|
||||||
|
|
@ -76,8 +77,8 @@ export const commonApiRouter = router({
|
||||||
.query(({ input }) => {
|
.query(({ input }) => {
|
||||||
try {
|
try {
|
||||||
const { lat, lng } = input;
|
const { lat, lng } = input;
|
||||||
const point = turf.point([lng, lat]); // GeoJSON: [longitude, latitude]
|
const point = turfPoint([lng, lat]); // GeoJSON: [longitude, latitude]
|
||||||
const isInside = turf.booleanPointInPolygon(point, polygon);
|
const isInside = booleanPointInPolygon(point, polygon);
|
||||||
return { isInside };
|
return { isInside };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('Invalid coordinates or polygon data');
|
throw new Error('Invalid coordinates or polygon data');
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import {
|
||||||
|
|
||||||
export { CacheCreator }
|
export { CacheCreator }
|
||||||
|
|
||||||
|
let app: ReturnType<typeof createApp> | null = null
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async fetch(
|
async fetch(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|
@ -33,9 +35,10 @@ export default {
|
||||||
},
|
},
|
||||||
ctx: ExecutionContext
|
ctx: ExecutionContext
|
||||||
) {
|
) {
|
||||||
console.log(env)
|
|
||||||
ensureWorkerInit(env)
|
ensureWorkerInit(env)
|
||||||
const app = createApp()
|
if (!app) {
|
||||||
|
app = createApp()
|
||||||
|
}
|
||||||
return app.fetch(request, env, ctx)
|
return app.fetch(request, env, ctx)
|
||||||
},
|
},
|
||||||
async queue(
|
async queue(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue