@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.
Files changed (112) hide show
  1. package/CONFIGURATION_GUIDE.md +1 -0
  2. package/README.md +384 -0
  3. package/SCHEMA_ORGANIZATION.md +209 -0
  4. package/dist/configs/index.d.ts +85 -0
  5. package/dist/configs/index.js +555 -0
  6. package/dist/events/kafka.d.ts +40 -0
  7. package/dist/events/kafka.js +311 -0
  8. package/dist/index.d.ts +13 -0
  9. package/dist/index.js +41 -0
  10. package/dist/interfaces/customer-events.d.ts +85 -0
  11. package/dist/interfaces/customer-events.js +2 -0
  12. package/dist/interfaces/inventory-events.d.ts +453 -0
  13. package/dist/interfaces/inventory-events.js +3 -0
  14. package/dist/interfaces/inventory-types.d.ts +894 -0
  15. package/dist/interfaces/inventory-types.js +3 -0
  16. package/dist/interfaces/order-events.d.ts +320 -0
  17. package/dist/interfaces/order-events.js +3 -0
  18. package/dist/lib/auditLogger.d.ts +162 -0
  19. package/dist/lib/auditLogger.js +626 -0
  20. package/dist/lib/authOrganization.d.ts +24 -0
  21. package/dist/lib/authOrganization.js +110 -0
  22. package/dist/lib/db.d.ts +6 -0
  23. package/dist/lib/db.js +88 -0
  24. package/dist/middleware/serviceAuth.d.ts +60 -0
  25. package/dist/middleware/serviceAuth.js +272 -0
  26. package/dist/middleware/storeOwnership.d.ts +15 -0
  27. package/dist/middleware/storeOwnership.js +156 -0
  28. package/dist/middleware/storeValidationMiddleware.d.ts +44 -0
  29. package/dist/middleware/storeValidationMiddleware.js +180 -0
  30. package/dist/middleware/userAuth.d.ts +27 -0
  31. package/dist/middleware/userAuth.js +218 -0
  32. package/dist/schemas/admin/admin-schema.d.ts +741 -0
  33. package/dist/schemas/admin/admin-schema.js +111 -0
  34. package/dist/schemas/ai-moderation/ai-moderation-schema.d.ts +648 -0
  35. package/dist/schemas/ai-moderation/ai-moderation-schema.js +88 -0
  36. package/dist/schemas/common/common-schemas.d.ts +436 -0
  37. package/dist/schemas/common/common-schemas.js +94 -0
  38. package/dist/schemas/compliance/compliance-schema.d.ts +3388 -0
  39. package/dist/schemas/compliance/compliance-schema.js +472 -0
  40. package/dist/schemas/compliance/kyc-schema.d.ts +2642 -0
  41. package/dist/schemas/compliance/kyc-schema.js +361 -0
  42. package/dist/schemas/customer/customer-schema.d.ts +2727 -0
  43. package/dist/schemas/customer/customer-schema.js +399 -0
  44. package/dist/schemas/index.d.ts +27 -0
  45. package/dist/schemas/index.js +138 -0
  46. package/dist/schemas/inventory/inventory-tables.d.ts +9476 -0
  47. package/dist/schemas/inventory/inventory-tables.js +1470 -0
  48. package/dist/schemas/inventory/lot-tables.d.ts +3281 -0
  49. package/dist/schemas/inventory/lot-tables.js +608 -0
  50. package/dist/schemas/order/order-schema.d.ts +5825 -0
  51. package/dist/schemas/order/order-schema.js +954 -0
  52. package/dist/schemas/product/discount-relations.d.ts +15 -0
  53. package/dist/schemas/product/discount-relations.js +34 -0
  54. package/dist/schemas/product/discount-schema.d.ts +1975 -0
  55. package/dist/schemas/product/discount-schema.js +297 -0
  56. package/dist/schemas/product/product-relations.d.ts +41 -0
  57. package/dist/schemas/product/product-relations.js +133 -0
  58. package/dist/schemas/product/product-schema.d.ts +4544 -0
  59. package/dist/schemas/product/product-schema.js +671 -0
  60. package/dist/schemas/store/store-audit-schema.d.ts +4135 -0
  61. package/dist/schemas/store/store-audit-schema.js +556 -0
  62. package/dist/schemas/store/store-schema.d.ts +3100 -0
  63. package/dist/schemas/store/store-schema.js +381 -0
  64. package/dist/schemas/store/store-settings-schema.d.ts +665 -0
  65. package/dist/schemas/store/store-settings-schema.js +141 -0
  66. package/dist/schemas/types.d.ts +50 -0
  67. package/dist/schemas/types.js +3 -0
  68. package/dist/types/events.d.ts +2396 -0
  69. package/dist/types/events.js +505 -0
  70. package/dist/utils/errorHandler.d.ts +12 -0
  71. package/dist/utils/errorHandler.js +36 -0
  72. package/dist/utils/subdomain.d.ts +6 -0
  73. package/dist/utils/subdomain.js +20 -0
  74. package/nul +8 -0
  75. package/package.json +43 -0
  76. package/src/configs/index.ts +654 -0
  77. package/src/events/kafka.ts +429 -0
  78. package/src/index.ts +26 -0
  79. package/src/interfaces/customer-events.ts +106 -0
  80. package/src/interfaces/inventory-events.ts +545 -0
  81. package/src/interfaces/inventory-types.ts +1004 -0
  82. package/src/interfaces/order-events.ts +381 -0
  83. package/src/lib/auditLogger.ts +1117 -0
  84. package/src/lib/authOrganization.ts +153 -0
  85. package/src/lib/db.ts +64 -0
  86. package/src/middleware/serviceAuth.ts +328 -0
  87. package/src/middleware/storeOwnership.ts +199 -0
  88. package/src/middleware/storeValidationMiddleware.ts +247 -0
  89. package/src/middleware/userAuth.ts +248 -0
  90. package/src/schemas/admin/admin-schema.ts +208 -0
  91. package/src/schemas/ai-moderation/ai-moderation-schema.ts +180 -0
  92. package/src/schemas/common/common-schemas.ts +108 -0
  93. package/src/schemas/compliance/compliance-schema.ts +927 -0
  94. package/src/schemas/compliance/kyc-schema.ts +649 -0
  95. package/src/schemas/customer/customer-schema.ts +576 -0
  96. package/src/schemas/index.ts +189 -0
  97. package/src/schemas/inventory/inventory-tables.ts +1927 -0
  98. package/src/schemas/inventory/lot-tables.ts +799 -0
  99. package/src/schemas/order/order-schema.ts +1400 -0
  100. package/src/schemas/product/discount-relations.ts +44 -0
  101. package/src/schemas/product/discount-schema.ts +464 -0
  102. package/src/schemas/product/product-relations.ts +187 -0
  103. package/src/schemas/product/product-schema.ts +955 -0
  104. package/src/schemas/store/ethiopian_business_api.md.resolved +212 -0
  105. package/src/schemas/store/store-audit-schema.ts +1257 -0
  106. package/src/schemas/store/store-schema.ts +661 -0
  107. package/src/schemas/store/store-settings-schema.ts +231 -0
  108. package/src/schemas/types.ts +67 -0
  109. package/src/types/events.ts +646 -0
  110. package/src/utils/errorHandler.ts +44 -0
  111. package/src/utils/subdomain.ts +19 -0
  112. 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
+ };