@instockng/api-client 1.0.7 → 1.0.8
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/apps/backend/src/http-app.js +28 -0
- package/dist/apps/backend/src/lib/brand-response.d.ts +1 -1
- package/dist/apps/backend/src/lib/cart-helpers.d.ts +13 -11
- package/dist/apps/backend/src/lib/cart-helpers.js +28 -0
- package/dist/apps/backend/src/lib/cart-response.d.ts +5 -5
- package/dist/apps/backend/src/lib/clerk.js +23 -0
- package/dist/apps/backend/src/lib/delivery-zone-response.d.ts +6 -4
- package/dist/apps/backend/src/lib/discount-code-response.d.ts +2 -2
- package/dist/apps/backend/src/lib/meta-capi.d.ts +5 -0
- package/dist/apps/backend/src/lib/meta-capi.js +33 -2
- package/dist/apps/backend/src/lib/order-recovery.d.ts +30 -24
- package/dist/apps/backend/src/lib/order-response.d.ts +9 -7
- package/dist/apps/backend/src/lib/product-response.d.ts +4 -4
- package/dist/apps/backend/src/lib/sentry.d.ts +48 -0
- package/dist/apps/backend/src/lib/sentry.js +180 -0
- package/dist/apps/backend/src/notifications/producers/meta-capi-producer.js +18 -4
- package/dist/apps/backend/src/routes/admin/abandoned-carts.d.ts +10 -10
- package/dist/apps/backend/src/routes/admin/brands.d.ts +4 -4
- package/dist/apps/backend/src/routes/admin/customers.d.ts +9 -7
- package/dist/apps/backend/src/routes/admin/delivery-zones.d.ts +23 -15
- package/dist/apps/backend/src/routes/admin/discount-codes.d.ts +10 -10
- package/dist/apps/backend/src/routes/admin/inventory.js +10 -0
- package/dist/apps/backend/src/routes/admin/orders.d.ts +54 -42
- package/dist/apps/backend/src/routes/admin/orders.js +25 -0
- package/dist/apps/backend/src/routes/admin/products.d.ts +12 -12
- package/dist/apps/backend/src/routes/admin/products.js +34 -15
- package/dist/apps/backend/src/routes/admin/stats.d.ts +9 -7
- package/dist/apps/backend/src/routes/admin/variants.d.ts +5 -5
- package/dist/apps/backend/src/routes/admin/variants.js +42 -18
- package/dist/apps/backend/src/routes/admin/warehouses.d.ts +7 -7
- package/dist/apps/backend/src/routes/public/brands.d.ts +1 -1
- package/dist/apps/backend/src/routes/public/carts.d.ts +49 -47
- package/dist/apps/backend/src/routes/public/carts.js +148 -1
- package/dist/apps/backend/src/routes/public/delivery-zones.d.ts +2 -0
- package/dist/apps/backend/src/routes/public/delivery-zones.js +2 -0
- package/dist/apps/backend/src/routes/public/orders.d.ts +18 -14
- package/dist/apps/backend/src/routes/public/orders.js +24 -0
- package/dist/apps/backend/src/routes/public/products.d.ts +6 -6
- package/dist/apps/backend/src/types/index.d.ts +1 -0
- package/dist/apps/backend/src/validators/delivery-zone.d.ts +4 -0
- package/dist/apps/backend/src/validators/delivery-zone.js +4 -0
- package/dist/apps/backend/src/validators/discount-code.d.ts +3 -3
- package/dist/apps/backend/src/validators/order.d.ts +3 -1
- package/dist/apps/backend/src/validators/order.js +3 -1
- package/dist/packages/api-client/src/fetchers/brands.d.ts +1 -1
- package/dist/packages/api-client/src/fetchers/carts.d.ts +49 -47
- package/dist/packages/api-client/src/fetchers/delivery-zones.d.ts +2 -0
- package/dist/packages/api-client/src/fetchers/orders.d.ts +18 -14
- package/dist/packages/api-client/src/fetchers/products.d.ts +6 -6
- package/dist/packages/api-client/src/hooks/admin/abandoned-carts.d.ts +10 -10
- package/dist/packages/api-client/src/hooks/admin/brands.d.ts +4 -4
- package/dist/packages/api-client/src/hooks/admin/customers.d.ts +9 -7
- package/dist/packages/api-client/src/hooks/admin/delivery-zones.d.ts +23 -15
- package/dist/packages/api-client/src/hooks/admin/discount-codes.d.ts +10 -10
- package/dist/packages/api-client/src/hooks/admin/orders.d.ts +54 -42
- package/dist/packages/api-client/src/hooks/admin/products.d.ts +6 -6
- package/dist/packages/api-client/src/hooks/admin/stats.d.ts +9 -7
- package/dist/packages/api-client/src/hooks/admin/variants.d.ts +5 -5
- package/dist/packages/api-client/src/hooks/admin/warehouses.d.ts +7 -7
- package/dist/packages/api-client/src/hooks/public/brands.d.ts +1 -1
- package/dist/packages/api-client/src/hooks/public/carts.d.ts +49 -47
- package/dist/packages/api-client/src/hooks/public/delivery-zones.d.ts +2 -0
- package/dist/packages/api-client/src/hooks/public/orders.d.ts +18 -14
- package/dist/packages/api-client/src/hooks/public/products.d.ts +6 -6
- package/dist/packages/api-client/src/rpc-client.d.ts +219 -187
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ import { clerkAuthMiddleware } from './middleware/clerk-auth';
|
|
|
8
8
|
import { createOpenAPIApp, openapiConfig } from './lib/openapi';
|
|
9
9
|
import { swaggerUI } from '@hono/swagger-ui';
|
|
10
10
|
import { HTTPException } from 'hono/http-exception';
|
|
11
|
+
import { captureException, captureMessage } from './lib/sentry';
|
|
11
12
|
// Public routes
|
|
12
13
|
import publicOrders from './routes/public/orders';
|
|
13
14
|
import publicProducts from './routes/public/products';
|
|
@@ -87,6 +88,19 @@ export function createHttpApp() {
|
|
|
87
88
|
// Error handler
|
|
88
89
|
app.onError((err, c) => {
|
|
89
90
|
if (err instanceof HTTPException && err.status === 400) {
|
|
91
|
+
// Track validation errors with sampling
|
|
92
|
+
captureMessage('Malformed JSON in request body', {
|
|
93
|
+
level: 'warning',
|
|
94
|
+
tags: {
|
|
95
|
+
error_code: 'BAD_REQUEST',
|
|
96
|
+
route: c.req.path,
|
|
97
|
+
method: c.req.method,
|
|
98
|
+
},
|
|
99
|
+
extra: {
|
|
100
|
+
url: c.req.url,
|
|
101
|
+
},
|
|
102
|
+
sampleRate: 0.1, // 10% sampling
|
|
103
|
+
});
|
|
90
104
|
return c.json({
|
|
91
105
|
error: {
|
|
92
106
|
code: 'BAD_REQUEST',
|
|
@@ -94,7 +108,21 @@ export function createHttpApp() {
|
|
|
94
108
|
},
|
|
95
109
|
}, 400);
|
|
96
110
|
}
|
|
111
|
+
// Capture unhandled errors - these are critical
|
|
97
112
|
console.error('Unhandled error:', err);
|
|
113
|
+
captureException(err, {
|
|
114
|
+
level: 'error',
|
|
115
|
+
tags: {
|
|
116
|
+
error_code: 'INTERNAL_ERROR',
|
|
117
|
+
route: c.req.path,
|
|
118
|
+
method: c.req.method,
|
|
119
|
+
},
|
|
120
|
+
extra: {
|
|
121
|
+
url: c.req.url,
|
|
122
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
123
|
+
},
|
|
124
|
+
honoContext: c,
|
|
125
|
+
});
|
|
98
126
|
return c.json({
|
|
99
127
|
error: {
|
|
100
128
|
code: 'INTERNAL_ERROR',
|
|
@@ -50,8 +50,8 @@ export declare const ORDER_INCLUDE_FULL: {
|
|
|
50
50
|
type CartWithRelations = Awaited<ReturnType<typeof getCartWithRelations>>;
|
|
51
51
|
declare function getCartWithRelations(prisma: PrismaClient, cartId: string): Promise<{
|
|
52
52
|
brand: {
|
|
53
|
-
name: string;
|
|
54
53
|
id: string;
|
|
54
|
+
name: string;
|
|
55
55
|
slug: string;
|
|
56
56
|
logoUrl: string | null;
|
|
57
57
|
siteUrl: string;
|
|
@@ -62,8 +62,8 @@ declare function getCartWithRelations(prisma: PrismaClient, cartId: string): Pro
|
|
|
62
62
|
deletedAt: Date | null;
|
|
63
63
|
};
|
|
64
64
|
deliveryZone: {
|
|
65
|
-
name: string;
|
|
66
65
|
id: string;
|
|
66
|
+
name: string;
|
|
67
67
|
createdAt: Date;
|
|
68
68
|
updatedAt: Date;
|
|
69
69
|
deletedAt: Date | null;
|
|
@@ -75,18 +75,20 @@ declare function getCartWithRelations(prisma: PrismaClient, cartId: string): Pro
|
|
|
75
75
|
allowOnline: boolean;
|
|
76
76
|
waybillOnly: boolean;
|
|
77
77
|
estimatedDays: number | null;
|
|
78
|
+
noteTitle: string | null;
|
|
79
|
+
noteContent: string | null;
|
|
78
80
|
isActive: boolean;
|
|
79
81
|
};
|
|
80
82
|
recoveryDiscountCode: {
|
|
81
83
|
id: string;
|
|
84
|
+
type: string;
|
|
85
|
+
value: import("@prisma/client/runtime/library").Decimal;
|
|
82
86
|
createdAt: Date;
|
|
83
87
|
updatedAt: Date;
|
|
84
88
|
deletedAt: Date | null;
|
|
85
89
|
brandId: string | null;
|
|
86
90
|
isActive: boolean;
|
|
87
91
|
code: string;
|
|
88
|
-
type: string;
|
|
89
|
-
value: import("@prisma/client/runtime/library").Decimal;
|
|
90
92
|
minPurchase: import("@prisma/client/runtime/library").Decimal | null;
|
|
91
93
|
maxDiscount: import("@prisma/client/runtime/library").Decimal | null;
|
|
92
94
|
usageLimit: number | null;
|
|
@@ -102,8 +104,8 @@ declare function getCartWithRelations(prisma: PrismaClient, cartId: string): Pro
|
|
|
102
104
|
items: ({
|
|
103
105
|
variant: {
|
|
104
106
|
product: {
|
|
105
|
-
name: string;
|
|
106
107
|
id: string;
|
|
108
|
+
name: string;
|
|
107
109
|
slug: string;
|
|
108
110
|
createdAt: Date;
|
|
109
111
|
updatedAt: Date;
|
|
@@ -115,8 +117,8 @@ declare function getCartWithRelations(prisma: PrismaClient, cartId: string): Pro
|
|
|
115
117
|
quantityDiscounts: import("@prisma/client/runtime/library").JsonValue | null;
|
|
116
118
|
};
|
|
117
119
|
} & {
|
|
118
|
-
name: string | null;
|
|
119
120
|
id: string;
|
|
121
|
+
name: string | null;
|
|
120
122
|
createdAt: Date;
|
|
121
123
|
updatedAt: Date;
|
|
122
124
|
deletedAt: Date | null;
|
|
@@ -176,8 +178,8 @@ export declare function buildCartResponse(prisma: PrismaClient, cart: NonNullabl
|
|
|
176
178
|
createdAt: string;
|
|
177
179
|
updatedAt: string;
|
|
178
180
|
deletedAt: string;
|
|
179
|
-
name: string;
|
|
180
181
|
id: string;
|
|
182
|
+
name: string;
|
|
181
183
|
slug: string;
|
|
182
184
|
logoUrl: string | null;
|
|
183
185
|
siteUrl: string;
|
|
@@ -197,14 +199,14 @@ export declare function buildCartResponse(prisma: PrismaClient, cart: NonNullabl
|
|
|
197
199
|
lastRecoveryAttemptAt: Date;
|
|
198
200
|
recoveryDiscountCode: {
|
|
199
201
|
id: string;
|
|
202
|
+
type: string;
|
|
203
|
+
value: import("@prisma/client/runtime/library").Decimal;
|
|
200
204
|
createdAt: Date;
|
|
201
205
|
updatedAt: Date;
|
|
202
206
|
deletedAt: Date | null;
|
|
203
207
|
brandId: string | null;
|
|
204
208
|
isActive: boolean;
|
|
205
209
|
code: string;
|
|
206
|
-
type: string;
|
|
207
|
-
value: import("@prisma/client/runtime/library").Decimal;
|
|
208
210
|
minPurchase: import("@prisma/client/runtime/library").Decimal | null;
|
|
209
211
|
maxDiscount: import("@prisma/client/runtime/library").Decimal | null;
|
|
210
212
|
usageLimit: number | null;
|
|
@@ -222,8 +224,8 @@ export declare function buildCartResponse(prisma: PrismaClient, cart: NonNullabl
|
|
|
222
224
|
variant: {
|
|
223
225
|
price: number;
|
|
224
226
|
product: {
|
|
225
|
-
name: string;
|
|
226
227
|
id: string;
|
|
228
|
+
name: string;
|
|
227
229
|
slug: string;
|
|
228
230
|
createdAt: Date;
|
|
229
231
|
updatedAt: Date;
|
|
@@ -234,8 +236,8 @@ export declare function buildCartResponse(prisma: PrismaClient, cart: NonNullabl
|
|
|
234
236
|
thumbnailUrl: string | null;
|
|
235
237
|
quantityDiscounts: import("@prisma/client/runtime/library").JsonValue | null;
|
|
236
238
|
};
|
|
237
|
-
name: string | null;
|
|
238
239
|
id: string;
|
|
240
|
+
name: string | null;
|
|
239
241
|
createdAt: Date;
|
|
240
242
|
updatedAt: Date;
|
|
241
243
|
deletedAt: Date | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { buildCartResponseWithPricing } from './cart-response';
|
|
2
|
+
import { captureMessage, getSampleRate } from './sentry';
|
|
2
3
|
/**
|
|
3
4
|
* Standard include pattern for cart queries with all necessary relations
|
|
4
5
|
*/
|
|
@@ -55,12 +56,39 @@ async function getCartWithRelations(prisma, cartId) {
|
|
|
55
56
|
export async function validateCart(prisma, cartId) {
|
|
56
57
|
const cart = await getCartWithRelations(prisma, cartId);
|
|
57
58
|
if (!cart) {
|
|
59
|
+
// Track cart not found errors with sampling
|
|
60
|
+
captureMessage('Cart not found', {
|
|
61
|
+
level: 'info',
|
|
62
|
+
tags: {
|
|
63
|
+
error_code: 'CART_NOT_FOUND',
|
|
64
|
+
},
|
|
65
|
+
extra: {
|
|
66
|
+
cartId,
|
|
67
|
+
},
|
|
68
|
+
sampleRate: getSampleRate('CART_NOT_FOUND'), // 5% sampling
|
|
69
|
+
});
|
|
58
70
|
return {
|
|
59
71
|
cart: null,
|
|
60
72
|
error: { code: 'CART_NOT_FOUND', message: 'Cart not found', status: 404 }
|
|
61
73
|
};
|
|
62
74
|
}
|
|
63
75
|
if (cart.expiresAt < new Date()) {
|
|
76
|
+
// Track cart expiration with sampling
|
|
77
|
+
const daysSinceExpiry = Math.floor((new Date().getTime() - cart.expiresAt.getTime()) / (1000 * 60 * 60 * 24));
|
|
78
|
+
captureMessage('Cart expired', {
|
|
79
|
+
level: 'info',
|
|
80
|
+
tags: {
|
|
81
|
+
error_code: 'CART_EXPIRED',
|
|
82
|
+
brand: cart.brand?.slug || 'unknown',
|
|
83
|
+
},
|
|
84
|
+
extra: {
|
|
85
|
+
cartId,
|
|
86
|
+
expiresAt: cart.expiresAt.toISOString(),
|
|
87
|
+
daysSinceExpiry,
|
|
88
|
+
lastUpdated: cart.updatedAt.toISOString(),
|
|
89
|
+
},
|
|
90
|
+
sampleRate: getSampleRate('CART_EXPIRED'), // 10% sampling
|
|
91
|
+
});
|
|
64
92
|
return {
|
|
65
93
|
cart: null,
|
|
66
94
|
error: { code: 'CART_EXPIRED', message: 'Cart has expired', status: 410 }
|
|
@@ -30,8 +30,8 @@ export declare function buildCartResponseWithPricing(prisma: PrismaClient, cart:
|
|
|
30
30
|
createdAt: string;
|
|
31
31
|
updatedAt: string;
|
|
32
32
|
deletedAt: string;
|
|
33
|
-
name: string;
|
|
34
33
|
id: string;
|
|
34
|
+
name: string;
|
|
35
35
|
slug: string;
|
|
36
36
|
logoUrl: string | null;
|
|
37
37
|
siteUrl: string;
|
|
@@ -51,14 +51,14 @@ export declare function buildCartResponseWithPricing(prisma: PrismaClient, cart:
|
|
|
51
51
|
lastRecoveryAttemptAt: Date;
|
|
52
52
|
recoveryDiscountCode: {
|
|
53
53
|
id: string;
|
|
54
|
+
type: string;
|
|
55
|
+
value: Prisma.Decimal;
|
|
54
56
|
createdAt: Date;
|
|
55
57
|
updatedAt: Date;
|
|
56
58
|
deletedAt: Date | null;
|
|
57
59
|
brandId: string | null;
|
|
58
60
|
isActive: boolean;
|
|
59
61
|
code: string;
|
|
60
|
-
type: string;
|
|
61
|
-
value: Prisma.Decimal;
|
|
62
62
|
minPurchase: Prisma.Decimal | null;
|
|
63
63
|
maxDiscount: Prisma.Decimal | null;
|
|
64
64
|
usageLimit: number | null;
|
|
@@ -76,8 +76,8 @@ export declare function buildCartResponseWithPricing(prisma: PrismaClient, cart:
|
|
|
76
76
|
variant: {
|
|
77
77
|
price: number;
|
|
78
78
|
product: {
|
|
79
|
-
name: string;
|
|
80
79
|
id: string;
|
|
80
|
+
name: string;
|
|
81
81
|
slug: string;
|
|
82
82
|
createdAt: Date;
|
|
83
83
|
updatedAt: Date;
|
|
@@ -88,8 +88,8 @@ export declare function buildCartResponseWithPricing(prisma: PrismaClient, cart:
|
|
|
88
88
|
thumbnailUrl: string | null;
|
|
89
89
|
quantityDiscounts: Prisma.JsonValue | null;
|
|
90
90
|
};
|
|
91
|
-
name: string | null;
|
|
92
91
|
id: string;
|
|
92
|
+
name: string | null;
|
|
93
93
|
createdAt: Date;
|
|
94
94
|
updatedAt: Date;
|
|
95
95
|
deletedAt: Date | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { captureException } from './sentry';
|
|
1
2
|
// In-memory cache for JWKS (in production, consider using Workers KV or Durable Objects)
|
|
2
3
|
let jwksCache = null;
|
|
3
4
|
const JWKS_CACHE_TTL = 3600000; // 1 hour in milliseconds
|
|
@@ -49,6 +50,18 @@ async function fetchJWKS(publishableKey) {
|
|
|
49
50
|
if (!response.ok) {
|
|
50
51
|
const errorText = await response.text();
|
|
51
52
|
console.error('Failed to fetch JWKS:', response.status, errorText);
|
|
53
|
+
// Capture JWKS fetch errors
|
|
54
|
+
captureException(new Error(`Failed to fetch JWKS: ${response.status} ${errorText}`), {
|
|
55
|
+
level: 'error',
|
|
56
|
+
tags: {
|
|
57
|
+
error_type: 'clerk_jwks_fetch_error',
|
|
58
|
+
http_status: response.status.toString(),
|
|
59
|
+
},
|
|
60
|
+
extra: {
|
|
61
|
+
jwksUrl: jwksUrl,
|
|
62
|
+
publishableKey: publishableKey.substring(0, 20) + '...', // Truncate for security
|
|
63
|
+
},
|
|
64
|
+
});
|
|
52
65
|
return [];
|
|
53
66
|
}
|
|
54
67
|
const jwks = await response.json();
|
|
@@ -66,6 +79,16 @@ async function fetchJWKS(publishableKey) {
|
|
|
66
79
|
}
|
|
67
80
|
catch (error) {
|
|
68
81
|
console.error('Error fetching JWKS:', error);
|
|
82
|
+
// Capture JWKS exception errors
|
|
83
|
+
captureException(error instanceof Error ? error : new Error(String(error)), {
|
|
84
|
+
level: 'error',
|
|
85
|
+
tags: {
|
|
86
|
+
error_type: 'clerk_jwks_exception',
|
|
87
|
+
},
|
|
88
|
+
extra: {
|
|
89
|
+
publishableKey: publishableKey.substring(0, 20) + '...', // Truncate for security
|
|
90
|
+
},
|
|
91
|
+
});
|
|
69
92
|
return [];
|
|
70
93
|
}
|
|
71
94
|
}
|
|
@@ -17,8 +17,8 @@ export declare function formatStateResponse(state: StateDBResponse & {
|
|
|
17
17
|
createdAt: string;
|
|
18
18
|
updatedAt: string;
|
|
19
19
|
deletedAt: string;
|
|
20
|
-
name: string;
|
|
21
20
|
id: string;
|
|
21
|
+
name: string;
|
|
22
22
|
isActive: boolean;
|
|
23
23
|
deliveryZones?: any[];
|
|
24
24
|
};
|
|
@@ -32,8 +32,8 @@ export declare function formatDeliveryZoneResponse(deliveryZone: DeliveryZoneDBR
|
|
|
32
32
|
createdAt: string;
|
|
33
33
|
updatedAt: string;
|
|
34
34
|
deletedAt: string;
|
|
35
|
-
name: string;
|
|
36
35
|
id: string;
|
|
36
|
+
name: string;
|
|
37
37
|
slug: string;
|
|
38
38
|
logoUrl: string | null;
|
|
39
39
|
siteUrl: string;
|
|
@@ -43,20 +43,22 @@ export declare function formatDeliveryZoneResponse(deliveryZone: DeliveryZoneDBR
|
|
|
43
43
|
stateName: string;
|
|
44
44
|
brandName: string;
|
|
45
45
|
state: {
|
|
46
|
-
name: string;
|
|
47
46
|
id: string;
|
|
47
|
+
name: string;
|
|
48
48
|
createdAt: Date;
|
|
49
49
|
updatedAt: Date;
|
|
50
50
|
deletedAt: Date | null;
|
|
51
51
|
isActive: boolean;
|
|
52
52
|
};
|
|
53
|
-
name: string;
|
|
54
53
|
id: string;
|
|
54
|
+
name: string;
|
|
55
55
|
brandId: string | null;
|
|
56
56
|
stateId: string;
|
|
57
57
|
allowCOD: boolean;
|
|
58
58
|
allowOnline: boolean;
|
|
59
59
|
waybillOnly: boolean;
|
|
60
60
|
estimatedDays: number | null;
|
|
61
|
+
noteTitle: string | null;
|
|
62
|
+
noteContent: string | null;
|
|
61
63
|
isActive: boolean;
|
|
62
64
|
};
|
|
@@ -15,8 +15,8 @@ export declare function formatDiscountCodeResponse(discountCode: DiscountCodeDBR
|
|
|
15
15
|
createdAt: string;
|
|
16
16
|
updatedAt: string;
|
|
17
17
|
deletedAt: string;
|
|
18
|
-
name: string;
|
|
19
18
|
id: string;
|
|
19
|
+
name: string;
|
|
20
20
|
slug: string;
|
|
21
21
|
logoUrl: string | null;
|
|
22
22
|
siteUrl: string;
|
|
@@ -26,10 +26,10 @@ export declare function formatDiscountCodeResponse(discountCode: DiscountCodeDBR
|
|
|
26
26
|
isExpired: boolean;
|
|
27
27
|
usagePercentage: number;
|
|
28
28
|
id: string;
|
|
29
|
+
type: string;
|
|
29
30
|
brandId: string | null;
|
|
30
31
|
isActive: boolean;
|
|
31
32
|
code: string;
|
|
32
|
-
type: string;
|
|
33
33
|
usageLimit: number | null;
|
|
34
34
|
usageCount: number;
|
|
35
35
|
perCustomerLimit: number | null;
|
|
@@ -29,6 +29,11 @@ export interface MetaCapiQueueMessage {
|
|
|
29
29
|
value?: number;
|
|
30
30
|
currency?: string;
|
|
31
31
|
contentIds?: string[];
|
|
32
|
+
contents?: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
quantity: number;
|
|
35
|
+
item_price: number;
|
|
36
|
+
}>;
|
|
32
37
|
contentType?: string;
|
|
33
38
|
numItems?: number;
|
|
34
39
|
contentName?: string;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Used alongside browser pixel for maximum reliability and iOS 14+ compliance.
|
|
6
6
|
*/
|
|
7
7
|
import crypto from 'crypto';
|
|
8
|
+
import { captureException } from './sentry';
|
|
8
9
|
/**
|
|
9
10
|
* Hash data with SHA256 for Meta CAPI
|
|
10
11
|
* Meta requires PII to be hashed before sending
|
|
@@ -99,13 +100,43 @@ export async function sendMetaCapiEvent(accessToken, message) {
|
|
|
99
100
|
});
|
|
100
101
|
if (!response.ok) {
|
|
101
102
|
const error = await response.text();
|
|
102
|
-
|
|
103
|
+
const metaError = new Error(`Meta CAPI error: ${response.status} ${error}`);
|
|
104
|
+
// Capture Meta CAPI HTTP errors
|
|
105
|
+
captureException(metaError, {
|
|
106
|
+
level: 'warning', // Non-blocking for users
|
|
107
|
+
tags: {
|
|
108
|
+
error_type: 'meta_capi_http_error',
|
|
109
|
+
event_name: message.eventName,
|
|
110
|
+
pixel_id: message.pixelId,
|
|
111
|
+
http_status: response.status.toString(),
|
|
112
|
+
},
|
|
113
|
+
extra: {
|
|
114
|
+
eventId: message.eventId,
|
|
115
|
+
responseBody: error,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
throw metaError;
|
|
103
119
|
}
|
|
104
120
|
const result = await response.json();
|
|
105
121
|
// Log if Meta returned any errors
|
|
106
122
|
if (result.events_received !== 1) {
|
|
107
123
|
console.error('[Meta CAPI] Event not received:', result);
|
|
108
|
-
|
|
124
|
+
const receiveError = new Error('Meta CAPI did not receive event');
|
|
125
|
+
// Capture event not received errors
|
|
126
|
+
captureException(receiveError, {
|
|
127
|
+
level: 'warning',
|
|
128
|
+
tags: {
|
|
129
|
+
error_type: 'meta_capi_event_not_received',
|
|
130
|
+
event_name: message.eventName,
|
|
131
|
+
pixel_id: message.pixelId,
|
|
132
|
+
},
|
|
133
|
+
extra: {
|
|
134
|
+
eventId: message.eventId,
|
|
135
|
+
eventsReceived: result.events_received,
|
|
136
|
+
response: result,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
throw receiveError;
|
|
109
140
|
}
|
|
110
141
|
}
|
|
111
142
|
/**
|
|
@@ -30,8 +30,8 @@ export declare const AUTO_CANCEL_HOURS = 72;
|
|
|
30
30
|
*/
|
|
31
31
|
export declare function findProspectOrdersForRecovery(prisma: PrismaClient, attemptNumber: number): Promise<({
|
|
32
32
|
brand: {
|
|
33
|
-
name: string;
|
|
34
33
|
id: string;
|
|
34
|
+
name: string;
|
|
35
35
|
slug: string;
|
|
36
36
|
logoUrl: string | null;
|
|
37
37
|
siteUrl: string;
|
|
@@ -42,8 +42,8 @@ export declare function findProspectOrdersForRecovery(prisma: PrismaClient, atte
|
|
|
42
42
|
deletedAt: Date | null;
|
|
43
43
|
};
|
|
44
44
|
deliveryZone: {
|
|
45
|
-
name: string;
|
|
46
45
|
id: string;
|
|
46
|
+
name: string;
|
|
47
47
|
createdAt: Date;
|
|
48
48
|
updatedAt: Date;
|
|
49
49
|
deletedAt: Date | null;
|
|
@@ -55,18 +55,20 @@ export declare function findProspectOrdersForRecovery(prisma: PrismaClient, atte
|
|
|
55
55
|
allowOnline: boolean;
|
|
56
56
|
waybillOnly: boolean;
|
|
57
57
|
estimatedDays: number | null;
|
|
58
|
+
noteTitle: string | null;
|
|
59
|
+
noteContent: string | null;
|
|
58
60
|
isActive: boolean;
|
|
59
61
|
};
|
|
60
62
|
recoveryDiscountCode: {
|
|
61
63
|
id: string;
|
|
64
|
+
type: string;
|
|
65
|
+
value: import("@prisma/client/runtime/library").Decimal;
|
|
62
66
|
createdAt: Date;
|
|
63
67
|
updatedAt: Date;
|
|
64
68
|
deletedAt: Date | null;
|
|
65
69
|
brandId: string | null;
|
|
66
70
|
isActive: boolean;
|
|
67
71
|
code: string;
|
|
68
|
-
type: string;
|
|
69
|
-
value: import("@prisma/client/runtime/library").Decimal;
|
|
70
72
|
minPurchase: import("@prisma/client/runtime/library").Decimal | null;
|
|
71
73
|
maxDiscount: import("@prisma/client/runtime/library").Decimal | null;
|
|
72
74
|
usageLimit: number | null;
|
|
@@ -82,8 +84,8 @@ export declare function findProspectOrdersForRecovery(prisma: PrismaClient, atte
|
|
|
82
84
|
items: ({
|
|
83
85
|
variant: {
|
|
84
86
|
product: {
|
|
85
|
-
name: string;
|
|
86
87
|
id: string;
|
|
88
|
+
name: string;
|
|
87
89
|
slug: string;
|
|
88
90
|
createdAt: Date;
|
|
89
91
|
updatedAt: Date;
|
|
@@ -95,8 +97,8 @@ export declare function findProspectOrdersForRecovery(prisma: PrismaClient, atte
|
|
|
95
97
|
quantityDiscounts: import("@prisma/client/runtime/library").JsonValue | null;
|
|
96
98
|
};
|
|
97
99
|
} & {
|
|
98
|
-
name: string | null;
|
|
99
100
|
id: string;
|
|
101
|
+
name: string | null;
|
|
100
102
|
createdAt: Date;
|
|
101
103
|
updatedAt: Date;
|
|
102
104
|
deletedAt: Date | null;
|
|
@@ -117,8 +119,8 @@ export declare function findProspectOrdersForRecovery(prisma: PrismaClient, atte
|
|
|
117
119
|
priceAtPurchase: import("@prisma/client/runtime/library").Decimal;
|
|
118
120
|
})[];
|
|
119
121
|
} & {
|
|
120
|
-
id: string;
|
|
121
122
|
email: string | null;
|
|
123
|
+
id: string;
|
|
122
124
|
createdAt: Date;
|
|
123
125
|
updatedAt: Date;
|
|
124
126
|
deletedAt: Date | null;
|
|
@@ -152,8 +154,8 @@ export declare function findProspectOrdersForRecovery(prisma: PrismaClient, atte
|
|
|
152
154
|
*/
|
|
153
155
|
export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, orderId: string, attemptNumber: number, brandId: string): Promise<{
|
|
154
156
|
brand: {
|
|
155
|
-
name: string;
|
|
156
157
|
id: string;
|
|
158
|
+
name: string;
|
|
157
159
|
slug: string;
|
|
158
160
|
logoUrl: string | null;
|
|
159
161
|
siteUrl: string;
|
|
@@ -164,8 +166,8 @@ export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, ord
|
|
|
164
166
|
deletedAt: Date | null;
|
|
165
167
|
};
|
|
166
168
|
deliveryZone: {
|
|
167
|
-
name: string;
|
|
168
169
|
id: string;
|
|
170
|
+
name: string;
|
|
169
171
|
createdAt: Date;
|
|
170
172
|
updatedAt: Date;
|
|
171
173
|
deletedAt: Date | null;
|
|
@@ -177,18 +179,20 @@ export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, ord
|
|
|
177
179
|
allowOnline: boolean;
|
|
178
180
|
waybillOnly: boolean;
|
|
179
181
|
estimatedDays: number | null;
|
|
182
|
+
noteTitle: string | null;
|
|
183
|
+
noteContent: string | null;
|
|
180
184
|
isActive: boolean;
|
|
181
185
|
};
|
|
182
186
|
recoveryDiscountCode: {
|
|
183
187
|
id: string;
|
|
188
|
+
type: string;
|
|
189
|
+
value: import("@prisma/client/runtime/library").Decimal;
|
|
184
190
|
createdAt: Date;
|
|
185
191
|
updatedAt: Date;
|
|
186
192
|
deletedAt: Date | null;
|
|
187
193
|
brandId: string | null;
|
|
188
194
|
isActive: boolean;
|
|
189
195
|
code: string;
|
|
190
|
-
type: string;
|
|
191
|
-
value: import("@prisma/client/runtime/library").Decimal;
|
|
192
196
|
minPurchase: import("@prisma/client/runtime/library").Decimal | null;
|
|
193
197
|
maxDiscount: import("@prisma/client/runtime/library").Decimal | null;
|
|
194
198
|
usageLimit: number | null;
|
|
@@ -204,8 +208,8 @@ export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, ord
|
|
|
204
208
|
items: ({
|
|
205
209
|
variant: {
|
|
206
210
|
product: {
|
|
207
|
-
name: string;
|
|
208
211
|
id: string;
|
|
212
|
+
name: string;
|
|
209
213
|
slug: string;
|
|
210
214
|
createdAt: Date;
|
|
211
215
|
updatedAt: Date;
|
|
@@ -217,8 +221,8 @@ export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, ord
|
|
|
217
221
|
quantityDiscounts: import("@prisma/client/runtime/library").JsonValue | null;
|
|
218
222
|
};
|
|
219
223
|
} & {
|
|
220
|
-
name: string | null;
|
|
221
224
|
id: string;
|
|
225
|
+
name: string | null;
|
|
222
226
|
createdAt: Date;
|
|
223
227
|
updatedAt: Date;
|
|
224
228
|
deletedAt: Date | null;
|
|
@@ -240,16 +244,16 @@ export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, ord
|
|
|
240
244
|
})[];
|
|
241
245
|
notes: {
|
|
242
246
|
id: string;
|
|
243
|
-
|
|
247
|
+
metadata: import("@prisma/client/runtime/library").JsonValue | null;
|
|
244
248
|
type: import("@prisma/client").$Enums.NoteType;
|
|
249
|
+
createdAt: Date;
|
|
245
250
|
createdBy: string | null;
|
|
246
251
|
orderId: string;
|
|
247
|
-
metadata: import("@prisma/client/runtime/library").JsonValue | null;
|
|
248
252
|
note: string;
|
|
249
253
|
}[];
|
|
250
254
|
} & {
|
|
251
|
-
id: string;
|
|
252
255
|
email: string | null;
|
|
256
|
+
id: string;
|
|
253
257
|
createdAt: Date;
|
|
254
258
|
updatedAt: Date;
|
|
255
259
|
deletedAt: Date | null;
|
|
@@ -283,8 +287,8 @@ export declare function prepareOrderForRecoveryAttempt(prisma: PrismaClient, ord
|
|
|
283
287
|
*/
|
|
284
288
|
export declare function confirmProspectOrder(prisma: PrismaClient, orderId: string, userActionToken: string): Promise<{
|
|
285
289
|
brand: {
|
|
286
|
-
name: string;
|
|
287
290
|
id: string;
|
|
291
|
+
name: string;
|
|
288
292
|
slug: string;
|
|
289
293
|
logoUrl: string | null;
|
|
290
294
|
siteUrl: string;
|
|
@@ -296,16 +300,16 @@ export declare function confirmProspectOrder(prisma: PrismaClient, orderId: stri
|
|
|
296
300
|
};
|
|
297
301
|
deliveryZone: {
|
|
298
302
|
state: {
|
|
299
|
-
name: string;
|
|
300
303
|
id: string;
|
|
304
|
+
name: string;
|
|
301
305
|
createdAt: Date;
|
|
302
306
|
updatedAt: Date;
|
|
303
307
|
deletedAt: Date | null;
|
|
304
308
|
isActive: boolean;
|
|
305
309
|
};
|
|
306
310
|
} & {
|
|
307
|
-
name: string;
|
|
308
311
|
id: string;
|
|
312
|
+
name: string;
|
|
309
313
|
createdAt: Date;
|
|
310
314
|
updatedAt: Date;
|
|
311
315
|
deletedAt: Date | null;
|
|
@@ -317,12 +321,14 @@ export declare function confirmProspectOrder(prisma: PrismaClient, orderId: stri
|
|
|
317
321
|
allowOnline: boolean;
|
|
318
322
|
waybillOnly: boolean;
|
|
319
323
|
estimatedDays: number | null;
|
|
324
|
+
noteTitle: string | null;
|
|
325
|
+
noteContent: string | null;
|
|
320
326
|
isActive: boolean;
|
|
321
327
|
};
|
|
322
328
|
items: ({
|
|
323
329
|
warehouse: {
|
|
324
|
-
name: string;
|
|
325
330
|
id: string;
|
|
331
|
+
name: string;
|
|
326
332
|
createdAt: Date;
|
|
327
333
|
updatedAt: Date;
|
|
328
334
|
deletedAt: Date | null;
|
|
@@ -333,8 +339,8 @@ export declare function confirmProspectOrder(prisma: PrismaClient, orderId: stri
|
|
|
333
339
|
};
|
|
334
340
|
variant: {
|
|
335
341
|
product: {
|
|
336
|
-
name: string;
|
|
337
342
|
id: string;
|
|
343
|
+
name: string;
|
|
338
344
|
slug: string;
|
|
339
345
|
createdAt: Date;
|
|
340
346
|
updatedAt: Date;
|
|
@@ -346,8 +352,8 @@ export declare function confirmProspectOrder(prisma: PrismaClient, orderId: stri
|
|
|
346
352
|
quantityDiscounts: import("@prisma/client/runtime/library").JsonValue | null;
|
|
347
353
|
};
|
|
348
354
|
} & {
|
|
349
|
-
name: string | null;
|
|
350
355
|
id: string;
|
|
356
|
+
name: string | null;
|
|
351
357
|
createdAt: Date;
|
|
352
358
|
updatedAt: Date;
|
|
353
359
|
deletedAt: Date | null;
|
|
@@ -368,8 +374,8 @@ export declare function confirmProspectOrder(prisma: PrismaClient, orderId: stri
|
|
|
368
374
|
priceAtPurchase: import("@prisma/client/runtime/library").Decimal;
|
|
369
375
|
})[];
|
|
370
376
|
} & {
|
|
371
|
-
id: string;
|
|
372
377
|
email: string | null;
|
|
378
|
+
id: string;
|
|
373
379
|
createdAt: Date;
|
|
374
380
|
updatedAt: Date;
|
|
375
381
|
deletedAt: Date | null;
|
|
@@ -421,8 +427,8 @@ export declare function getProspectRecoveryStats(prisma: PrismaClient, brandId?:
|
|
|
421
427
|
* Mark order as prospect with reason
|
|
422
428
|
*/
|
|
423
429
|
export declare function markOrderAsProspect(prisma: PrismaClient, orderId: string, reason: ProspectReason, notes: string, userId?: string): Promise<{
|
|
424
|
-
id: string;
|
|
425
430
|
email: string | null;
|
|
431
|
+
id: string;
|
|
426
432
|
createdAt: Date;
|
|
427
433
|
updatedAt: Date;
|
|
428
434
|
deletedAt: Date | null;
|