This commit is contained in:
shafi54 2026-04-02 00:52:07 +05:30
parent 15991f46db
commit 982d3027f8
35 changed files with 5383 additions and 4049 deletions

1
.gitignore vendored
View file

@ -8,6 +8,7 @@ yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
**/.wrangler/*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

View file

@ -1,11 +0,0 @@
import worker, * as OTHER_EXPORTS from "/Users/mohammedshafiuddin/WebDev/freshyo/apps/backend/worker.ts";
import * as __MIDDLEWARE_0__ from "/Users/mohammedshafiuddin/WebDev/freshyo/node_modules/wrangler/templates/middleware/middleware-ensure-req-body-drained.ts";
import * as __MIDDLEWARE_1__ from "/Users/mohammedshafiuddin/WebDev/freshyo/node_modules/wrangler/templates/middleware/middleware-miniflare3-json-error.ts";
export * from "/Users/mohammedshafiuddin/WebDev/freshyo/apps/backend/worker.ts";
export const __INTERNAL_WRANGLER_MIDDLEWARE__ = [
__MIDDLEWARE_0__.default,__MIDDLEWARE_1__.default
]
export default worker;

View file

@ -1,134 +0,0 @@
// This loads all middlewares exposed on the middleware object and then starts
// the invocation chain. The big idea is that we can add these to the middleware
// export dynamically through wrangler, or we can potentially let users directly
// add them as a sort of "plugin" system.
import ENTRY, { __INTERNAL_WRANGLER_MIDDLEWARE__ } from "/Users/mohammedshafiuddin/WebDev/freshyo/apps/backend/.wrangler/tmp/bundle-l1tHq1/middleware-insertion-facade.js";
import { __facade_invoke__, __facade_register__, Dispatcher } from "/Users/mohammedshafiuddin/WebDev/freshyo/node_modules/wrangler/templates/middleware/common.ts";
import type { WorkerEntrypointConstructor } from "/Users/mohammedshafiuddin/WebDev/freshyo/apps/backend/.wrangler/tmp/bundle-l1tHq1/middleware-insertion-facade.js";
// Preserve all the exports from the worker
export * from "/Users/mohammedshafiuddin/WebDev/freshyo/apps/backend/.wrangler/tmp/bundle-l1tHq1/middleware-insertion-facade.js";
class __Facade_ScheduledController__ implements ScheduledController {
readonly #noRetry: ScheduledController["noRetry"];
constructor(
readonly scheduledTime: number,
readonly cron: string,
noRetry: ScheduledController["noRetry"]
) {
this.#noRetry = noRetry;
}
noRetry() {
if (!(this instanceof __Facade_ScheduledController__)) {
throw new TypeError("Illegal invocation");
}
// Need to call native method immediately in case uncaught error thrown
this.#noRetry();
}
}
function wrapExportedHandler(worker: ExportedHandler): ExportedHandler {
// If we don't have any middleware defined, just return the handler as is
if (
__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||
__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0
) {
return worker;
}
// Otherwise, register all middleware once
for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {
__facade_register__(middleware);
}
const fetchDispatcher: ExportedHandlerFetchHandler = function (
request,
env,
ctx
) {
if (worker.fetch === undefined) {
throw new Error("Handler does not export a fetch() function.");
}
return worker.fetch(request, env, ctx);
};
return {
...worker,
fetch(request, env, ctx) {
const dispatcher: Dispatcher = function (type, init) {
if (type === "scheduled" && worker.scheduled !== undefined) {
const controller = new __Facade_ScheduledController__(
Date.now(),
init.cron ?? "",
() => {}
);
return worker.scheduled(controller, env, ctx);
}
};
return __facade_invoke__(request, env, ctx, dispatcher, fetchDispatcher);
},
};
}
function wrapWorkerEntrypoint(
klass: WorkerEntrypointConstructor
): WorkerEntrypointConstructor {
// If we don't have any middleware defined, just return the handler as is
if (
__INTERNAL_WRANGLER_MIDDLEWARE__ === undefined ||
__INTERNAL_WRANGLER_MIDDLEWARE__.length === 0
) {
return klass;
}
// Otherwise, register all middleware once
for (const middleware of __INTERNAL_WRANGLER_MIDDLEWARE__) {
__facade_register__(middleware);
}
// `extend`ing `klass` here so other RPC methods remain callable
return class extends klass {
#fetchDispatcher: ExportedHandlerFetchHandler<Record<string, unknown>> = (
request,
env,
ctx
) => {
this.env = env;
this.ctx = ctx;
if (super.fetch === undefined) {
throw new Error("Entrypoint class does not define a fetch() function.");
}
return super.fetch(request);
};
#dispatcher: Dispatcher = (type, init) => {
if (type === "scheduled" && super.scheduled !== undefined) {
const controller = new __Facade_ScheduledController__(
Date.now(),
init.cron ?? "",
() => {}
);
return super.scheduled(controller);
}
};
fetch(request: Request<unknown, IncomingRequestCfProperties>) {
return __facade_invoke__(
request,
this.env,
this.ctx,
this.#dispatcher,
this.#fetchDispatcher
);
}
};
}
let WRAPPED_ENTRY: ExportedHandler | WorkerEntrypointConstructor | undefined;
if (typeof ENTRY === "object") {
WRAPPED_ENTRY = wrapExportedHandler(ENTRY);
} else if (typeof ENTRY === "function") {
WRAPPED_ENTRY = wrapWorkerEntrypoint(ENTRY);
}
export default WRAPPED_ENTRY;

View file

@ -1,13 +0,0 @@
function stripCfConnectingIPHeader(input, init) {
const request = new Request(input, init);
request.headers.delete("CF-Connecting-IP");
return request;
}
globalThis.fetch = new Proxy(globalThis.fetch, {
apply(target, thisArg, argArray) {
return Reflect.apply(target, thisArg, [
stripCfConnectingIPHeader.apply(null, argArray),
]);
},
});

View file

@ -9566,9 +9566,9 @@ async function incrementCacheVersion() {
});
const nextValue = parseCacheVersion(existing?.value) + 1;
if (existing) {
await tx.update(keyValStore).set({ value: nextValue }).where(eq(keyValStore.key, CACHE_VERSION_KEY));
await tx.update(keyValStore).set({ value: nextValue + "" }).where(eq(keyValStore.key, CACHE_VERSION_KEY));
} else {
await tx.insert(keyValStore).values({ key: CACHE_VERSION_KEY, value: nextValue });
await tx.insert(keyValStore).values({ key: CACHE_VERSION_KEY, value: nextValue + "" });
}
return nextValue;
});

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -38,7 +38,7 @@
"zod": "^4.1.12"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260304.0",
"@cloudflare/workers-types": "^4.20260401.1",
"@types/node": "^24.5.2",
"rimraf": "^6.1.2",
"ts-node-dev": "^2.0.0",

View file

@ -1,5 +1,6 @@
import dayjs from 'dayjs'
import { initializeAllStores } from '@/src/stores/store-initializer'
import { initDb } from '@/src/dbService'
const LAST_TRIGGER_KEY = 'lastTrigger'
const ALARM_DELAY_MINUTES = 0.5
@ -7,11 +8,32 @@ const ALARM_DELAY_MINUTES = 0.5
export class CacheCreator {
private state: any
private env: any
constructor(state: any) {
constructor(state: any, env: any) {
this.state = state
this.env = env
;(globalThis as any).ENV = env
}
async schedule(): Promise<void> {
console.log( 'from the fetch method of durable object')
// if (request.method === 'POST' && url.pathname === '/schedule') {
const now = Date.now()
await this.state.storage.put(LAST_TRIGGER_KEY, now)
const alarmAt = dayjs(now).add(ALARM_DELAY_MINUTES, 'minute').valueOf()
await this.state.storage.setAlarm(alarmAt)
// return new Response('OK')
// }
// if (request.method === 'POST' && url.pathname === '/clear') {
await this.state.storage.deleteAll()
// return new Response('OK')
// }
// return new Response('CacheCreator ready', { status: 200 })
}
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url)
if (request.method === 'POST' && url.pathname === '/schedule') {
@ -30,6 +52,10 @@ export class CacheCreator {
}
async alarm(): Promise<void> {
;(globalThis as any).ENV = this.env
if (this.env?.DB) {
initDb(this.env.DB)
}
const lastTrigger = await this.state.storage.get(LAST_TRIGGER_KEY)
if (!lastTrigger) {
return

View file

@ -1,294 +1,294 @@
// Postgres Importer - Intermediate layer to avoid direct postgresService imports in dbService
// This file re-exports everything from postgresService
// Re-export database connection
export { db } from 'postgresService'
// Re-export all schema exports
export * from 'postgresService'
// Re-export all helper methods from postgresService
export {
// Admin - Banner
getBanners,
getBannerById,
createBanner,
updateBanner,
deleteBanner,
// Admin - Complaint
getComplaints,
resolveComplaint,
// Admin - Constants
getAllConstants,
upsertConstants,
// Admin - Coupon
getAllCoupons,
getCouponById,
invalidateCoupon,
validateCoupon,
getReservedCoupons,
getUsersForCoupon,
createCouponWithRelations,
updateCouponWithRelations,
generateCancellationCoupon,
createReservedCouponWithProducts,
createCouponForUser,
checkUsersExist,
checkCouponExists,
checkReservedCouponExists,
getOrderWithUser,
// Admin - Order
updateOrderNotes,
getOrderDetails,
updateOrderPackaged,
updateOrderDelivered,
updateOrderItemPackaging,
removeDeliveryCharge,
getSlotOrders,
updateAddressCoords,
getAllOrders,
rebalanceSlots,
cancelOrder,
deleteOrderById,
// Admin - Product
getAllProducts,
getProductById,
deleteProduct,
createProduct,
updateProduct,
checkProductExistsByName,
checkUnitExists,
getProductImagesById,
createSpecialDealsForProduct,
updateProductDeals,
replaceProductTags,
toggleProductOutOfStock,
updateSlotProducts,
getSlotProductIds,
getSlotsProductIds,
getAllUnits,
getAllProductTags,
getAllProductTagInfos,
getProductTagInfoById,
createProductTag,
getProductTagById,
updateProductTag,
deleteProductTag,
checkProductTagExistsByName,
getProductReviews,
respondToReview,
getAllProductGroups,
createProductGroup,
updateProductGroup,
deleteProductGroup,
addProductToGroup,
removeProductFromGroup,
updateProductPrices,
// Admin - Slots
getActiveSlotsWithProducts,
getActiveSlots,
getSlotsAfterDate,
getSlotByIdWithRelations,
createSlotWithRelations,
updateSlotWithRelations,
deleteSlotById,
updateSlotCapacity,
getSlotDeliverySequence,
updateSlotDeliverySequence,
// Admin - Staff User
getStaffUserByName,
getStaffUserById,
getAllStaff,
getAllUsers,
getUserWithDetails,
updateUserSuspensionStatus,
checkStaffUserExists,
checkStaffRoleExists,
createStaffUser,
getAllRoles,
// Admin - Store
getAllStores,
getStoreById,
createStore,
updateStore,
deleteStore,
// Admin - User
createUserByMobile,
getUserByMobile,
getUnresolvedComplaintsCount,
getAllUsersWithFilters,
getOrderCountsByUserIds,
getLastOrdersByUserIds,
getSuspensionStatusesByUserIds,
getUserBasicInfo,
getUserSuspensionStatus,
getUserOrders,
getOrderStatusesByOrderIds,
getItemCountsByOrderIds,
upsertUserSuspension,
searchUsers,
getAllNotifCreds,
getAllUnloggedTokens,
getNotifTokensByUserIds,
getUserIncidentsWithRelations,
createUserIncident,
// Admin - Vendor Snippets
checkVendorSnippetExists,
getVendorSnippetById,
getVendorSnippetByCode,
getAllVendorSnippets,
createVendorSnippet,
updateVendorSnippet,
deleteVendorSnippet,
getProductsByIds,
getVendorSlotById,
getVendorOrdersBySlotId,
getOrderItemsByOrderIds,
getOrderStatusByOrderIds,
updateVendorOrderItemPackaging,
getVendorOrders,
// User - Address
getUserDefaultAddress,
getUserAddresses,
getUserAddressById,
clearUserDefaultAddress,
createUserAddress,
updateUserAddress,
deleteUserAddress,
hasOngoingOrdersForAddress,
// User - Banners
getUserActiveBanners,
// User - Cart
getUserCartItemsWithProducts,
getUserProductById,
getUserCartItemByUserProduct,
incrementUserCartItemQuantity,
insertUserCartItem,
updateUserCartItemQuantity,
deleteUserCartItem,
clearUserCart,
// User - Complaint
getUserComplaints,
createUserComplaint,
// User - Stores
getUserStoreSummaries,
getUserStoreDetail,
// User - Product
getUserProductDetailById,
getUserProductReviews,
getUserProductByIdBasic,
createUserProductReview,
getAllProductsWithUnits,
type ProductSummaryData,
// User - Slots
getUserActiveSlotsList,
getUserProductAvailability,
// User - Payments
getUserPaymentOrderById,
getUserPaymentByOrderId,
getUserPaymentByMerchantOrderId,
updateUserPaymentSuccess,
updateUserOrderPaymentStatus,
markUserPaymentFailed,
// User - Auth
getUserAuthByEmail,
getUserAuthByMobile,
getUserAuthById,
getUserAuthCreds,
getUserAuthDetails,
isUserSuspended,
createUserAuthWithCreds,
createUserAuthWithMobile,
upsertUserAuthPassword,
deleteUserAuthAccount,
// UV API helpers
createUserWithProfile,
getUserDetailsByUserId,
updateUserProfile,
// User - Coupon
getUserActiveCouponsWithRelations,
getUserAllCouponsWithRelations,
getUserReservedCouponByCode,
redeemUserReservedCoupon,
// User - Profile
getUserProfileById,
getUserProfileDetailById,
getUserWithCreds,
getUserNotifCred,
upsertUserNotifCred,
deleteUserUnloggedToken,
getUserUnloggedToken,
upsertUserUnloggedToken,
// User - Order
validateAndGetUserCoupon,
applyDiscountToUserOrder,
getUserAddressByIdAndUser,
getOrderProductById,
checkUserSuspended,
getUserSlotCapacityStatus,
placeUserOrderTransaction,
deleteUserCartItemsForOrder,
recordUserCouponUsage,
getUserOrdersWithRelations,
getUserOrderCount,
getUserOrderByIdWithRelations,
getUserCouponUsageForOrder,
getUserOrderBasic,
cancelUserOrderTransaction,
updateUserOrderNotes,
getUserRecentlyDeliveredOrderIds,
getUserProductIdsFromOrders,
getUserProductsForRecentOrders,
// Store Helpers
getAllBannersForCache,
getAllProductsForCache,
getAllStoresForCache,
getAllDeliverySlotsForCache,
getAllSpecialDealsForCache,
getAllProductTagsForCache,
getAllTagsForCache,
getAllTagProductMappings,
getAllSlotsWithProductsForCache,
getAllUserNegativityScores,
getUserNegativityScore,
type BannerData,
type ProductBasicData,
type StoreBasicData,
type DeliverySlotData,
type SpecialDealData,
type ProductTagData,
type TagBasicData,
type TagProductMapping,
type SlotWithProductsData,
type UserNegativityData,
// Automated Jobs
toggleFlashDeliveryForItems,
toggleKeyVal,
getAllKeyValStore,
// Post-order handler helpers
getOrdersByIdsWithFullData,
getOrderByIdWithFullData,
type OrderWithFullData,
type OrderWithCancellationData,
// Common API helpers
getSuspendedProductIds,
getNextDeliveryDateWithCapacity,
getStoresSummary,
healthCheck,
// Delete orders helper
deleteOrdersWithRelations,
// Seed helpers
seedUnits,
seedStaffRoles,
seedStaffPermissions,
seedRolePermissions,
seedKeyValStore,
type UnitSeedData,
type RolePermissionAssignment,
type KeyValSeedData,
type StaffRoleName,
type StaffPermissionName,
// Upload URL Helpers
createUploadUrlStatus,
claimUploadUrlStatus,
} from 'postgresService'
// // Postgres Importer - Intermediate layer to avoid direct postgresService imports in dbService
// // This file re-exports everything from postgresService
//
// // Re-export database connection
// export { db } from 'postgresService'
//
// // Re-export all schema exports
// export * from 'postgresService'
//
// // Re-export all helper methods from postgresService
// export {
// // Admin - Banner
// getBanners,
// getBannerById,
// createBanner,
// updateBanner,
// deleteBanner,
// // Admin - Complaint
// getComplaints,
// resolveComplaint,
// // Admin - Constants
// getAllConstants,
// upsertConstants,
// // Admin - Coupon
// getAllCoupons,
// getCouponById,
// invalidateCoupon,
// validateCoupon,
// getReservedCoupons,
// getUsersForCoupon,
// createCouponWithRelations,
// updateCouponWithRelations,
// generateCancellationCoupon,
// createReservedCouponWithProducts,
// createCouponForUser,
// checkUsersExist,
// checkCouponExists,
// checkReservedCouponExists,
// getOrderWithUser,
// // Admin - Order
// updateOrderNotes,
// getOrderDetails,
// updateOrderPackaged,
// updateOrderDelivered,
// updateOrderItemPackaging,
// removeDeliveryCharge,
// getSlotOrders,
// updateAddressCoords,
// getAllOrders,
// rebalanceSlots,
// cancelOrder,
// deleteOrderById,
// // Admin - Product
// getAllProducts,
// getProductById,
// deleteProduct,
// createProduct,
// updateProduct,
// checkProductExistsByName,
// checkUnitExists,
// getProductImagesById,
// createSpecialDealsForProduct,
// updateProductDeals,
// replaceProductTags,
// toggleProductOutOfStock,
// updateSlotProducts,
// getSlotProductIds,
// getSlotsProductIds,
// getAllUnits,
// getAllProductTags,
// getAllProductTagInfos,
// getProductTagInfoById,
// createProductTag,
// getProductTagById,
// updateProductTag,
// deleteProductTag,
// checkProductTagExistsByName,
// getProductReviews,
// respondToReview,
// getAllProductGroups,
// createProductGroup,
// updateProductGroup,
// deleteProductGroup,
// addProductToGroup,
// removeProductFromGroup,
// updateProductPrices,
// // Admin - Slots
// getActiveSlotsWithProducts,
// getActiveSlots,
// getSlotsAfterDate,
// getSlotByIdWithRelations,
// createSlotWithRelations,
// updateSlotWithRelations,
// deleteSlotById,
// updateSlotCapacity,
// getSlotDeliverySequence,
// updateSlotDeliverySequence,
// // Admin - Staff User
// getStaffUserByName,
// getStaffUserById,
// getAllStaff,
// getAllUsers,
// getUserWithDetails,
// updateUserSuspensionStatus,
// checkStaffUserExists,
// checkStaffRoleExists,
// createStaffUser,
// getAllRoles,
// // Admin - Store
// getAllStores,
// getStoreById,
// createStore,
// updateStore,
// deleteStore,
// // Admin - User
// createUserByMobile,
// getUserByMobile,
// getUnresolvedComplaintsCount,
// getAllUsersWithFilters,
// getOrderCountsByUserIds,
// getLastOrdersByUserIds,
// getSuspensionStatusesByUserIds,
// getUserBasicInfo,
// getUserSuspensionStatus,
// getUserOrders,
// getOrderStatusesByOrderIds,
// getItemCountsByOrderIds,
// upsertUserSuspension,
// searchUsers,
// getAllNotifCreds,
// getAllUnloggedTokens,
// getNotifTokensByUserIds,
// getUserIncidentsWithRelations,
// createUserIncident,
// // Admin - Vendor Snippets
// checkVendorSnippetExists,
// getVendorSnippetById,
// getVendorSnippetByCode,
// getAllVendorSnippets,
// createVendorSnippet,
// updateVendorSnippet,
// deleteVendorSnippet,
// getProductsByIds,
// getVendorSlotById,
// getVendorOrdersBySlotId,
// getOrderItemsByOrderIds,
// getOrderStatusByOrderIds,
// updateVendorOrderItemPackaging,
// getVendorOrders,
// // User - Address
// getUserDefaultAddress,
// getUserAddresses,
// getUserAddressById,
// clearUserDefaultAddress,
// createUserAddress,
// updateUserAddress,
// deleteUserAddress,
// hasOngoingOrdersForAddress,
// // User - Banners
// getUserActiveBanners,
// // User - Cart
// getUserCartItemsWithProducts,
// getUserProductById,
// getUserCartItemByUserProduct,
// incrementUserCartItemQuantity,
// insertUserCartItem,
// updateUserCartItemQuantity,
// deleteUserCartItem,
// clearUserCart,
// // User - Complaint
// getUserComplaints,
// createUserComplaint,
// // User - Stores
// getUserStoreSummaries,
// getUserStoreDetail,
// // User - Product
// getUserProductDetailById,
// getUserProductReviews,
// getUserProductByIdBasic,
// createUserProductReview,
// getAllProductsWithUnits,
// type ProductSummaryData,
// // User - Slots
// getUserActiveSlotsList,
// getUserProductAvailability,
// // User - Payments
// getUserPaymentOrderById,
// getUserPaymentByOrderId,
// getUserPaymentByMerchantOrderId,
// updateUserPaymentSuccess,
// updateUserOrderPaymentStatus,
// markUserPaymentFailed,
// // User - Auth
// getUserAuthByEmail,
// getUserAuthByMobile,
// getUserAuthById,
// getUserAuthCreds,
// getUserAuthDetails,
// isUserSuspended,
// createUserAuthWithCreds,
// createUserAuthWithMobile,
// upsertUserAuthPassword,
// deleteUserAuthAccount,
// // UV API helpers
// createUserWithProfile,
// getUserDetailsByUserId,
// updateUserProfile,
// // User - Coupon
// getUserActiveCouponsWithRelations,
// getUserAllCouponsWithRelations,
// getUserReservedCouponByCode,
// redeemUserReservedCoupon,
// // User - Profile
// getUserProfileById,
// getUserProfileDetailById,
// getUserWithCreds,
// getUserNotifCred,
// upsertUserNotifCred,
// deleteUserUnloggedToken,
// getUserUnloggedToken,
// upsertUserUnloggedToken,
// // User - Order
// validateAndGetUserCoupon,
// applyDiscountToUserOrder,
// getUserAddressByIdAndUser,
// getOrderProductById,
// checkUserSuspended,
// getUserSlotCapacityStatus,
// placeUserOrderTransaction,
// deleteUserCartItemsForOrder,
// recordUserCouponUsage,
// getUserOrdersWithRelations,
// getUserOrderCount,
// getUserOrderByIdWithRelations,
// getUserCouponUsageForOrder,
// getUserOrderBasic,
// cancelUserOrderTransaction,
// updateUserOrderNotes,
// getUserRecentlyDeliveredOrderIds,
// getUserProductIdsFromOrders,
// getUserProductsForRecentOrders,
// // Store Helpers
// getAllBannersForCache,
// getAllProductsForCache,
// getAllStoresForCache,
// getAllDeliverySlotsForCache,
// getAllSpecialDealsForCache,
// getAllProductTagsForCache,
// getAllTagsForCache,
// getAllTagProductMappings,
// getAllSlotsWithProductsForCache,
// getAllUserNegativityScores,
// getUserNegativityScore,
// type BannerData,
// type ProductBasicData,
// type StoreBasicData,
// type DeliverySlotData,
// type SpecialDealData,
// type ProductTagData,
// type TagBasicData,
// type TagProductMapping,
// type SlotWithProductsData,
// type UserNegativityData,
// // Automated Jobs
// toggleFlashDeliveryForItems,
// toggleKeyVal,
// getAllKeyValStore,
// // Post-order handler helpers
// getOrdersByIdsWithFullData,
// getOrderByIdWithFullData,
// type OrderWithFullData,
// type OrderWithCancellationData,
// // Common API helpers
// getSuspendedProductIds,
// getNextDeliveryDateWithCapacity,
// getStoresSummary,
// healthCheck,
// // Delete orders helper
// deleteOrdersWithRelations,
// // Seed helpers
// seedUnits,
// seedStaffRoles,
// seedStaffPermissions,
// seedRolePermissions,
// seedKeyValStore,
// type UnitSeedData,
// type RolePermissionAssignment,
// type KeyValSeedData,
// type StaffRoleName,
// type StaffPermissionName,
// // Upload URL Helpers
// createUploadUrlStatus,
// claimUploadUrlStatus,
// } from 'postgresService'

View file

@ -2,7 +2,17 @@
// This file re-exports everything from sqliteService
// Re-export database connection
export { db, initDb } from 'sqliteService'
import type { D1Database } from '@cloudflare/workers-types'
import { db, initDb as initDbBase } from 'sqliteService'
export { db }
let dbInitialized = false
export const initDb = (database: D1Database) => {
if (dbInitialized) return
initDbBase(database)
dbInitialized = true
}
// Re-export all schema exports
export * from 'sqliteService'

View file

@ -42,7 +42,8 @@ export const initializeAllStores = async (): Promise<void> => {
}
};
export const scheduleStoreInitialization = (): void => {
export const scheduleStoreInitialization = async (): Promise<void> => {
console.log("scheduling store initialization")
const env = (globalThis as { ENV?: { CACHE_CREATOR?: DurableObjectNamespace } }).ENV
if (!env?.CACHE_CREATOR) {
console.warn('CACHE_CREATOR durable object binding not available for store initialization')
@ -50,6 +51,11 @@ export const scheduleStoreInitialization = (): void => {
}
const id = env.CACHE_CREATOR.idFromName('store-init')
const stub = env.CACHE_CREATOR.get(id)
void stub.fetch('https://cache-creator/schedule', { method: 'POST' })
// const stub = env.CACHE_CREATOR.get(id)
const stub = env.CACHE_CREATOR.getByName('store-init')
try {
await stub.fetch('https://cache-creator/schedule', { method: 'POST' })
} catch (error) {
console.error('Failed to schedule store initialization:', error)
}
}

View file

@ -137,7 +137,7 @@ export const bannerRouter = router({
*/
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return banner;
} catch (error) {
@ -204,7 +204,7 @@ export const bannerRouter = router({
*/
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return banner;
} catch (error) {
@ -226,7 +226,7 @@ export const bannerRouter = router({
*/
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return { success: true };
}),

View file

@ -169,7 +169,7 @@ export const productRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: 'Product deleted successfully',
@ -208,7 +208,7 @@ export const productRouter = router({
throw new ApiError('Product not found', 404)
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
product: updatedProduct,
@ -282,7 +282,7 @@ export const productRouter = router({
await Promise.all(uploadUrls.map(url => claimUploadUrl(url)))
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
product: newProduct,
@ -370,7 +370,7 @@ export const productRouter = router({
await Promise.all(uploadUrls.map(url => claimUploadUrl(url)))
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
product: updatedProduct,
@ -430,7 +430,7 @@ export const productRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: "Slot products updated successfully",
@ -439,7 +439,7 @@ export const productRouter = router({
};
*/
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: 'Slot products updated successfully',
@ -701,7 +701,7 @@ export const productRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
group: newGroup,
@ -709,7 +709,7 @@ export const productRouter = router({
};
*/
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
group: newGroup,
@ -761,7 +761,7 @@ export const productRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
group: updatedGroup,
@ -773,7 +773,7 @@ export const productRouter = router({
throw new ApiError('Group not found', 404)
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
group: updatedGroup,
@ -806,7 +806,7 @@ export const productRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: 'Group deleted successfully',
@ -817,7 +817,7 @@ export const productRouter = router({
throw new ApiError('Group not found', 404)
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: 'Group deleted successfully',
@ -881,7 +881,7 @@ export const productRouter = router({
await Promise.all(updatePromises);
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: `Updated prices for ${updates.length} product(s)`,
@ -893,7 +893,7 @@ export const productRouter = router({
throw new ApiError(`Invalid product IDs: ${result.invalidIds.join(', ')}`, 400)
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: `Updated prices for ${result.updatedCount} product(s)`,
@ -967,7 +967,7 @@ export const productRouter = router({
await Promise.all(uploadUrls.map((url) => claimUploadUrl(url)))
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
const { products, ...createdTagInfo } = createdTag
@ -1017,7 +1017,7 @@ export const productRouter = router({
await Promise.all(uploadUrls.map((url) => claimUploadUrl(url)))
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
const { products, ...updatedTagInfo } = updatedTag
@ -1045,7 +1045,7 @@ export const productRouter = router({
await deleteProductTagInDb(input.id)
scheduleStoreInitialization()
await scheduleStoreInitialization()
return { message: 'Tag deleted successfully' }
}),

View file

@ -256,7 +256,7 @@ export const slotsRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: "Slot products updated successfully",
@ -265,7 +265,7 @@ export const slotsRouter = router({
};
*/
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: result.message,
@ -360,7 +360,7 @@ export const slotsRouter = router({
*/
// Reinitialize stores to reflect changes (outside transaction)
scheduleStoreInitialization()
await scheduleStoreInitialization()
return result
}),
@ -543,7 +543,7 @@ export const slotsRouter = router({
}
// Reinitialize stores to reflect changes (outside transaction)
scheduleStoreInitialization()
await scheduleStoreInitialization()
return result
}
@ -582,7 +582,7 @@ export const slotsRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
message: 'Slot deleted successfully',
@ -717,7 +717,7 @@ export const slotsRouter = router({
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
success: true,
@ -730,7 +730,7 @@ export const slotsRouter = router({
throw new ApiError('Slot not found', 404)
}
scheduleStoreInitialization()
await scheduleStoreInitialization()
return result
}),

View file

@ -93,7 +93,7 @@ export const storeRouter = router({
*/
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
store: newStore,
@ -184,7 +184,7 @@ export const storeRouter = router({
*/
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
await scheduleStoreInitialization()
return {
store: updatedStore,
@ -227,7 +227,7 @@ export const storeRouter = router({
*/
// Reinitialize stores to reflect changes (outside transaction)
scheduleStoreInitialization()
await scheduleStoreInitialization()
return result;
}),

View file

@ -7,7 +7,6 @@ import { scaffoldAssetUrl } from '@/src/lib/s3-client'
import {
getUserProfileById as getUserProfileByIdInDb,
getUserProfileDetailById as getUserProfileDetailByIdInDb,
getUserWithCreds as getUserWithCredsInDb,
upsertUserNotifCred as upsertUserNotifCredInDb,
deleteUserUnloggedToken as deleteUserUnloggedTokenInDb,
getUserUnloggedToken as getUserUnloggedTokenInDb,
@ -15,7 +14,6 @@ import {
} from '@/src/dbService'
import type {
UserSelfDataResponse,
UserProfileCompleteResponse,
UserSavePushTokenResponse,
} from '@packages/shared'
@ -69,25 +67,6 @@ export const userRouter = router({
}
}),
checkProfileComplete: protectedProcedure
.query(async ({ ctx }): Promise<UserProfileCompleteResponse> => {
const userId = ctx.user.userId;
if (!userId) {
throw new ApiError('User not authenticated', 401);
}
const result = await getUserWithCredsInDb(userId)
if (!result) {
throw new ApiError('User not found', 404)
}
return {
isComplete: !!(result.user.name && result.user.email && result.creds),
};
}),
savePushToken: publicProcedure
.input(z.object({ token: z.string() }))
.mutation(async ({ input, ctx }): Promise<UserSavePushTokenResponse> => {

View file

@ -4,6 +4,8 @@ import type {
DurableObjectNamespace,
} from '@cloudflare/workers-types'
import { CacheCreator } from './src/jobs/cache-creator'
import { createApp } from './src/app'
import { initDb } from './src/dbService'
import {
handleNotifQueue,
handleOrderPlacedQueue,
@ -31,8 +33,6 @@ export default {
ctx: ExecutionContext
) {
;(globalThis as any).ENV = env
const { createApp } = await import('./src/app')
const { initDb } = await import('./src/dbService')
if (env.DB) {
initDb(env.DB)
}

View file

@ -2,37 +2,58 @@ name = "freshyo-backend"
main = "worker.ts"
compatibility_date = "2024-12-01"
compatibility_flags = ["nodejs_compat"]
routes = [
{ pattern = "api.freshyo.in/*", zone_name = "freshyo.in" }
]
[[d1_databases]]
binding = "DB"
database_name = "freshyo-dev"
database_id = "45e81d12-9043-45ad-a8ba-3b93127dc5ea"
database_id = "ed09e4a2-4b36-472f-8ff3-dd6c704b1b99"
[durable_objects]
bindings = [
{ name = "CACHE_CREATOR", class_name = "CacheCreator" },
]
[[migrations]]
tag = "cache-creator-v1"
new_classes = ["CacheCreator"]
[[queues.producers]]
binding = "NOTIF_QUEUE"
queue = "notif_queue"
queue = "notif-queue-dev"
[[queues.producers]]
binding = "ORDER_PLACED_QUEUE"
queue = "order_placed_queue"
queue = "order-placed-queue-dev"
[[queues.producers]]
binding = "ORDER_CANCELLED_QUEUE"
queue = "order_cancelled_queue"
queue = "order-cancelled-queue-dev"
[[queues.consumers]]
queue = "notif_queue"
queue = "notif-queue-dev"
[[queues.consumers]]
queue = "order_placed_queue"
queue = "order-placed-queue-dev"
[[queues.consumers]]
queue = "order_cancelled_queue"
queue = "order-cancelled-queue-dev"
[observability]
enabled = false
head_sampling_rate = 1
[observability.logs]
enabled = true
head_sampling_rate = 1
persist = true
invocation_logs = true
[observability.traces]
enabled = false
persist = true
head_sampling_rate = 1
[vars]
ENV_MODE = "PROD"

BIN
apps/test2.sqlite Normal file

Binary file not shown.

Binary file not shown.

View file

@ -9,7 +9,6 @@ import { LinearGradient } from "expo-linear-gradient";
import { Ionicons } from "@expo/vector-icons";
import { useAuth } from "@/src/contexts/AuthContext";
import { tw, theme, MyTouchableOpacity, MyText } from "common-ui";
import ProfileChecker from "@/components/ProfileChecker";
import HomeIcon from "@/components/icons/HomeIcon";
import StoresIcon from "@/components/icons/StoresIcon";
import OrderAgainIcon from "@/components/icons/OrderAgainIcon";
@ -114,7 +113,6 @@ export default function Layout() {
}}
/>
</Tabs>
<ProfileChecker />
</>
);
}

View file

@ -9,6 +9,7 @@ import { trpc } from '@/src/trpc-client';
import { Image } from 'expo-image';
import { orderStatusManipulator } from '@/src/lib/string-manipulators';
import { useGetEssentialConsts } from '@/src/hooks/prominent-api-hooks';
import { useUserDetails } from '@/src/contexts/AuthContext';
interface OrderItem {
productName: string;
@ -42,10 +43,13 @@ interface Order {
export default function NextOrderGlimpse() {
const router = useRouter();
const { setNavigationTarget } = useNavigationTarget();
const userDetails = useUserDetails();
const { data: ordersData, isLoading: ordersLoading } = trpc.user.order.getOrders.useQuery({
page: 1,
pageSize: 50,
}, {
enabled: !!userDetails,
});
const { data: essentialConsts } = useGetEssentialConsts();
@ -76,6 +80,10 @@ export default function NextOrderGlimpse() {
const nextOrder = upcomingOrders[0] || null;
if (!userDetails) {
return null;
}
if (ordersLoading) {
return (
<View style={tw`px-6 mb-4`}>

Binary file not shown.

View file

@ -54,7 +54,6 @@ export function useAllProducts() {
export function useStores() {
const cacheUrl = useCacheUrl(CACHE_FILENAMES.stores)
console.log(cacheUrl)
return useQuery<StoresResponse>({
queryKey: ['stores', cacheUrl],
queryFn: async () => {

View file

@ -129,7 +129,7 @@
"zod": "^4.1.12",
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260304.0",
"@cloudflare/workers-types": "^4.20260401.1",
"@types/node": "^24.5.2",
"rimraf": "^6.1.2",
"ts-node-dev": "^2.0.0",
@ -3553,6 +3553,8 @@
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"backend/@cloudflare/workers-types": ["@cloudflare/workers-types@4.20260401.1", "", {}, "sha512-tKBeV/ySfJjbO0qMKkFrstHDdWzZHAcW4vCpO5QaqjB/667y9lhZt9gZyTKeJ0gluIBwpeQ/efBjqRLqpkgw9g=="],
"backend/expo-server-sdk": ["expo-server-sdk@4.0.0", "", { "dependencies": { "node-fetch": "^2.6.0", "promise-limit": "^2.7.0", "promise-retry": "^2.0.1" } }, "sha512-zi83XtG2pqyP3gyn1JIRYkydo2i6HU3CYaWo/VvhZG/F29U+QIDv6LBEUsWf4ddZlVE7c9WN1N8Be49rHgO8OQ=="],
"backend/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],

View file

@ -66,11 +66,11 @@ export async function incrementCacheVersion(): Promise<number> {
if (existing) {
await tx.update(keyValStore)
.set({ value: nextValue })
.set({ value: nextValue +'' })
.where(eq(keyValStore.key, CACHE_VERSION_KEY))
} else {
await tx.insert(keyValStore)
.values({ key: CACHE_VERSION_KEY, value: nextValue })
.values({ key: CACHE_VERSION_KEY, value: nextValue+'' })
}
return nextValue

View file

@ -46,7 +46,7 @@ const numericText = (name: string) =>
})(name)
const timestampText = (name: string) =>
customType<{ data: Date | null; driverData: string | number | null }>({
customType<{ data: Date; driverData: string | number | null }>({
dataType() {
return 'text'
},
@ -56,8 +56,8 @@ const timestampText = (name: string) =>
return String(value)
},
fromDriver(value) {
if (value === null || value === undefined) return null
return coerceDate(value)
if (value === null || value === undefined) return new Date(0)
return coerceDate(value) || new Date(0)
},
})(name)

View file

@ -1,6 +1,7 @@
import { db } from '../db/db_index'
import { productInfo, keyValStore } from '../db/schema'
import { inArray, eq } from 'drizzle-orm'
import { castConstValue } from '../lib/const-keys'
/**
* Toggle flash delivery availability for specific products
@ -28,7 +29,7 @@ export async function toggleKeyVal(
): Promise<void> {
await db
.update(keyValStore)
.set({ value })
.set({ value: value+'' })
.where(eq(keyValStore.key, key))
}
@ -37,5 +38,9 @@ export async function toggleKeyVal(
* @returns Array of all key-value pairs
*/
export async function getAllKeyValStore(): Promise<Array<{ key: string; value: any }>> {
return db.select().from(keyValStore)
const records = await db.select().from(keyValStore)
return records.map((record) => ({
key: record.key,
value: castConstValue(record.key, record.value),
}))
}

View file

@ -8,8 +8,8 @@ type SlotRow = InferSelectModel<typeof deliverySlotInfo>
const mapSlot = (slot: SlotRow): UserDeliverySlot => ({
id: slot.id,
deliveryTime: slot.deliveryTime,
freezeTime: slot.freezeTime,
deliveryTime: slot.deliveryTime!,
freezeTime: slot.freezeTime!,
isActive: slot.isActive,
isFlash: slot.isFlash,
isCapacityFull: slot.isCapacityFull,

Binary file not shown.

View file

@ -1,4 +1,4 @@
import { Client } from 'pg';
import { Client, types as pgTypes } from 'pg';
import Database from 'better-sqlite3';
import { postgresConfig, sqliteConfig, migrationConfig, logConfig } from '../config';
import * as fs from 'fs';
@ -17,6 +17,74 @@ interface ColumnInfo {
isPrimaryKey: boolean;
}
const KOLKATA_OFFSET_MINUTES = 330
const pad = (value: number, size: number = 2) => String(value).padStart(size, '0')
function formatDatePartsInKolkata(
year: number,
month: number,
day: number,
hour: number,
minute: number,
second: number,
millisecond: number
): string {
return `${year}-${pad(month)}-${pad(day)}T${pad(hour)}:${pad(minute)}:${pad(second)}.${pad(millisecond, 3)}Z`
}
function formatDateInKolkata(date: Date): string {
const shifted = new Date(date.getTime() + KOLKATA_OFFSET_MINUTES * 60 * 1000)
return formatDatePartsInKolkata(
shifted.getUTCFullYear(),
shifted.getUTCMonth() + 1,
shifted.getUTCDate(),
shifted.getUTCHours(),
shifted.getUTCMinutes(),
shifted.getUTCSeconds(),
shifted.getUTCMilliseconds()
)
}
function formatStringDateInKolkata(value: string): string | null {
const trimmed = value.trim()
if (!trimmed) return null
const hasTimezone = /[Zz]|[+-]\d{2}:?\d{2}$/.test(trimmed)
if (hasTimezone) {
const parsed = new Date(trimmed)
return Number.isNaN(parsed.getTime()) ? null : formatDateInKolkata(parsed)
}
const match = trimmed.match(
/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,6}))?)?)?$/
)
if (!match) return null
const year = Number(match[1])
const month = Number(match[2])
const day = Number(match[3])
const hour = match[4] ? Number(match[4]) : 0
const minute = match[5] ? Number(match[5]) : 0
const second = match[6] ? Number(match[6]) : 0
const msRaw = match[7] ? match[7].slice(0, 3).padEnd(3, '0') : '000'
const millisecond = Number(msRaw)
if (
Number.isNaN(year) ||
Number.isNaN(month) ||
Number.isNaN(day) ||
Number.isNaN(hour) ||
Number.isNaN(minute) ||
Number.isNaN(second) ||
Number.isNaN(millisecond)
) {
return null
}
return formatDatePartsInKolkata(year, month, day, hour, minute, second, millisecond)
}
/**
* Maps PostgreSQL data types to SQLite data types
*/
@ -224,13 +292,27 @@ async function migrateTableData(
);
const insertMany = sqliteDb.transaction((rows) => {
console.log(rows.at(-1))
for (const row of rows) {
const values = columns.map(col => {
const val = row[col.name];
// Handle special cases
if (val === null || val === undefined) return null;
if (typeof val === 'boolean') return val ? 1 : 0;
if (val instanceof Date) return val.toISOString();
if (val instanceof Date) {
const formattedDate = formatDateInKolkata(val)
console.log({formattedDate, id: row['id']})
return formattedDate
}
if (
typeof val === 'string' &&
(col.type === 'date' || col.type.startsWith('timestamp'))
) {
const formatted = formatStringDateInKolkata(val)
console.log({formatted, id: row['id']})
if (formatted) return formatted
}
if (Array.isArray(val)) return JSON.stringify(val);
if (typeof val === 'object') return JSON.stringify(val);
// Ensure it's a primitive type SQLite can handle
@ -260,6 +342,14 @@ async function migrateTableData(
*/
async function migratePostgresToSqlite(): Promise<void> {
console.log('Starting PostgreSQL to SQLite migration...\n');
pgTypes.setTypeParser(1114, (value) => value)
pgTypes.setTypeParser(1184, (value) => value)
pgTypes.setTypeParser(1082, (value) => value)
pgTypes.setTypeParser(1114, (value) => value)
pgTypes.setTypeParser(1184, (value) => value)
pgTypes.setTypeParser(1082, (value) => value)
// Ensure SQLite directory exists
const sqliteDir = path.dirname(sqliteConfig.filename);
@ -287,7 +377,8 @@ async function migratePostgresToSqlite(): Promise<void> {
try {
// Get all tables
const tables = await getPostgresTables(pgClient);
let tables = await getPostgresTables(pgClient);
// tables = tables.filter(item => item === 'delivery_slot_info')
console.log(`\nFound ${tables.length} tables to migrate\n`);
let totalMigrated = 0;

View file

@ -65,10 +65,11 @@ const isDevMode = Constants.executionEnvironment !== "standalone";
// const BASE_API_URL = 'http://10.0.2.2:4000';
// const BASE_API_URL = 'http://192.168.100.101:4000';
// const BASE_API_URL = 'http://192.168.1.5:4000';
const BASE_API_URL = 'http://192.168.1.5:8787';
// const BASE_API_URL = 'http://192.168.1.5:8787';
// let BASE_API_URL = "https://mf.freshyo.in";
let BASE_API_URL = "https://worker.freshyo.in";
// let BASE_API_URL = "https://freshyo.technocracy.ovh";
// let BASE_API_URL = 'http://192.168.100.107:4000';
// let BASE_API_URL = 'http://192.168.100.109:8787';
// let BASE_API_URL = 'http://192.168.29.176:4000';
// if(isDevMode) {