@instockng/api-client 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/enum-types.d.ts +8 -0
- package/dist/enum-types.js +5 -0
- package/dist/fetchers/carts.js +5 -0
- package/dist/hooks/admin/abandoned-carts.js +12 -8
- package/dist/hooks/admin/brands.js +15 -10
- package/dist/hooks/admin/customers.js +3 -2
- package/dist/hooks/admin/delivery-zones.js +24 -16
- package/dist/hooks/admin/discount-codes.js +24 -16
- package/dist/hooks/admin/inventory.js +15 -10
- package/dist/hooks/admin/orders.js +18 -12
- package/dist/hooks/admin/products.js +15 -10
- package/dist/hooks/admin/stats.js +3 -2
- package/dist/hooks/admin/variants.js +18 -12
- package/dist/hooks/admin/warehouses.js +15 -10
- package/dist/hooks/useApiConfig.d.ts +2 -1
- package/dist/hooks/useApiConfig.js +2 -2
- package/dist/provider.d.ts +7 -4
- package/dist/provider.js +5 -3
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/dist/apps/backend/src/generated/zod/index.d.ts +0 -1114
- package/dist/apps/backend/src/generated/zod/index.js +0 -670
- package/dist/apps/backend/src/http-app.d.ts +0 -40
- package/dist/apps/backend/src/http-app.js +0 -106
- package/dist/apps/backend/src/lib/brand-response.d.ts +0 -14
- package/dist/apps/backend/src/lib/brand-response.js +0 -8
- package/dist/apps/backend/src/lib/cart-helpers.d.ts +0 -280
- package/dist/apps/backend/src/lib/cart-helpers.js +0 -93
- package/dist/apps/backend/src/lib/cart-recovery.d.ts +0 -30
- package/dist/apps/backend/src/lib/cart-recovery.js +0 -147
- package/dist/apps/backend/src/lib/cart-response.d.ts +0 -121
- package/dist/apps/backend/src/lib/cart-response.js +0 -150
- package/dist/apps/backend/src/lib/clerk.d.ts +0 -18
- package/dist/apps/backend/src/lib/clerk.js +0 -167
- package/dist/apps/backend/src/lib/delivery-zone-response.d.ts +0 -62
- package/dist/apps/backend/src/lib/delivery-zone-response.js +0 -24
- package/dist/apps/backend/src/lib/discount-code-response.d.ts +0 -42
- package/dist/apps/backend/src/lib/discount-code-response.js +0 -19
- package/dist/apps/backend/src/lib/discount.d.ts +0 -20
- package/dist/apps/backend/src/lib/discount.js +0 -35
- package/dist/apps/backend/src/lib/inventory.d.ts +0 -26
- package/dist/apps/backend/src/lib/inventory.js +0 -160
- package/dist/apps/backend/src/lib/meta-capi.d.ts +0 -48
- package/dist/apps/backend/src/lib/meta-capi.js +0 -120
- package/dist/apps/backend/src/lib/openapi.d.ts +0 -36
- package/dist/apps/backend/src/lib/openapi.js +0 -69
- package/dist/apps/backend/src/lib/order-recovery.d.ts +0 -367
- package/dist/apps/backend/src/lib/order-recovery.js +0 -373
- package/dist/apps/backend/src/lib/order-response.d.ts +0 -136
- package/dist/apps/backend/src/lib/order-response.js +0 -61
- package/dist/apps/backend/src/lib/pricing.d.ts +0 -39
- package/dist/apps/backend/src/lib/pricing.js +0 -62
- package/dist/apps/backend/src/lib/prisma.d.ts +0 -9
- package/dist/apps/backend/src/lib/prisma.js +0 -30
- package/dist/apps/backend/src/lib/product-response.d.ts +0 -82
- package/dist/apps/backend/src/lib/product-response.js +0 -29
- package/dist/apps/backend/src/lib/utils.d.ts +0 -32
- package/dist/apps/backend/src/lib/utils.js +0 -63
- package/dist/apps/backend/src/middleware/clerk-auth.d.ts +0 -8
- package/dist/apps/backend/src/middleware/clerk-auth.js +0 -89
- package/dist/apps/backend/src/middleware/cors.d.ts +0 -8
- package/dist/apps/backend/src/middleware/cors.js +0 -11
- package/dist/apps/backend/src/notifications/producers/meta-capi-producer.d.ts +0 -55
- package/dist/apps/backend/src/notifications/producers/meta-capi-producer.js +0 -125
- package/dist/apps/backend/src/notifications/producers/order-notification.d.ts +0 -9
- package/dist/apps/backend/src/notifications/producers/order-notification.js +0 -18
- package/dist/apps/backend/src/notifications/producers/prospect-recovery-notification.d.ts +0 -10
- package/dist/apps/backend/src/notifications/producers/prospect-recovery-notification.js +0 -11
- package/dist/apps/backend/src/routes/admin/abandoned-carts.d.ts +0 -605
- package/dist/apps/backend/src/routes/admin/abandoned-carts.js +0 -194
- package/dist/apps/backend/src/routes/admin/brands.d.ts +0 -175
- package/dist/apps/backend/src/routes/admin/brands.js +0 -118
- package/dist/apps/backend/src/routes/admin/customers.d.ts +0 -306
- package/dist/apps/backend/src/routes/admin/customers.js +0 -39
- package/dist/apps/backend/src/routes/admin/delivery-zones.d.ts +0 -438
- package/dist/apps/backend/src/routes/admin/delivery-zones.js +0 -300
- package/dist/apps/backend/src/routes/admin/discount-codes.d.ts +0 -478
- package/dist/apps/backend/src/routes/admin/discount-codes.js +0 -418
- package/dist/apps/backend/src/routes/admin/inventory.d.ts +0 -273
- package/dist/apps/backend/src/routes/admin/inventory.js +0 -189
- package/dist/apps/backend/src/routes/admin/orders.d.ts +0 -1478
- package/dist/apps/backend/src/routes/admin/orders.js +0 -503
- package/dist/apps/backend/src/routes/admin/products.d.ts +0 -860
- package/dist/apps/backend/src/routes/admin/products.js +0 -107
- package/dist/apps/backend/src/routes/admin/stats.d.ts +0 -288
- package/dist/apps/backend/src/routes/admin/stats.js +0 -55
- package/dist/apps/backend/src/routes/admin/variants.d.ts +0 -239
- package/dist/apps/backend/src/routes/admin/variants.js +0 -173
- package/dist/apps/backend/src/routes/admin/warehouses.d.ts +0 -373
- package/dist/apps/backend/src/routes/admin/warehouses.js +0 -123
- package/dist/apps/backend/src/routes/public/brands.d.ts +0 -40
- package/dist/apps/backend/src/routes/public/brands.js +0 -38
- package/dist/apps/backend/src/routes/public/carts.d.ts +0 -2655
- package/dist/apps/backend/src/routes/public/carts.js +0 -631
- package/dist/apps/backend/src/routes/public/delivery-zones.d.ts +0 -35
- package/dist/apps/backend/src/routes/public/delivery-zones.js +0 -62
- package/dist/apps/backend/src/routes/public/orders.d.ts +0 -323
- package/dist/apps/backend/src/routes/public/orders.js +0 -160
- package/dist/apps/backend/src/routes/public/products.d.ts +0 -449
- package/dist/apps/backend/src/routes/public/products.js +0 -133
- package/dist/apps/backend/src/types/index.d.ts +0 -42
- package/dist/apps/backend/src/types/index.js +0 -2
- package/dist/apps/backend/src/validators/brand.d.ts +0 -17
- package/dist/apps/backend/src/validators/brand.js +0 -15
- package/dist/apps/backend/src/validators/delivery-zone.d.ts +0 -31
- package/dist/apps/backend/src/validators/delivery-zone.js +0 -51
- package/dist/apps/backend/src/validators/discount-code.d.ts +0 -74
- package/dist/apps/backend/src/validators/discount-code.js +0 -50
- package/dist/apps/backend/src/validators/inventory.d.ts +0 -20
- package/dist/apps/backend/src/validators/inventory.js +0 -15
- package/dist/apps/backend/src/validators/order.d.ts +0 -87
- package/dist/apps/backend/src/validators/order.js +0 -61
- package/dist/apps/backend/src/validators/product.d.ts +0 -18
- package/dist/apps/backend/src/validators/product.js +0 -19
- package/dist/apps/backend/src/validators/variant.d.ts +0 -19
- package/dist/apps/backend/src/validators/variant.js +0 -19
- package/dist/apps/backend/src/validators/warehouse.d.ts +0 -15
- package/dist/apps/backend/src/validators/warehouse.js +0 -15
- package/dist/packages/api-client/src/backend-types.d.ts +0 -10
- package/dist/packages/api-client/src/backend-types.js +0 -10
- package/dist/packages/api-client/src/client.d.ts +0 -20
- package/dist/packages/api-client/src/client.js +0 -40
- package/dist/packages/api-client/src/fetchers/brands.d.ts +0 -25
- package/dist/packages/api-client/src/fetchers/brands.js +0 -26
- package/dist/packages/api-client/src/fetchers/carts.d.ts +0 -2335
- package/dist/packages/api-client/src/fetchers/carts.js +0 -169
- package/dist/packages/api-client/src/fetchers/delivery-zones.d.ts +0 -28
- package/dist/packages/api-client/src/fetchers/delivery-zones.js +0 -26
- package/dist/packages/api-client/src/fetchers/index.d.ts +0 -22
- package/dist/packages/api-client/src/fetchers/index.js +0 -22
- package/dist/packages/api-client/src/fetchers/orders.d.ts +0 -283
- package/dist/packages/api-client/src/fetchers/orders.js +0 -44
- package/dist/packages/api-client/src/fetchers/products.d.ts +0 -386
- package/dist/packages/api-client/src/fetchers/products.js +0 -42
- package/dist/packages/api-client/src/hooks/admin/abandoned-carts.d.ts +0 -535
- package/dist/packages/api-client/src/hooks/admin/abandoned-carts.js +0 -83
- package/dist/packages/api-client/src/hooks/admin/brands.d.ts +0 -79
- package/dist/packages/api-client/src/hooks/admin/brands.js +0 -108
- package/dist/packages/api-client/src/hooks/admin/customers.d.ts +0 -278
- package/dist/packages/api-client/src/hooks/admin/customers.js +0 -26
- package/dist/packages/api-client/src/hooks/admin/delivery-zones.d.ts +0 -270
- package/dist/packages/api-client/src/hooks/admin/delivery-zones.js +0 -176
- package/dist/packages/api-client/src/hooks/admin/discount-codes.d.ts +0 -299
- package/dist/packages/api-client/src/hooks/admin/discount-codes.js +0 -165
- package/dist/packages/api-client/src/hooks/admin/index.d.ts +0 -16
- package/dist/packages/api-client/src/hooks/admin/index.js +0 -16
- package/dist/packages/api-client/src/hooks/admin/inventory.d.ts +0 -224
- package/dist/packages/api-client/src/hooks/admin/inventory.js +0 -107
- package/dist/packages/api-client/src/hooks/admin/orders.d.ts +0 -1380
- package/dist/packages/api-client/src/hooks/admin/orders.js +0 -175
- package/dist/packages/api-client/src/hooks/admin/products.d.ts +0 -374
- package/dist/packages/api-client/src/hooks/admin/products.js +0 -89
- package/dist/packages/api-client/src/hooks/admin/stats.d.ts +0 -277
- package/dist/packages/api-client/src/hooks/admin/stats.js +0 -25
- package/dist/packages/api-client/src/hooks/admin/variants.d.ts +0 -115
- package/dist/packages/api-client/src/hooks/admin/variants.js +0 -127
- package/dist/packages/api-client/src/hooks/admin/warehouses.d.ts +0 -277
- package/dist/packages/api-client/src/hooks/admin/warehouses.js +0 -108
- package/dist/packages/api-client/src/hooks/public/brands.d.ts +0 -33
- package/dist/packages/api-client/src/hooks/public/brands.js +0 -30
- package/dist/packages/api-client/src/hooks/public/carts.d.ts +0 -2405
- package/dist/packages/api-client/src/hooks/public/carts.js +0 -213
- package/dist/packages/api-client/src/hooks/public/delivery-zones.d.ts +0 -34
- package/dist/packages/api-client/src/hooks/public/delivery-zones.js +0 -28
- package/dist/packages/api-client/src/hooks/public/index.d.ts +0 -10
- package/dist/packages/api-client/src/hooks/public/index.js +0 -10
- package/dist/packages/api-client/src/hooks/public/orders.d.ts +0 -302
- package/dist/packages/api-client/src/hooks/public/orders.js +0 -50
- package/dist/packages/api-client/src/hooks/public/products.d.ts +0 -398
- package/dist/packages/api-client/src/hooks/public/products.js +0 -47
- package/dist/packages/api-client/src/hooks/use-query-unwrapped.d.ts +0 -20
- package/dist/packages/api-client/src/hooks/use-query-unwrapped.js +0 -22
- package/dist/packages/api-client/src/hooks/useApiConfig.d.ts +0 -12
- package/dist/packages/api-client/src/hooks/useApiConfig.js +0 -14
- package/dist/packages/api-client/src/index.d.ts +0 -20
- package/dist/packages/api-client/src/index.js +0 -25
- package/dist/packages/api-client/src/provider.d.ts +0 -36
- package/dist/packages/api-client/src/provider.js +0 -54
- package/dist/packages/api-client/src/rpc-client.d.ts +0 -9035
- package/dist/packages/api-client/src/rpc-client.js +0 -78
- package/dist/packages/api-client/src/rpc-types.d.ts +0 -76
- package/dist/packages/api-client/src/rpc-types.js +0 -7
- package/dist/packages/api-client/src/types.d.ts +0 -37
- package/dist/packages/api-client/src/types.js +0 -16
- package/dist/packages/api-client/src/utils/query-keys.d.ts +0 -106
- package/dist/packages/api-client/src/utils/query-keys.js +0 -108
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { PrismaClient } from '@prisma/client';
|
|
2
|
-
import { PrismaNeon } from '@prisma/adapter-neon';
|
|
3
|
-
import { neonConfig } from '@neondatabase/serverless';
|
|
4
|
-
// Configure Neon for WebSocket connections globally (required for Cloudflare Workers)
|
|
5
|
-
// @ts-ignore-next-line
|
|
6
|
-
neonConfig.webSocketConstructor = WebSocket;
|
|
7
|
-
/**
|
|
8
|
-
* Creates a new Prisma client for each request.
|
|
9
|
-
*
|
|
10
|
-
* IMPORTANT: In Cloudflare Workers, we CANNOT use a singleton pattern because
|
|
11
|
-
* I/O objects (like database connections) cannot be shared across different requests.
|
|
12
|
-
* Each request must create its own Prisma instance.
|
|
13
|
-
*/
|
|
14
|
-
export function getPrismaClient(databaseUrl) {
|
|
15
|
-
if (!databaseUrl) {
|
|
16
|
-
throw new Error('DATABASE_URL is required but not provided');
|
|
17
|
-
}
|
|
18
|
-
// Prisma 6.6.0+ changed the Driver Adapters API
|
|
19
|
-
// The adapter now takes connectionString directly, not a Pool
|
|
20
|
-
const adapter = new PrismaNeon({ connectionString: databaseUrl });
|
|
21
|
-
// Create a new Prisma Client for this request
|
|
22
|
-
const prisma = new PrismaClient({
|
|
23
|
-
adapter,
|
|
24
|
-
log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
|
|
25
|
-
});
|
|
26
|
-
return prisma;
|
|
27
|
-
}
|
|
28
|
-
// Note: Prisma v6 removed $use middleware API
|
|
29
|
-
// Soft delete logic is now handled directly in queries (where: { deletedAt: null })
|
|
30
|
-
// For soft deletes, use: prisma.model.update({ where: { id }, data: { deletedAt: new Date() } })
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Prisma } from '@prisma/client';
|
|
2
|
-
export declare const PRODUCT_INCLUDE_FULL: {
|
|
3
|
-
brand: boolean;
|
|
4
|
-
variants: {
|
|
5
|
-
where: {
|
|
6
|
-
deletedAt: any;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
export declare const PRODUCT_INCLUDE_FULL_PUBLIC: {
|
|
11
|
-
brand: boolean;
|
|
12
|
-
variants: {
|
|
13
|
-
where: {
|
|
14
|
-
isActive: boolean;
|
|
15
|
-
deletedAt: any;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
export type ProductDBResponse = Prisma.ProductGetPayload<{
|
|
20
|
-
include: {
|
|
21
|
-
brand: true;
|
|
22
|
-
variants: true;
|
|
23
|
-
};
|
|
24
|
-
}>;
|
|
25
|
-
export type ProductVariantDBResponse = Prisma.ProductVariantGetPayload<{
|
|
26
|
-
include: {
|
|
27
|
-
product: false;
|
|
28
|
-
};
|
|
29
|
-
}>;
|
|
30
|
-
export declare function formatProductResponse(product: ProductDBResponse): {
|
|
31
|
-
brand: {
|
|
32
|
-
createdAt: string;
|
|
33
|
-
updatedAt: string;
|
|
34
|
-
deletedAt: string;
|
|
35
|
-
name: string;
|
|
36
|
-
id: string;
|
|
37
|
-
slug: string;
|
|
38
|
-
logoUrl: string | null;
|
|
39
|
-
siteUrl: string;
|
|
40
|
-
domain: string;
|
|
41
|
-
metaPixelId: string | null;
|
|
42
|
-
};
|
|
43
|
-
variants: {
|
|
44
|
-
createdAt: string;
|
|
45
|
-
updatedAt: string;
|
|
46
|
-
price: number;
|
|
47
|
-
deletedAt: string;
|
|
48
|
-
name: string | null;
|
|
49
|
-
id: string;
|
|
50
|
-
isActive: boolean;
|
|
51
|
-
thumbnailUrl: string | null;
|
|
52
|
-
productId: string;
|
|
53
|
-
sku: string;
|
|
54
|
-
trackInventory: boolean;
|
|
55
|
-
lowStockThreshold: number | null;
|
|
56
|
-
}[];
|
|
57
|
-
name: string;
|
|
58
|
-
id: string;
|
|
59
|
-
slug: string;
|
|
60
|
-
createdAt: Date;
|
|
61
|
-
updatedAt: Date;
|
|
62
|
-
deletedAt: Date | null;
|
|
63
|
-
brandId: string;
|
|
64
|
-
isActive: boolean;
|
|
65
|
-
description: string | null;
|
|
66
|
-
thumbnailUrl: string | null;
|
|
67
|
-
quantityDiscounts: Prisma.JsonValue | null;
|
|
68
|
-
};
|
|
69
|
-
export declare function formatProductVariantResponse(variant: ProductVariantDBResponse): {
|
|
70
|
-
createdAt: string;
|
|
71
|
-
updatedAt: string;
|
|
72
|
-
price: number;
|
|
73
|
-
deletedAt: string;
|
|
74
|
-
name: string | null;
|
|
75
|
-
id: string;
|
|
76
|
-
isActive: boolean;
|
|
77
|
-
thumbnailUrl: string | null;
|
|
78
|
-
productId: string;
|
|
79
|
-
sku: string;
|
|
80
|
-
trackInventory: boolean;
|
|
81
|
-
lowStockThreshold: number | null;
|
|
82
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { formatBrandResponse } from './brand-response';
|
|
2
|
-
export const PRODUCT_INCLUDE_FULL = {
|
|
3
|
-
brand: true,
|
|
4
|
-
variants: {
|
|
5
|
-
where: { deletedAt: null },
|
|
6
|
-
},
|
|
7
|
-
};
|
|
8
|
-
export const PRODUCT_INCLUDE_FULL_PUBLIC = {
|
|
9
|
-
brand: true,
|
|
10
|
-
variants: {
|
|
11
|
-
where: { isActive: true, deletedAt: null },
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
export function formatProductResponse(product) {
|
|
15
|
-
return {
|
|
16
|
-
...product,
|
|
17
|
-
brand: formatBrandResponse(product.brand),
|
|
18
|
-
variants: product.variants.map(formatProductVariantResponse),
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export function formatProductVariantResponse(variant) {
|
|
22
|
-
return {
|
|
23
|
-
...variant,
|
|
24
|
-
createdAt: variant.createdAt.toISOString(),
|
|
25
|
-
updatedAt: variant.updatedAt.toISOString(),
|
|
26
|
-
price: parseFloat(variant.price.toString()),
|
|
27
|
-
deletedAt: variant.deletedAt ? variant.deletedAt.toISOString() : null,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Decimal } from '@prisma/client/runtime/library';
|
|
2
|
-
export { WHATSAPP_HELP_NUMBER, WHATSAPP_HELP_NUMBER_FORMATTED, WHATSAPP_HELP_LINK } from '@oms/shared';
|
|
3
|
-
/**
|
|
4
|
-
* Convert Decimal to number for JSON responses
|
|
5
|
-
*/
|
|
6
|
-
export declare function toNumber(value: number | Decimal): number;
|
|
7
|
-
/**
|
|
8
|
-
* Round to 2 decimal places (for monetary values in Naira)
|
|
9
|
-
*/
|
|
10
|
-
export declare function round(value: number): number;
|
|
11
|
-
export declare function formatCurrency(amount: number | string | Decimal | null | undefined): string;
|
|
12
|
-
export declare function formatDate(date: Date | string): string;
|
|
13
|
-
export interface PaginationParams {
|
|
14
|
-
page?: number;
|
|
15
|
-
limit?: number;
|
|
16
|
-
}
|
|
17
|
-
export interface PaginatedResponse<T> {
|
|
18
|
-
data: T[];
|
|
19
|
-
pagination: {
|
|
20
|
-
page: number;
|
|
21
|
-
limit: number;
|
|
22
|
-
total: number;
|
|
23
|
-
totalPages: number;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
export declare function getPaginationParams(params: PaginationParams): {
|
|
27
|
-
page: number;
|
|
28
|
-
limit: number;
|
|
29
|
-
skip: number;
|
|
30
|
-
};
|
|
31
|
-
export declare function createPaginatedResponse<T>(data: T[], total: number, page: number, limit: number): PaginatedResponse<T>;
|
|
32
|
-
export declare function generateSlug(text: string): string;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// Re-export shared constants
|
|
2
|
-
export { WHATSAPP_HELP_NUMBER, WHATSAPP_HELP_NUMBER_FORMATTED, WHATSAPP_HELP_LINK } from '@oms/shared';
|
|
3
|
-
/**
|
|
4
|
-
* Convert Decimal to number for JSON responses
|
|
5
|
-
*/
|
|
6
|
-
export function toNumber(value) {
|
|
7
|
-
if (typeof value === 'number')
|
|
8
|
-
return value;
|
|
9
|
-
return parseFloat(value.toString());
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Round to 2 decimal places (for monetary values in Naira)
|
|
13
|
-
*/
|
|
14
|
-
export function round(value) {
|
|
15
|
-
return Math.round(value * 100) / 100;
|
|
16
|
-
}
|
|
17
|
-
export function formatCurrency(amount) {
|
|
18
|
-
if (amount === null || amount === undefined) {
|
|
19
|
-
return '₦0.00';
|
|
20
|
-
}
|
|
21
|
-
const numericAmount = typeof amount === 'string' ? parseFloat(amount) : toNumber(amount) ?? 0;
|
|
22
|
-
if (isNaN(numericAmount)) {
|
|
23
|
-
return '₦0.00';
|
|
24
|
-
}
|
|
25
|
-
return new Intl.NumberFormat('en-US', {
|
|
26
|
-
style: 'currency',
|
|
27
|
-
currency: 'NGN',
|
|
28
|
-
}).format(numericAmount);
|
|
29
|
-
}
|
|
30
|
-
export function formatDate(date) {
|
|
31
|
-
const d = typeof date === 'string' ? new Date(date) : date;
|
|
32
|
-
return d.toLocaleDateString('en-US', {
|
|
33
|
-
year: 'numeric',
|
|
34
|
-
month: 'long',
|
|
35
|
-
day: 'numeric',
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
export function getPaginationParams(params) {
|
|
39
|
-
const page = Math.max(1, params.page || 1);
|
|
40
|
-
const limit = Math.min(100, Math.max(1, params.limit || 20));
|
|
41
|
-
const skip = (page - 1) * limit;
|
|
42
|
-
return { page, limit, skip };
|
|
43
|
-
}
|
|
44
|
-
export function createPaginatedResponse(data, total, page, limit) {
|
|
45
|
-
return {
|
|
46
|
-
data,
|
|
47
|
-
pagination: {
|
|
48
|
-
page,
|
|
49
|
-
limit,
|
|
50
|
-
total,
|
|
51
|
-
totalPages: Math.ceil(total / limit),
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
// Generate a URL-friendly slug from a string
|
|
56
|
-
export function generateSlug(text) {
|
|
57
|
-
return text
|
|
58
|
-
.toLowerCase()
|
|
59
|
-
.trim()
|
|
60
|
-
.replace(/[^\w\s-]/g, '') // Remove non-word chars (except spaces and hyphens)
|
|
61
|
-
.replace(/[\s_-]+/g, '-') // Replace spaces, underscores, and multiple hyphens with single hyphen
|
|
62
|
-
.replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
|
|
63
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { verifyClerkToken, extractBearerToken } from '../lib/clerk';
|
|
2
|
-
import { getPrismaClient } from '../lib/prisma';
|
|
3
|
-
export async function clerkAuthMiddleware(c, next) {
|
|
4
|
-
const authHeader = c.req.header('Authorization');
|
|
5
|
-
const token = extractBearerToken(authHeader);
|
|
6
|
-
console.log('Authenticating request with token');
|
|
7
|
-
if (!token) {
|
|
8
|
-
return c.json({
|
|
9
|
-
success: false,
|
|
10
|
-
error: {
|
|
11
|
-
code: 'UNAUTHORIZED',
|
|
12
|
-
message: 'Missing authentication token',
|
|
13
|
-
},
|
|
14
|
-
}, 401);
|
|
15
|
-
}
|
|
16
|
-
const clerkUser = await verifyClerkToken(token, c.env.CLERK_PUBLISHABLE_KEY);
|
|
17
|
-
console.log(clerkUser);
|
|
18
|
-
if (!clerkUser) {
|
|
19
|
-
return c.json({
|
|
20
|
-
success: false,
|
|
21
|
-
error: {
|
|
22
|
-
code: 'UNAUTHORIZED',
|
|
23
|
-
message: 'Invalid authentication token',
|
|
24
|
-
},
|
|
25
|
-
}, 401);
|
|
26
|
-
}
|
|
27
|
-
// Ensure user exists in database (auto-provisioning)
|
|
28
|
-
const prisma = getPrismaClient(c.env.DATABASE_URL);
|
|
29
|
-
// First check if user exists
|
|
30
|
-
let dbUser = await prisma.user.findUnique({
|
|
31
|
-
where: { clerkId: clerkUser.id },
|
|
32
|
-
});
|
|
33
|
-
// If user doesn't exist, fetch their details from Clerk API and create them
|
|
34
|
-
if (!dbUser) {
|
|
35
|
-
console.log('User not found in database, fetching details from Clerk API');
|
|
36
|
-
try {
|
|
37
|
-
const userResponse = await fetch(`https://api.clerk.com/v1/users/${clerkUser.id}`, {
|
|
38
|
-
headers: {
|
|
39
|
-
Authorization: `Bearer ${c.env.CLERK_SECRET_KEY}`,
|
|
40
|
-
'Content-Type': 'application/json',
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
if (userResponse.ok) {
|
|
44
|
-
const userData = await userResponse.json();
|
|
45
|
-
console.log('Fetched user data from Clerk API');
|
|
46
|
-
const email = userData.email_addresses?.[0]?.email_address || userData.primary_email_address || `${clerkUser.id}@unknown.clerk`;
|
|
47
|
-
const name = userData.first_name && userData.last_name
|
|
48
|
-
? `${userData.first_name} ${userData.last_name}`.trim()
|
|
49
|
-
: userData.first_name || userData.last_name || null;
|
|
50
|
-
dbUser = await prisma.user.create({
|
|
51
|
-
data: {
|
|
52
|
-
clerkId: clerkUser.id,
|
|
53
|
-
email,
|
|
54
|
-
name,
|
|
55
|
-
role: 'admin',
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
console.error('Failed to fetch user from Clerk API:', userResponse.status);
|
|
61
|
-
// Create user with minimal info
|
|
62
|
-
dbUser = await prisma.user.create({
|
|
63
|
-
data: {
|
|
64
|
-
clerkId: clerkUser.id,
|
|
65
|
-
email: `${clerkUser.id}@unknown.clerk`,
|
|
66
|
-
name: null,
|
|
67
|
-
role: 'admin',
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
console.error('Error fetching user from Clerk API:', error);
|
|
74
|
-
// Create user with minimal info
|
|
75
|
-
dbUser = await prisma.user.create({
|
|
76
|
-
data: {
|
|
77
|
-
clerkId: clerkUser.id,
|
|
78
|
-
email: `${clerkUser.id}@unknown.clerk`,
|
|
79
|
-
name: null,
|
|
80
|
-
role: 'admin',
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// Store both Clerk user and database user in context for later use
|
|
86
|
-
c.set('user', clerkUser);
|
|
87
|
-
c.set('dbUser', dbUser);
|
|
88
|
-
await next();
|
|
89
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { HonoRequest, Next } from 'hono';
|
|
2
|
-
import { Env } from '../types';
|
|
3
|
-
export declare function corsMiddleware(c: {
|
|
4
|
-
env: Env;
|
|
5
|
-
req: HonoRequest;
|
|
6
|
-
header: (name: string, value: string) => void;
|
|
7
|
-
body: (body: any, status: number) => Response;
|
|
8
|
-
}, next: Next): Promise<Response>;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export async function corsMiddleware(c, next) {
|
|
2
|
-
c.header('Access-Control-Allow-Origin', '*');
|
|
3
|
-
c.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
4
|
-
c.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key');
|
|
5
|
-
c.header('Access-Control-Allow-Credentials', 'true');
|
|
6
|
-
// Handle preflight requests
|
|
7
|
-
if (c.req.method === 'OPTIONS') {
|
|
8
|
-
return c.body(null, 204);
|
|
9
|
-
}
|
|
10
|
-
await next();
|
|
11
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Meta Conversions API Event Producer
|
|
3
|
-
*
|
|
4
|
-
* Queues Meta CAPI events for processing by the queue consumer.
|
|
5
|
-
*/
|
|
6
|
-
import { Env } from '../../types';
|
|
7
|
-
import { OrderDBResponse } from '../../lib/order-response';
|
|
8
|
-
/**
|
|
9
|
-
* Queue an AddToCart event
|
|
10
|
-
*/
|
|
11
|
-
export declare function enqueueAddToCartEvent(env: Env, data: {
|
|
12
|
-
cartId: string;
|
|
13
|
-
itemId: string;
|
|
14
|
-
pixelId: string | null;
|
|
15
|
-
brandSiteUrl: string;
|
|
16
|
-
productName: string;
|
|
17
|
-
productSlug: string;
|
|
18
|
-
sku: string;
|
|
19
|
-
price: number;
|
|
20
|
-
quantity: number;
|
|
21
|
-
customerEmail?: string | null;
|
|
22
|
-
customerPhone?: string | null;
|
|
23
|
-
clientIpAddress?: string;
|
|
24
|
-
clientUserAgent?: string;
|
|
25
|
-
fbc?: string;
|
|
26
|
-
fbp?: string;
|
|
27
|
-
}): Promise<void>;
|
|
28
|
-
/**
|
|
29
|
-
* Queue an InitiateCheckout event
|
|
30
|
-
*/
|
|
31
|
-
export declare function enqueueInitiateCheckoutEvent(env: Env, data: {
|
|
32
|
-
cartId: string;
|
|
33
|
-
pixelId: string | null;
|
|
34
|
-
brandSiteUrl: string;
|
|
35
|
-
cartTotal: number;
|
|
36
|
-
itemCount: number;
|
|
37
|
-
customerEmail?: string | null;
|
|
38
|
-
customerPhone?: string | null;
|
|
39
|
-
clientIpAddress?: string;
|
|
40
|
-
clientUserAgent?: string;
|
|
41
|
-
fbc?: string;
|
|
42
|
-
fbp?: string;
|
|
43
|
-
}): Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Queue a Purchase event from an order
|
|
46
|
-
*
|
|
47
|
-
* For orders with multiple products, uses the brand's homepage
|
|
48
|
-
* since there's no single product page to reference.
|
|
49
|
-
*/
|
|
50
|
-
export declare function enqueuePurchaseEvent(env: Env, order: OrderDBResponse, options?: {
|
|
51
|
-
clientIpAddress?: string;
|
|
52
|
-
clientUserAgent?: string;
|
|
53
|
-
fbc?: string;
|
|
54
|
-
fbp?: string;
|
|
55
|
-
}): Promise<void>;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Meta Conversions API Event Producer
|
|
3
|
-
*
|
|
4
|
-
* Queues Meta CAPI events for processing by the queue consumer.
|
|
5
|
-
*/
|
|
6
|
-
import { generateEventId } from '../../lib/meta-capi';
|
|
7
|
-
/**
|
|
8
|
-
* Queue an AddToCart event
|
|
9
|
-
*/
|
|
10
|
-
export async function enqueueAddToCartEvent(env, data) {
|
|
11
|
-
if (!env.META_CAPI_QUEUE) {
|
|
12
|
-
console.warn('[Meta CAPI] Queue not configured, skipping AddToCart event');
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
if (!data.pixelId) {
|
|
16
|
-
console.log('[Meta CAPI] No pixel ID, skipping AddToCart event');
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const message = {
|
|
20
|
-
pixelId: data.pixelId,
|
|
21
|
-
eventName: 'AddToCart',
|
|
22
|
-
eventId: generateEventId('cart', data.cartId, `item_${data.itemId}`),
|
|
23
|
-
eventTime: Math.floor(Date.now() / 1000),
|
|
24
|
-
eventSourceUrl: `${data.brandSiteUrl}/product/${data.productSlug}`,
|
|
25
|
-
userData: {
|
|
26
|
-
email: data.customerEmail || undefined,
|
|
27
|
-
phone: data.customerPhone || undefined,
|
|
28
|
-
clientIpAddress: data.clientIpAddress,
|
|
29
|
-
clientUserAgent: data.clientUserAgent,
|
|
30
|
-
fbc: data.fbc,
|
|
31
|
-
fbp: data.fbp,
|
|
32
|
-
},
|
|
33
|
-
customData: {
|
|
34
|
-
value: data.price, // Unit price, not total
|
|
35
|
-
currency: 'NGN',
|
|
36
|
-
contentIds: [data.sku],
|
|
37
|
-
contentName: data.productName,
|
|
38
|
-
contentType: 'product',
|
|
39
|
-
numItems: data.quantity,
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
await env.META_CAPI_QUEUE.send(message);
|
|
43
|
-
console.log(`[Meta CAPI] Queued AddToCart event: ${message.eventId}`);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Queue an InitiateCheckout event
|
|
47
|
-
*/
|
|
48
|
-
export async function enqueueInitiateCheckoutEvent(env, data) {
|
|
49
|
-
if (!env.META_CAPI_QUEUE) {
|
|
50
|
-
console.warn('[Meta CAPI] Queue not configured, skipping InitiateCheckout event');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
if (!data.pixelId) {
|
|
54
|
-
console.log('[Meta CAPI] No pixel ID, skipping InitiateCheckout event');
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const message = {
|
|
58
|
-
pixelId: data.pixelId,
|
|
59
|
-
eventName: 'InitiateCheckout',
|
|
60
|
-
eventId: generateEventId('cart', data.cartId, 'checkout'),
|
|
61
|
-
eventTime: Math.floor(Date.now() / 1000),
|
|
62
|
-
eventSourceUrl: `${data.brandSiteUrl}/checkout`,
|
|
63
|
-
userData: {
|
|
64
|
-
email: data.customerEmail || undefined,
|
|
65
|
-
phone: data.customerPhone || undefined,
|
|
66
|
-
clientIpAddress: data.clientIpAddress,
|
|
67
|
-
clientUserAgent: data.clientUserAgent,
|
|
68
|
-
fbc: data.fbc,
|
|
69
|
-
fbp: data.fbp,
|
|
70
|
-
},
|
|
71
|
-
customData: {
|
|
72
|
-
value: data.cartTotal,
|
|
73
|
-
currency: 'NGN',
|
|
74
|
-
numItems: data.itemCount,
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
await env.META_CAPI_QUEUE.send(message);
|
|
78
|
-
console.log(`[Meta CAPI] Queued InitiateCheckout event: ${message.eventId}`);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Queue a Purchase event from an order
|
|
82
|
-
*
|
|
83
|
-
* For orders with multiple products, uses the brand's homepage
|
|
84
|
-
* since there's no single product page to reference.
|
|
85
|
-
*/
|
|
86
|
-
export async function enqueuePurchaseEvent(env, order, options) {
|
|
87
|
-
if (!env.META_CAPI_QUEUE) {
|
|
88
|
-
console.warn('[Meta CAPI] Queue not configured, skipping Purchase event');
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
const pixelId = order.brand.metaPixelId;
|
|
92
|
-
if (!pixelId) {
|
|
93
|
-
console.log('[Meta CAPI] No pixel ID for brand, skipping Purchase event');
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
const message = {
|
|
97
|
-
pixelId,
|
|
98
|
-
eventName: 'Purchase',
|
|
99
|
-
eventId: generateEventId('order', order.id),
|
|
100
|
-
eventTime: Math.floor(Date.now() / 1000),
|
|
101
|
-
// Use brand homepage for multi-product orders
|
|
102
|
-
eventSourceUrl: order.brand.siteUrl,
|
|
103
|
-
userData: {
|
|
104
|
-
email: order.email || undefined,
|
|
105
|
-
phone: order.phone,
|
|
106
|
-
firstName: order.firstName,
|
|
107
|
-
lastName: order.lastName,
|
|
108
|
-
city: order.city,
|
|
109
|
-
country: 'ng', // Nigeria
|
|
110
|
-
clientIpAddress: options?.clientIpAddress,
|
|
111
|
-
clientUserAgent: options?.clientUserAgent,
|
|
112
|
-
fbc: options?.fbc,
|
|
113
|
-
fbp: options?.fbp,
|
|
114
|
-
},
|
|
115
|
-
customData: {
|
|
116
|
-
value: Number(order.totalPrice),
|
|
117
|
-
currency: 'NGN',
|
|
118
|
-
contentIds: order.items.map((item) => item.variant.sku),
|
|
119
|
-
contentType: 'product',
|
|
120
|
-
numItems: order.items.reduce((sum, item) => sum + item.quantity, 0),
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
await env.META_CAPI_QUEUE.send(message);
|
|
124
|
-
console.log(`[Meta CAPI] Queued Purchase event: ${message.eventId}`);
|
|
125
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Env } from '../../types';
|
|
2
|
-
export type OrderNotificationType = 'order_confirmation' | 'order_shipped' | 'order_delivered' | 'order_cancelled';
|
|
3
|
-
export type MessageType = {
|
|
4
|
-
messageType: 'order_notification';
|
|
5
|
-
type: OrderNotificationType;
|
|
6
|
-
orderId: string;
|
|
7
|
-
timestamp: string;
|
|
8
|
-
};
|
|
9
|
-
export declare function enqueueOrderNotification(env: Env, type: OrderNotificationType, orderId: string): Promise<void>;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export async function enqueueOrderNotification(env, type, orderId) {
|
|
2
|
-
if (env.WHATSAPP_QUEUE) {
|
|
3
|
-
await env.WHATSAPP_QUEUE.send({
|
|
4
|
-
messageType: 'order_notification',
|
|
5
|
-
type,
|
|
6
|
-
orderId,
|
|
7
|
-
timestamp: new Date().toISOString(),
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
if (env.EMAIL_QUEUE) {
|
|
11
|
-
await env.EMAIL_QUEUE.send({
|
|
12
|
-
messageType: 'order_notification',
|
|
13
|
-
type,
|
|
14
|
-
orderId,
|
|
15
|
-
timestamp: new Date().toISOString(),
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Env } from '../../types';
|
|
2
|
-
export type ProspectRecoveryNotificationType = 'prospect_recovery_reminder' | 'prospect_recovery' | 'prospect_recovery_final';
|
|
3
|
-
export type MessageType = {
|
|
4
|
-
messageType: 'prospect_recovery';
|
|
5
|
-
type: ProspectRecoveryNotificationType;
|
|
6
|
-
orderId: string;
|
|
7
|
-
attemptNumber: number;
|
|
8
|
-
timestamp: string;
|
|
9
|
-
};
|
|
10
|
-
export declare function enqueueProspectRecoveryNotification(env: Env, type: ProspectRecoveryNotificationType, orderId: string, attemptNumber: number): Promise<void>;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export async function enqueueProspectRecoveryNotification(env, type, orderId, attemptNumber) {
|
|
2
|
-
if (env.EMAIL_QUEUE) {
|
|
3
|
-
await env.EMAIL_QUEUE.send({
|
|
4
|
-
messageType: 'prospect_recovery',
|
|
5
|
-
type,
|
|
6
|
-
orderId,
|
|
7
|
-
attemptNumber,
|
|
8
|
-
timestamp: new Date().toISOString(),
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
}
|