@axova/shared 1.0.0
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/CONFIGURATION_GUIDE.md +1 -0
- package/README.md +384 -0
- package/SCHEMA_ORGANIZATION.md +209 -0
- package/dist/configs/index.d.ts +85 -0
- package/dist/configs/index.js +555 -0
- package/dist/events/kafka.d.ts +40 -0
- package/dist/events/kafka.js +311 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +41 -0
- package/dist/interfaces/customer-events.d.ts +85 -0
- package/dist/interfaces/customer-events.js +2 -0
- package/dist/interfaces/inventory-events.d.ts +453 -0
- package/dist/interfaces/inventory-events.js +3 -0
- package/dist/interfaces/inventory-types.d.ts +894 -0
- package/dist/interfaces/inventory-types.js +3 -0
- package/dist/interfaces/order-events.d.ts +320 -0
- package/dist/interfaces/order-events.js +3 -0
- package/dist/lib/auditLogger.d.ts +162 -0
- package/dist/lib/auditLogger.js +626 -0
- package/dist/lib/authOrganization.d.ts +24 -0
- package/dist/lib/authOrganization.js +110 -0
- package/dist/lib/db.d.ts +6 -0
- package/dist/lib/db.js +88 -0
- package/dist/middleware/serviceAuth.d.ts +60 -0
- package/dist/middleware/serviceAuth.js +272 -0
- package/dist/middleware/storeOwnership.d.ts +15 -0
- package/dist/middleware/storeOwnership.js +156 -0
- package/dist/middleware/storeValidationMiddleware.d.ts +44 -0
- package/dist/middleware/storeValidationMiddleware.js +180 -0
- package/dist/middleware/userAuth.d.ts +27 -0
- package/dist/middleware/userAuth.js +218 -0
- package/dist/schemas/admin/admin-schema.d.ts +741 -0
- package/dist/schemas/admin/admin-schema.js +111 -0
- package/dist/schemas/ai-moderation/ai-moderation-schema.d.ts +648 -0
- package/dist/schemas/ai-moderation/ai-moderation-schema.js +88 -0
- package/dist/schemas/common/common-schemas.d.ts +436 -0
- package/dist/schemas/common/common-schemas.js +94 -0
- package/dist/schemas/compliance/compliance-schema.d.ts +3388 -0
- package/dist/schemas/compliance/compliance-schema.js +472 -0
- package/dist/schemas/compliance/kyc-schema.d.ts +2642 -0
- package/dist/schemas/compliance/kyc-schema.js +361 -0
- package/dist/schemas/customer/customer-schema.d.ts +2727 -0
- package/dist/schemas/customer/customer-schema.js +399 -0
- package/dist/schemas/index.d.ts +27 -0
- package/dist/schemas/index.js +138 -0
- package/dist/schemas/inventory/inventory-tables.d.ts +9476 -0
- package/dist/schemas/inventory/inventory-tables.js +1470 -0
- package/dist/schemas/inventory/lot-tables.d.ts +3281 -0
- package/dist/schemas/inventory/lot-tables.js +608 -0
- package/dist/schemas/order/order-schema.d.ts +5825 -0
- package/dist/schemas/order/order-schema.js +954 -0
- package/dist/schemas/product/discount-relations.d.ts +15 -0
- package/dist/schemas/product/discount-relations.js +34 -0
- package/dist/schemas/product/discount-schema.d.ts +1975 -0
- package/dist/schemas/product/discount-schema.js +297 -0
- package/dist/schemas/product/product-relations.d.ts +41 -0
- package/dist/schemas/product/product-relations.js +133 -0
- package/dist/schemas/product/product-schema.d.ts +4544 -0
- package/dist/schemas/product/product-schema.js +671 -0
- package/dist/schemas/store/store-audit-schema.d.ts +4135 -0
- package/dist/schemas/store/store-audit-schema.js +556 -0
- package/dist/schemas/store/store-schema.d.ts +3100 -0
- package/dist/schemas/store/store-schema.js +381 -0
- package/dist/schemas/store/store-settings-schema.d.ts +665 -0
- package/dist/schemas/store/store-settings-schema.js +141 -0
- package/dist/schemas/types.d.ts +50 -0
- package/dist/schemas/types.js +3 -0
- package/dist/types/events.d.ts +2396 -0
- package/dist/types/events.js +505 -0
- package/dist/utils/errorHandler.d.ts +12 -0
- package/dist/utils/errorHandler.js +36 -0
- package/dist/utils/subdomain.d.ts +6 -0
- package/dist/utils/subdomain.js +20 -0
- package/nul +8 -0
- package/package.json +43 -0
- package/src/configs/index.ts +654 -0
- package/src/events/kafka.ts +429 -0
- package/src/index.ts +26 -0
- package/src/interfaces/customer-events.ts +106 -0
- package/src/interfaces/inventory-events.ts +545 -0
- package/src/interfaces/inventory-types.ts +1004 -0
- package/src/interfaces/order-events.ts +381 -0
- package/src/lib/auditLogger.ts +1117 -0
- package/src/lib/authOrganization.ts +153 -0
- package/src/lib/db.ts +64 -0
- package/src/middleware/serviceAuth.ts +328 -0
- package/src/middleware/storeOwnership.ts +199 -0
- package/src/middleware/storeValidationMiddleware.ts +247 -0
- package/src/middleware/userAuth.ts +248 -0
- package/src/schemas/admin/admin-schema.ts +208 -0
- package/src/schemas/ai-moderation/ai-moderation-schema.ts +180 -0
- package/src/schemas/common/common-schemas.ts +108 -0
- package/src/schemas/compliance/compliance-schema.ts +927 -0
- package/src/schemas/compliance/kyc-schema.ts +649 -0
- package/src/schemas/customer/customer-schema.ts +576 -0
- package/src/schemas/index.ts +189 -0
- package/src/schemas/inventory/inventory-tables.ts +1927 -0
- package/src/schemas/inventory/lot-tables.ts +799 -0
- package/src/schemas/order/order-schema.ts +1400 -0
- package/src/schemas/product/discount-relations.ts +44 -0
- package/src/schemas/product/discount-schema.ts +464 -0
- package/src/schemas/product/product-relations.ts +187 -0
- package/src/schemas/product/product-schema.ts +955 -0
- package/src/schemas/store/ethiopian_business_api.md.resolved +212 -0
- package/src/schemas/store/store-audit-schema.ts +1257 -0
- package/src/schemas/store/store-schema.ts +661 -0
- package/src/schemas/store/store-settings-schema.ts +231 -0
- package/src/schemas/types.ts +67 -0
- package/src/types/events.ts +646 -0
- package/src/utils/errorHandler.ts +44 -0
- package/src/utils/subdomain.ts +19 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// Base event schema
|
|
4
|
+
export const BaseEventSchema = z.object({
|
|
5
|
+
id: z.string(),
|
|
6
|
+
timestamp: z.string(),
|
|
7
|
+
source: z.string(),
|
|
8
|
+
version: z.string().default("1.0"),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// Store Events
|
|
12
|
+
export const StoreCreatedEventSchema = BaseEventSchema.extend({
|
|
13
|
+
type: z.literal("store.created"),
|
|
14
|
+
data: z.object({
|
|
15
|
+
storeId: z.string(),
|
|
16
|
+
userId: z.string(),
|
|
17
|
+
storeName: z.string(),
|
|
18
|
+
subdomain: z.string(),
|
|
19
|
+
timezone: z.string(),
|
|
20
|
+
currency: z.string(),
|
|
21
|
+
isActive: z.boolean(),
|
|
22
|
+
organizationId: z.string().optional(),
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const StoreUpdatedEventSchema = BaseEventSchema.extend({
|
|
27
|
+
type: z.literal("store.updated"),
|
|
28
|
+
data: z.object({
|
|
29
|
+
storeId: z.string(),
|
|
30
|
+
userId: z.string(),
|
|
31
|
+
changes: z.record(z.unknown()),
|
|
32
|
+
previousValues: z.record(z.unknown()).optional(),
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Compliance Events
|
|
37
|
+
export const ComplianceViolationDetectedEventSchema = BaseEventSchema.extend({
|
|
38
|
+
type: z.literal("compliance.violation.detected"),
|
|
39
|
+
data: z.object({
|
|
40
|
+
storeId: z.string(),
|
|
41
|
+
violationType: z.enum([
|
|
42
|
+
"CONTENT_VIOLATION",
|
|
43
|
+
"POLICY_VIOLATION",
|
|
44
|
+
"BEHAVIOR_VIOLATION",
|
|
45
|
+
]),
|
|
46
|
+
severity: z.enum(["LOW", "MEDIUM", "HIGH", "CRITICAL"]),
|
|
47
|
+
description: z.string(),
|
|
48
|
+
evidence: z.record(z.unknown()).optional(),
|
|
49
|
+
autoAction: z.enum(["NONE", "WARNING", "SUSPEND", "BAN"]).optional(),
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const StoreSuspendedEventSchema = BaseEventSchema.extend({
|
|
54
|
+
type: z.literal("store.suspended"),
|
|
55
|
+
data: z.object({
|
|
56
|
+
storeId: z.string(),
|
|
57
|
+
reason: z.string(),
|
|
58
|
+
duration: z.number().optional(), // Duration in hours, null for indefinite
|
|
59
|
+
suspendedBy: z.string(),
|
|
60
|
+
additionalNotes: z.string().optional(),
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const StoreUnbannedEventSchema = BaseEventSchema.extend({
|
|
65
|
+
type: z.literal("store.unbanned"),
|
|
66
|
+
data: z.object({
|
|
67
|
+
storeId: z.string(),
|
|
68
|
+
reason: z.string(),
|
|
69
|
+
unbannedBy: z.string(),
|
|
70
|
+
previousBanReason: z.string().optional(),
|
|
71
|
+
additionalNotes: z.string().optional(),
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Notification Events
|
|
76
|
+
export const NotificationSendEventSchema = BaseEventSchema.extend({
|
|
77
|
+
type: z.literal("notification.send"),
|
|
78
|
+
data: z.object({
|
|
79
|
+
recipientId: z.string(),
|
|
80
|
+
recipientType: z.enum(["USER", "STORE", "ADMIN"]),
|
|
81
|
+
channel: z.enum(["EMAIL", "SMS", "IN_APP", "PUSH"]),
|
|
82
|
+
template: z.string(),
|
|
83
|
+
templateData: z.record(z.unknown()),
|
|
84
|
+
priority: z.enum(["LOW", "NORMAL", "HIGH", "URGENT"]).default("NORMAL"),
|
|
85
|
+
scheduledFor: z.string().optional(), // ISO date string
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Audit Events
|
|
90
|
+
export const AuditLoggedEventSchema = BaseEventSchema.extend({
|
|
91
|
+
type: z.literal("audit.logged"),
|
|
92
|
+
data: z.object({
|
|
93
|
+
action: z.string(),
|
|
94
|
+
resource: z.string(),
|
|
95
|
+
resourceId: z.string(),
|
|
96
|
+
performedBy: z.string(),
|
|
97
|
+
performedByType: z.enum(["USER", "SYSTEM", "ADMIN", "SERVICE"]),
|
|
98
|
+
changes: z.record(z.unknown()).optional(),
|
|
99
|
+
metadata: z.record(z.unknown()).optional(),
|
|
100
|
+
ip: z.string().optional(),
|
|
101
|
+
userAgent: z.string().optional(),
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Appeal Events
|
|
106
|
+
export const AppealSubmittedEventSchema = BaseEventSchema.extend({
|
|
107
|
+
type: z.literal("appeal.submitted"),
|
|
108
|
+
data: z.object({
|
|
109
|
+
appealId: z.string(),
|
|
110
|
+
storeId: z.string(),
|
|
111
|
+
userId: z.string(),
|
|
112
|
+
appealType: z.enum([
|
|
113
|
+
"BAN_APPEAL",
|
|
114
|
+
"SUSPENSION_APPEAL",
|
|
115
|
+
"WARNING_APPEAL",
|
|
116
|
+
"POLICY_DISPUTE",
|
|
117
|
+
]),
|
|
118
|
+
reason: z.string(),
|
|
119
|
+
evidence: z.array(z.string()).optional(), // Array of URLs or file references
|
|
120
|
+
originalViolationId: z.string().optional(),
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export const AppealReviewedEventSchema = BaseEventSchema.extend({
|
|
125
|
+
type: z.literal("appeal.reviewed"),
|
|
126
|
+
data: z.object({
|
|
127
|
+
appealId: z.string(),
|
|
128
|
+
storeId: z.string(),
|
|
129
|
+
reviewedBy: z.string(),
|
|
130
|
+
decision: z.enum(["APPROVED", "REJECTED", "PARTIALLY_APPROVED"]),
|
|
131
|
+
reasoning: z.string(),
|
|
132
|
+
actionTaken: z.string().optional(),
|
|
133
|
+
reviewNotes: z.string().optional(),
|
|
134
|
+
}),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Type exports
|
|
138
|
+
export type StoreCreatedEvent = z.infer<typeof StoreCreatedEventSchema>;
|
|
139
|
+
export type StoreUpdatedEvent = z.infer<typeof StoreUpdatedEventSchema>;
|
|
140
|
+
export type ComplianceViolationDetectedEvent = z.infer<
|
|
141
|
+
typeof ComplianceViolationDetectedEventSchema
|
|
142
|
+
>;
|
|
143
|
+
export type StoreSuspendedEvent = z.infer<typeof StoreSuspendedEventSchema>;
|
|
144
|
+
export type StoreUnbannedEvent = z.infer<typeof StoreUnbannedEventSchema>;
|
|
145
|
+
export type NotificationSendEvent = z.infer<typeof NotificationSendEventSchema>;
|
|
146
|
+
export type AuditLoggedEvent = z.infer<typeof AuditLoggedEventSchema>;
|
|
147
|
+
export type AppealSubmittedEvent = z.infer<typeof AppealSubmittedEventSchema>;
|
|
148
|
+
export type AppealReviewedEvent = z.infer<typeof AppealReviewedEventSchema>;
|
|
149
|
+
|
|
150
|
+
// Union type of all events
|
|
151
|
+
// Customer Events
|
|
152
|
+
export const CustomerCreatedEventSchema = BaseEventSchema.extend({
|
|
153
|
+
type: z.literal("customer.created"),
|
|
154
|
+
data: z.object({
|
|
155
|
+
customerId: z.string(),
|
|
156
|
+
userId: z.string(),
|
|
157
|
+
email: z.string(),
|
|
158
|
+
firstName: z.string(),
|
|
159
|
+
lastName: z.string(),
|
|
160
|
+
customerType: z.string(),
|
|
161
|
+
registrationSource: z.string(),
|
|
162
|
+
storeLocationId: z.string().optional(),
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
export const CustomerUpdatedEventSchema = BaseEventSchema.extend({
|
|
167
|
+
type: z.literal("customer.updated"),
|
|
168
|
+
data: z.object({
|
|
169
|
+
customerId: z.string(),
|
|
170
|
+
userId: z.string(),
|
|
171
|
+
changes: z.record(z.unknown()),
|
|
172
|
+
previousValues: z.record(z.unknown()),
|
|
173
|
+
registrationSourceChanged: z.boolean(),
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
export const CustomerDeletedEventSchema = BaseEventSchema.extend({
|
|
178
|
+
type: z.literal("customer.deleted"),
|
|
179
|
+
data: z.object({
|
|
180
|
+
customerId: z.string(),
|
|
181
|
+
userId: z.string(),
|
|
182
|
+
email: z.string(),
|
|
183
|
+
customerType: z.string(),
|
|
184
|
+
registrationSource: z.string(),
|
|
185
|
+
totalSpent: z.string(),
|
|
186
|
+
totalOrders: z.number(),
|
|
187
|
+
totalVisits: z.number(),
|
|
188
|
+
totalInteractions: z.number(),
|
|
189
|
+
}),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
export const CustomerVisitCreatedEventSchema = BaseEventSchema.extend({
|
|
193
|
+
type: z.literal("customer.visit.created"),
|
|
194
|
+
data: z.object({
|
|
195
|
+
visitId: z.string(),
|
|
196
|
+
customerId: z.string(),
|
|
197
|
+
visitType: z.string(),
|
|
198
|
+
storeLocationId: z.string().optional(),
|
|
199
|
+
outcome: z.string().optional(),
|
|
200
|
+
duration: z.number().optional(),
|
|
201
|
+
}),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
export const CustomerInteractionCreatedEventSchema = BaseEventSchema.extend({
|
|
205
|
+
type: z.literal("customer.interaction.created"),
|
|
206
|
+
data: z.object({
|
|
207
|
+
interactionId: z.string(),
|
|
208
|
+
customerId: z.string(),
|
|
209
|
+
interactionType: z.string(),
|
|
210
|
+
targetType: z.string().optional(),
|
|
211
|
+
targetId: z.string().optional(),
|
|
212
|
+
outcome: z.string().optional(),
|
|
213
|
+
staffId: z.string().optional(),
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
export const CustomerNoteCreatedEventSchema = BaseEventSchema.extend({
|
|
218
|
+
type: z.literal("customer.note.created"),
|
|
219
|
+
data: z.object({
|
|
220
|
+
noteId: z.string(),
|
|
221
|
+
customerId: z.string(),
|
|
222
|
+
noteType: z.string(),
|
|
223
|
+
priority: z.string(),
|
|
224
|
+
isAlert: z.boolean(),
|
|
225
|
+
createdBy: z.string(),
|
|
226
|
+
}),
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
export const CustomerSupportTicketCreatedEventSchema = BaseEventSchema.extend({
|
|
230
|
+
type: z.literal("customer.support.ticket.created"),
|
|
231
|
+
data: z.object({
|
|
232
|
+
ticketId: z.string(),
|
|
233
|
+
ticketNumber: z.string(),
|
|
234
|
+
customerId: z.string(),
|
|
235
|
+
subject: z.string(),
|
|
236
|
+
category: z.string(),
|
|
237
|
+
priority: z.string(),
|
|
238
|
+
}),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
export const CustomerReviewSubmittedEventSchema = BaseEventSchema.extend({
|
|
242
|
+
type: z.literal("customer.review.submitted"),
|
|
243
|
+
data: z.object({
|
|
244
|
+
reviewId: z.string(),
|
|
245
|
+
customerId: z.string(),
|
|
246
|
+
targetType: z.string(),
|
|
247
|
+
targetId: z.string(),
|
|
248
|
+
rating: z.number(),
|
|
249
|
+
isVerifiedPurchase: z.boolean(),
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Order Events
|
|
254
|
+
export const OrderCreatedEventSchema = BaseEventSchema.extend({
|
|
255
|
+
type: z.literal("order.created"),
|
|
256
|
+
data: z.object({
|
|
257
|
+
orderId: z.string(),
|
|
258
|
+
orderNumber: z.string(),
|
|
259
|
+
storeId: z.string(),
|
|
260
|
+
customerId: z.string().optional(),
|
|
261
|
+
userId: z.string().optional(),
|
|
262
|
+
orderType: z.string(),
|
|
263
|
+
orderSource: z.string(),
|
|
264
|
+
status: z.string(),
|
|
265
|
+
totalAmount: z.string(),
|
|
266
|
+
currency: z.string(),
|
|
267
|
+
itemCount: z.number(),
|
|
268
|
+
isGuestOrder: z.boolean(),
|
|
269
|
+
paymentMethod: z.string().optional(),
|
|
270
|
+
shippingRequired: z.boolean(),
|
|
271
|
+
priority: z.string(),
|
|
272
|
+
}),
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
export const OrderUpdatedEventSchema = BaseEventSchema.extend({
|
|
276
|
+
type: z.literal("order.updated"),
|
|
277
|
+
data: z.object({
|
|
278
|
+
orderId: z.string(),
|
|
279
|
+
orderNumber: z.string(),
|
|
280
|
+
storeId: z.string(),
|
|
281
|
+
customerId: z.string().optional(),
|
|
282
|
+
changes: z.record(z.unknown()),
|
|
283
|
+
previousValues: z.record(z.unknown()),
|
|
284
|
+
statusChanged: z.boolean(),
|
|
285
|
+
paymentStatusChanged: z.boolean(),
|
|
286
|
+
fulfillmentStatusChanged: z.boolean(),
|
|
287
|
+
amountChanged: z.boolean(),
|
|
288
|
+
}),
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
export const OrderStatusChangedEventSchema = BaseEventSchema.extend({
|
|
292
|
+
type: z.literal("order.status.changed"),
|
|
293
|
+
data: z.object({
|
|
294
|
+
orderId: z.string(),
|
|
295
|
+
orderNumber: z.string(),
|
|
296
|
+
storeId: z.string(),
|
|
297
|
+
customerId: z.string().optional(),
|
|
298
|
+
fromStatus: z.string(),
|
|
299
|
+
toStatus: z.string(),
|
|
300
|
+
reason: z.string().optional(),
|
|
301
|
+
actorId: z.string(),
|
|
302
|
+
actorType: z.string(),
|
|
303
|
+
timestamp: z.string(),
|
|
304
|
+
}),
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
export const OrderPaymentProcessedEventSchema = BaseEventSchema.extend({
|
|
308
|
+
type: z.literal("order.payment.processed"),
|
|
309
|
+
data: z.object({
|
|
310
|
+
orderId: z.string(),
|
|
311
|
+
paymentId: z.string(),
|
|
312
|
+
transactionId: z.string().optional(),
|
|
313
|
+
paymentMethod: z.string(),
|
|
314
|
+
paymentProvider: z.string().optional(),
|
|
315
|
+
amount: z.string(),
|
|
316
|
+
currency: z.string(),
|
|
317
|
+
status: z.string(),
|
|
318
|
+
isSuccessful: z.boolean(),
|
|
319
|
+
failureReason: z.string().optional(),
|
|
320
|
+
}),
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
export const OrderShippedEventSchema = BaseEventSchema.extend({
|
|
324
|
+
type: z.literal("order.shipped"),
|
|
325
|
+
data: z.object({
|
|
326
|
+
orderId: z.string(),
|
|
327
|
+
fulfillmentId: z.string(),
|
|
328
|
+
trackingNumber: z.string().optional(),
|
|
329
|
+
trackingUrl: z.string().optional(),
|
|
330
|
+
shippingCarrier: z.string().optional(),
|
|
331
|
+
shippingService: z.string().optional(),
|
|
332
|
+
estimatedDeliveryDate: z.string().optional(),
|
|
333
|
+
packedBy: z.string().optional(),
|
|
334
|
+
shippedBy: z.string().optional(),
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
export const OrderDeliveredEventSchema = BaseEventSchema.extend({
|
|
339
|
+
type: z.literal("order.delivered"),
|
|
340
|
+
data: z.object({
|
|
341
|
+
orderId: z.string(),
|
|
342
|
+
fulfillmentId: z.string(),
|
|
343
|
+
deliveredAt: z.string(),
|
|
344
|
+
deliveredBy: z.string().optional(),
|
|
345
|
+
signedBy: z.string().optional(),
|
|
346
|
+
deliveryLocation: z.string().optional(),
|
|
347
|
+
proofOfDelivery: z.record(z.unknown()).optional(),
|
|
348
|
+
}),
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
export const OrderCancelledEventSchema = BaseEventSchema.extend({
|
|
352
|
+
type: z.literal("order.cancelled"),
|
|
353
|
+
data: z.object({
|
|
354
|
+
orderId: z.string(),
|
|
355
|
+
orderNumber: z.string(),
|
|
356
|
+
storeId: z.string(),
|
|
357
|
+
customerId: z.string().optional(),
|
|
358
|
+
cancellationReason: z.string(),
|
|
359
|
+
cancelledBy: z.string(),
|
|
360
|
+
cancelledByType: z.string(),
|
|
361
|
+
refundRequired: z.boolean(),
|
|
362
|
+
refundAmount: z.string().optional(),
|
|
363
|
+
inventoryReleased: z.boolean(),
|
|
364
|
+
}),
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
export const OrderRefundedEventSchema = BaseEventSchema.extend({
|
|
368
|
+
type: z.literal("order.refunded"),
|
|
369
|
+
data: z.object({
|
|
370
|
+
orderId: z.string(),
|
|
371
|
+
paymentId: z.string(),
|
|
372
|
+
refundId: z.string(),
|
|
373
|
+
refundAmount: z.string(),
|
|
374
|
+
refundReason: z.string(),
|
|
375
|
+
refundMethod: z.string(),
|
|
376
|
+
isPartialRefund: z.boolean(),
|
|
377
|
+
processedBy: z.string(),
|
|
378
|
+
customerNotified: z.boolean(),
|
|
379
|
+
}),
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
export const OrderNoteAddedEventSchema = BaseEventSchema.extend({
|
|
383
|
+
type: z.literal("order.note.added"),
|
|
384
|
+
data: z.object({
|
|
385
|
+
orderId: z.string(),
|
|
386
|
+
noteId: z.string(),
|
|
387
|
+
noteType: z.string(),
|
|
388
|
+
content: z.string(),
|
|
389
|
+
isCustomerVisible: z.boolean(),
|
|
390
|
+
priority: z.string(),
|
|
391
|
+
createdBy: z.string(),
|
|
392
|
+
createdByName: z.string(),
|
|
393
|
+
requiresFollowUp: z.boolean(),
|
|
394
|
+
}),
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
export const OrderItemAddedEventSchema = BaseEventSchema.extend({
|
|
398
|
+
type: z.literal("order.item.added"),
|
|
399
|
+
data: z.object({
|
|
400
|
+
orderId: z.string(),
|
|
401
|
+
itemId: z.string(),
|
|
402
|
+
productId: z.string(),
|
|
403
|
+
variantId: z.string().optional(),
|
|
404
|
+
sku: z.string(),
|
|
405
|
+
productTitle: z.string(),
|
|
406
|
+
quantity: z.number(),
|
|
407
|
+
unitPrice: z.string(),
|
|
408
|
+
totalPrice: z.string(),
|
|
409
|
+
addedBy: z.string(),
|
|
410
|
+
}),
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
export const OrderItemRemovedEventSchema = BaseEventSchema.extend({
|
|
414
|
+
type: z.literal("order.item.removed"),
|
|
415
|
+
data: z.object({
|
|
416
|
+
orderId: z.string(),
|
|
417
|
+
itemId: z.string(),
|
|
418
|
+
productId: z.string(),
|
|
419
|
+
sku: z.string(),
|
|
420
|
+
productTitle: z.string(),
|
|
421
|
+
quantity: z.number(),
|
|
422
|
+
removedBy: z.string(),
|
|
423
|
+
removalReason: z.string().optional(),
|
|
424
|
+
}),
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
export const OrderDiscountAppliedEventSchema = BaseEventSchema.extend({
|
|
428
|
+
type: z.literal("order.discount.applied"),
|
|
429
|
+
data: z.object({
|
|
430
|
+
orderId: z.string(),
|
|
431
|
+
discountId: z.string(),
|
|
432
|
+
discountCode: z.string().optional(),
|
|
433
|
+
discountType: z.string(),
|
|
434
|
+
discountAmount: z.string(),
|
|
435
|
+
discountPercentage: z.number().optional(),
|
|
436
|
+
appliedBy: z.string().optional(),
|
|
437
|
+
campaignId: z.string().optional(),
|
|
438
|
+
}),
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Subscription Events
|
|
442
|
+
export const SubscriptionOrderCreatedEventSchema = BaseEventSchema.extend({
|
|
443
|
+
type: z.literal("subscription.order.created"),
|
|
444
|
+
data: z.object({
|
|
445
|
+
subscriptionId: z.string(),
|
|
446
|
+
orderId: z.string(),
|
|
447
|
+
orderNumber: z.string(),
|
|
448
|
+
storeId: z.string(),
|
|
449
|
+
customerId: z.string().optional(),
|
|
450
|
+
frequency: z.string(),
|
|
451
|
+
planId: z.string(),
|
|
452
|
+
totalAmount: z.string(),
|
|
453
|
+
correlationId: z.string().optional(),
|
|
454
|
+
}),
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
export const SubscriptionRenewedEventSchema = BaseEventSchema.extend({
|
|
458
|
+
type: z.literal("subscription.renewed"),
|
|
459
|
+
data: z.object({
|
|
460
|
+
subscriptionId: z.string(),
|
|
461
|
+
orderId: z.string(),
|
|
462
|
+
orderNumber: z.string(),
|
|
463
|
+
storeId: z.string(),
|
|
464
|
+
customerId: z.string().optional(),
|
|
465
|
+
cycle: z.number(),
|
|
466
|
+
totalAmount: z.string(),
|
|
467
|
+
correlationId: z.string().optional(),
|
|
468
|
+
}),
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
export const SubscriptionCancelledEventSchema = BaseEventSchema.extend({
|
|
472
|
+
type: z.literal("subscription.cancelled"),
|
|
473
|
+
data: z.object({
|
|
474
|
+
subscriptionId: z.string(),
|
|
475
|
+
orderId: z.string(),
|
|
476
|
+
orderNumber: z.string(),
|
|
477
|
+
storeId: z.string(),
|
|
478
|
+
customerId: z.string().optional(),
|
|
479
|
+
reason: z.string().optional(),
|
|
480
|
+
action: z.string(),
|
|
481
|
+
parameters: z.record(z.unknown()).optional(),
|
|
482
|
+
correlationId: z.string().optional(),
|
|
483
|
+
}),
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
export const OrderReturnRequestedEventSchema = BaseEventSchema.extend({
|
|
487
|
+
type: z.literal("order.return.requested"),
|
|
488
|
+
data: z.object({
|
|
489
|
+
orderId: z.string(),
|
|
490
|
+
orderNumber: z.string(),
|
|
491
|
+
storeId: z.string(),
|
|
492
|
+
customerId: z.string(),
|
|
493
|
+
returnId: z.string(),
|
|
494
|
+
returnType: z.string(),
|
|
495
|
+
reason: z.string(),
|
|
496
|
+
itemCount: z.number(),
|
|
497
|
+
totalAmount: z.string().optional(),
|
|
498
|
+
correlationId: z.string().optional(),
|
|
499
|
+
}),
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
export const OrderRefundProcessedEventSchema = BaseEventSchema.extend({
|
|
503
|
+
type: z.literal("order.refund.processed"),
|
|
504
|
+
data: z.object({
|
|
505
|
+
orderId: z.string(),
|
|
506
|
+
orderNumber: z.string(),
|
|
507
|
+
storeId: z.string(),
|
|
508
|
+
customerId: z.string().optional(),
|
|
509
|
+
refundId: z.string(),
|
|
510
|
+
refundAmount: z.string(),
|
|
511
|
+
refundMethod: z.string(),
|
|
512
|
+
reason: z.string(),
|
|
513
|
+
processedBy: z.string(),
|
|
514
|
+
correlationId: z.string().optional(),
|
|
515
|
+
}),
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// Order event types
|
|
519
|
+
export type OrderCreatedEvent = z.infer<typeof OrderCreatedEventSchema>;
|
|
520
|
+
export type OrderUpdatedEvent = z.infer<typeof OrderUpdatedEventSchema>;
|
|
521
|
+
export type OrderStatusChangedEvent = z.infer<
|
|
522
|
+
typeof OrderStatusChangedEventSchema
|
|
523
|
+
>;
|
|
524
|
+
export type OrderPaymentProcessedEvent = z.infer<
|
|
525
|
+
typeof OrderPaymentProcessedEventSchema
|
|
526
|
+
>;
|
|
527
|
+
export type OrderShippedEvent = z.infer<typeof OrderShippedEventSchema>;
|
|
528
|
+
export type OrderDeliveredEvent = z.infer<typeof OrderDeliveredEventSchema>;
|
|
529
|
+
export type OrderCancelledEvent = z.infer<typeof OrderCancelledEventSchema>;
|
|
530
|
+
export type OrderRefundedEvent = z.infer<typeof OrderRefundedEventSchema>;
|
|
531
|
+
export type OrderNoteAddedEvent = z.infer<typeof OrderNoteAddedEventSchema>;
|
|
532
|
+
export type OrderItemAddedEvent = z.infer<typeof OrderItemAddedEventSchema>;
|
|
533
|
+
export type OrderItemRemovedEvent = z.infer<typeof OrderItemRemovedEventSchema>;
|
|
534
|
+
export type OrderDiscountAppliedEvent = z.infer<
|
|
535
|
+
typeof OrderDiscountAppliedEventSchema
|
|
536
|
+
>;
|
|
537
|
+
|
|
538
|
+
// Subscription event types
|
|
539
|
+
export type SubscriptionOrderCreatedEvent = z.infer<
|
|
540
|
+
typeof SubscriptionOrderCreatedEventSchema
|
|
541
|
+
>;
|
|
542
|
+
export type SubscriptionRenewedEvent = z.infer<
|
|
543
|
+
typeof SubscriptionRenewedEventSchema
|
|
544
|
+
>;
|
|
545
|
+
export type SubscriptionCancelledEvent = z.infer<
|
|
546
|
+
typeof SubscriptionCancelledEventSchema
|
|
547
|
+
>;
|
|
548
|
+
export type OrderReturnRequestedEvent = z.infer<
|
|
549
|
+
typeof OrderReturnRequestedEventSchema
|
|
550
|
+
>;
|
|
551
|
+
export type OrderRefundProcessedEvent = z.infer<
|
|
552
|
+
typeof OrderRefundProcessedEventSchema
|
|
553
|
+
>;
|
|
554
|
+
|
|
555
|
+
// Customer event types
|
|
556
|
+
export type CustomerCreatedEvent = z.infer<typeof CustomerCreatedEventSchema>;
|
|
557
|
+
export type CustomerUpdatedEvent = z.infer<typeof CustomerUpdatedEventSchema>;
|
|
558
|
+
export type CustomerDeletedEvent = z.infer<typeof CustomerDeletedEventSchema>;
|
|
559
|
+
export type CustomerVisitCreatedEvent = z.infer<
|
|
560
|
+
typeof CustomerVisitCreatedEventSchema
|
|
561
|
+
>;
|
|
562
|
+
export type CustomerInteractionCreatedEvent = z.infer<
|
|
563
|
+
typeof CustomerInteractionCreatedEventSchema
|
|
564
|
+
>;
|
|
565
|
+
export type CustomerNoteCreatedEvent = z.infer<
|
|
566
|
+
typeof CustomerNoteCreatedEventSchema
|
|
567
|
+
>;
|
|
568
|
+
export type CustomerSupportTicketCreatedEvent = z.infer<
|
|
569
|
+
typeof CustomerSupportTicketCreatedEventSchema
|
|
570
|
+
>;
|
|
571
|
+
export type CustomerReviewSubmittedEvent = z.infer<
|
|
572
|
+
typeof CustomerReviewSubmittedEventSchema
|
|
573
|
+
>;
|
|
574
|
+
|
|
575
|
+
export type AxovaEvent =
|
|
576
|
+
| StoreCreatedEvent
|
|
577
|
+
| StoreUpdatedEvent
|
|
578
|
+
| ComplianceViolationDetectedEvent
|
|
579
|
+
| StoreSuspendedEvent
|
|
580
|
+
| StoreUnbannedEvent
|
|
581
|
+
| NotificationSendEvent
|
|
582
|
+
| AuditLoggedEvent
|
|
583
|
+
| AppealSubmittedEvent
|
|
584
|
+
| AppealReviewedEvent
|
|
585
|
+
| OrderCreatedEvent
|
|
586
|
+
| OrderUpdatedEvent
|
|
587
|
+
| OrderStatusChangedEvent
|
|
588
|
+
| OrderPaymentProcessedEvent
|
|
589
|
+
| OrderShippedEvent
|
|
590
|
+
| OrderDeliveredEvent
|
|
591
|
+
| OrderCancelledEvent
|
|
592
|
+
| OrderRefundedEvent
|
|
593
|
+
| OrderNoteAddedEvent
|
|
594
|
+
| OrderItemAddedEvent
|
|
595
|
+
| OrderItemRemovedEvent
|
|
596
|
+
| OrderDiscountAppliedEvent
|
|
597
|
+
| SubscriptionOrderCreatedEvent
|
|
598
|
+
| SubscriptionRenewedEvent
|
|
599
|
+
| SubscriptionCancelledEvent
|
|
600
|
+
| OrderReturnRequestedEvent
|
|
601
|
+
| OrderRefundProcessedEvent
|
|
602
|
+
| CustomerCreatedEvent
|
|
603
|
+
| CustomerUpdatedEvent
|
|
604
|
+
| CustomerDeletedEvent
|
|
605
|
+
| CustomerVisitCreatedEvent
|
|
606
|
+
| CustomerInteractionCreatedEvent
|
|
607
|
+
| CustomerNoteCreatedEvent
|
|
608
|
+
| CustomerSupportTicketCreatedEvent
|
|
609
|
+
| CustomerReviewSubmittedEvent;
|
|
610
|
+
|
|
611
|
+
// Kafka topic mappings
|
|
612
|
+
export const KAFKA_TOPICS = {
|
|
613
|
+
STORE_CREATED: "store.created",
|
|
614
|
+
STORE_UPDATED: "store.updated",
|
|
615
|
+
COMPLIANCE_VIOLATION_DETECTED: "compliance.violation.detected",
|
|
616
|
+
STORE_SUSPENDED: "store.suspended",
|
|
617
|
+
STORE_UNBANNED: "store.unbanned",
|
|
618
|
+
NOTIFICATION_SEND: "notification.send",
|
|
619
|
+
AUDIT_LOGGED: "audit.logged",
|
|
620
|
+
APPEAL_SUBMITTED: "appeal.submitted",
|
|
621
|
+
APPEAL_REVIEWED: "appeal.reviewed",
|
|
622
|
+
// Order service topics
|
|
623
|
+
ORDER_CREATED: "order.created",
|
|
624
|
+
ORDER_UPDATED: "order.updated",
|
|
625
|
+
ORDER_STATUS_CHANGED: "order.status.changed",
|
|
626
|
+
ORDER_PAYMENT_PROCESSED: "order.payment.processed",
|
|
627
|
+
ORDER_SHIPPED: "order.shipped",
|
|
628
|
+
ORDER_DELIVERED: "order.delivered",
|
|
629
|
+
ORDER_CANCELLED: "order.cancelled",
|
|
630
|
+
ORDER_REFUNDED: "order.refunded",
|
|
631
|
+
ORDER_NOTE_ADDED: "order.note.added",
|
|
632
|
+
ORDER_ITEM_ADDED: "order.item.added",
|
|
633
|
+
ORDER_ITEM_REMOVED: "order.item.removed",
|
|
634
|
+
ORDER_DISCOUNT_APPLIED: "order.discount.applied",
|
|
635
|
+
// Customer service topics
|
|
636
|
+
CUSTOMER_CREATED: "customer.created",
|
|
637
|
+
CUSTOMER_UPDATED: "customer.updated",
|
|
638
|
+
CUSTOMER_DELETED: "customer.deleted",
|
|
639
|
+
CUSTOMER_VISIT_CREATED: "customer.visit.created",
|
|
640
|
+
CUSTOMER_INTERACTION_CREATED: "customer.interaction.created",
|
|
641
|
+
CUSTOMER_NOTE_CREATED: "customer.note.created",
|
|
642
|
+
CUSTOMER_SUPPORT_TICKET_CREATED: "customer.support.ticket.created",
|
|
643
|
+
CUSTOMER_REVIEW_SUBMITTED: "customer.review.submitted",
|
|
644
|
+
} as const;
|
|
645
|
+
|
|
646
|
+
export type KafkaTopic = (typeof KAFKA_TOPICS)[keyof typeof KAFKA_TOPICS];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { FastifyReply } from "fastify";
|
|
2
|
+
|
|
3
|
+
export class APIError extends Error {
|
|
4
|
+
statusCode: number;
|
|
5
|
+
details?: unknown;
|
|
6
|
+
|
|
7
|
+
constructor(message: string, statusCode = 400, details?: unknown) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
this.details = details;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Handles API errors in a unified way.
|
|
16
|
+
* @param {FastifyReply} reply The Fastify reply object.
|
|
17
|
+
* @param {APIError} error The API error object.
|
|
18
|
+
*/
|
|
19
|
+
export const handleAPIError = (
|
|
20
|
+
reply: FastifyReply,
|
|
21
|
+
error: APIError | Error,
|
|
22
|
+
) => {
|
|
23
|
+
// Default status code
|
|
24
|
+
let statusCode = 500;
|
|
25
|
+
let details: unknown;
|
|
26
|
+
|
|
27
|
+
// If it's an APIError, use its status code and details
|
|
28
|
+
if (error instanceof APIError) {
|
|
29
|
+
statusCode = error.statusCode || 500;
|
|
30
|
+
details = error.details;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Ensure there's always a message
|
|
34
|
+
const message = error.message || "An unexpected error occurred";
|
|
35
|
+
|
|
36
|
+
reply.status(statusCode).send({
|
|
37
|
+
success: false,
|
|
38
|
+
message,
|
|
39
|
+
...(details ? { details } : {}),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Log the error for debugging
|
|
43
|
+
console.error(`[API Error] ${statusCode}: ${message}`, details || "");
|
|
44
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import { db } from "../lib/db";
|
|
3
|
+
import { stores } from "../schemas/store/store-schema";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a subdomain is available.
|
|
7
|
+
* @param subdomain The subdomain to check.
|
|
8
|
+
* @returns {Promise<boolean>} True if available, false if taken.
|
|
9
|
+
*/
|
|
10
|
+
export const isSubdomainAvailable = async (
|
|
11
|
+
subdomain: string,
|
|
12
|
+
): Promise<boolean> => {
|
|
13
|
+
const existingStore = await db
|
|
14
|
+
.select()
|
|
15
|
+
.from(stores)
|
|
16
|
+
.where(eq(stores.subdomain, subdomain))
|
|
17
|
+
.limit(1);
|
|
18
|
+
return existingStore.length === 0;
|
|
19
|
+
};
|