@axova/shared 1.0.2 → 1.0.9

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 (66) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +2 -0
  3. package/dist/lib/db.d.ts +34226 -1
  4. package/dist/lib/db.js +21 -1
  5. package/dist/middleware/storeOwnership.js +22 -3
  6. package/dist/middleware/storeValidationMiddleware.js +16 -39
  7. package/dist/schemas/admin/admin-schema.d.ts +2 -2
  8. package/dist/schemas/ai-moderation/ai-moderation-schema.d.ts +8 -8
  9. package/dist/schemas/common/common-schemas.d.ts +71 -71
  10. package/dist/schemas/compliance/compliance-schema.d.ts +20 -20
  11. package/dist/schemas/compliance/kyc-schema.d.ts +6 -6
  12. package/dist/schemas/customer/customer-schema.d.ts +18 -18
  13. package/dist/schemas/index.d.ts +28 -0
  14. package/dist/schemas/index.js +134 -3
  15. package/dist/schemas/inventory/inventory-tables.d.ts +188 -188
  16. package/dist/schemas/inventory/lot-tables.d.ts +104 -104
  17. package/dist/schemas/order/cart-schema.d.ts +2865 -0
  18. package/dist/schemas/order/cart-schema.js +396 -0
  19. package/dist/schemas/order/order-schema.d.ts +19 -19
  20. package/dist/schemas/order/order-schema.js +8 -2
  21. package/dist/schemas/product/discount-schema.d.ts +3 -3
  22. package/dist/schemas/product/product-schema.d.ts +3 -3
  23. package/dist/schemas/store/store-audit-schema.d.ts +22 -22
  24. package/dist/schemas/store/storefront-config-schema.d.ts +434 -823
  25. package/dist/schemas/store/storefront-config-schema.js +35 -62
  26. package/dist/utils/subdomain.d.ts +1 -1
  27. package/dist/utils/subdomain.js +10 -15
  28. package/package.json +1 -1
  29. package/src/configs/index.ts +654 -654
  30. package/src/index.ts +26 -23
  31. package/src/interfaces/customer-events.ts +106 -106
  32. package/src/interfaces/inventory-events.ts +545 -545
  33. package/src/interfaces/inventory-types.ts +1004 -1004
  34. package/src/interfaces/order-events.ts +381 -381
  35. package/src/lib/auditLogger.ts +1117 -1117
  36. package/src/lib/authOrganization.ts +153 -153
  37. package/src/lib/db.ts +84 -64
  38. package/src/middleware/serviceAuth.ts +328 -328
  39. package/src/middleware/storeOwnership.ts +199 -181
  40. package/src/middleware/storeValidationMiddleware.ts +17 -50
  41. package/src/middleware/userAuth.ts +248 -248
  42. package/src/schemas/admin/admin-schema.ts +208 -208
  43. package/src/schemas/ai-moderation/ai-moderation-schema.ts +180 -180
  44. package/src/schemas/common/common-schemas.ts +108 -108
  45. package/src/schemas/compliance/compliance-schema.ts +927 -0
  46. package/src/schemas/compliance/kyc-schema.ts +649 -0
  47. package/src/schemas/customer/customer-schema.ts +576 -0
  48. package/src/schemas/index.ts +202 -3
  49. package/src/schemas/inventory/inventory-tables.ts +1927 -0
  50. package/src/schemas/inventory/lot-tables.ts +799 -0
  51. package/src/schemas/order/cart-schema.ts +652 -0
  52. package/src/schemas/order/order-schema.ts +1406 -0
  53. package/src/schemas/product/discount-relations.ts +44 -0
  54. package/src/schemas/product/discount-schema.ts +464 -0
  55. package/src/schemas/product/product-relations.ts +187 -0
  56. package/src/schemas/product/product-schema.ts +955 -0
  57. package/src/schemas/store/ethiopian_business_api.md.resolved +212 -0
  58. package/src/schemas/store/store-audit-schema.ts +1257 -0
  59. package/src/schemas/store/store-schema.ts +661 -0
  60. package/src/schemas/store/store-settings-schema.ts +231 -0
  61. package/src/schemas/store/storefront-config-schema.ts +382 -0
  62. package/src/schemas/types.ts +67 -67
  63. package/src/types/events.ts +646 -646
  64. package/src/utils/errorHandler.ts +44 -44
  65. package/src/utils/subdomain.ts +19 -23
  66. package/tsconfig.json +21 -21
@@ -1,248 +1,248 @@
1
- import { createAuthMiddleware } from "better-middleware";
2
- import type { FastifyPluginAsync, FastifyReply, FastifyRequest } from "fastify";
3
- import fp from "fastify-plugin";
4
-
5
- // Standardized user context aligned with existing request augmentation in this package
6
- export interface SharedUserContext {
7
- userId: string;
8
- storeId: string;
9
- role: string;
10
- permissions: string[];
11
- organizationId?: string;
12
- activeOrganizationId?: string;
13
- iat?: number;
14
- exp?: number;
15
- }
16
-
17
- // Optional role → permission mapping (used for helpers)
18
- export const DEFAULT_ROLE_PERMISSIONS: Record<string, string[]> = {
19
- SUPER_ADMIN: ["*"],
20
- STORE_ADMIN: [
21
- "store:read",
22
- "store:write",
23
- "store:delete",
24
- "orders:read",
25
- "orders:write",
26
- "products:read",
27
- "products:write",
28
- ],
29
- STORE_MANAGER: [
30
- "store:read",
31
- "store:write",
32
- "orders:read",
33
- "orders:write",
34
- "products:read",
35
- "products:write",
36
- ],
37
- STORE_EMPLOYEE: ["store:read", "orders:read", "products:read"],
38
- USER: ["store:read"],
39
- };
40
-
41
- // Core adapter of better-middleware to Fastify
42
- function createFastifyAuthHandler() {
43
- const auth = createAuthMiddleware<FastifyRequest>({
44
- baseURL: process.env.NEXT_PUBLIC_AUTH_URL || "http://localhost:4000",
45
- cache: { enabled: true, ttl: 300, max: 1000 },
46
- onError: async () => ({
47
- status: 401,
48
- body: {
49
- success: false,
50
- error: "Authentication required",
51
- code: "UNAUTHORIZED",
52
- },
53
- }),
54
- logger: {
55
- info: (m, d) =>
56
- process.env.NODE_ENV === "development"
57
- ? console.log(`[Auth] ${m}`, d)
58
- : undefined,
59
- error: (m, d) => console.error(`[Auth] ${m}`, d),
60
- debug: (m, d) =>
61
- process.env.NODE_ENV === "development"
62
- ? console.debug(`[Auth] ${m}`, d)
63
- : undefined,
64
- },
65
- framework: {
66
- getHeaders: (request: any) => {
67
- const headers: Record<string, string> = {};
68
- Object.entries(request.headers || {}).forEach(([k, v]) => {
69
- if (typeof v === "string") headers[k] = v;
70
- else if (Array.isArray(v)) headers[k] = v.join(", ");
71
- });
72
- const hasCookie = (headers["cookie"] || "").includes(
73
- "better-auth.session_token=",
74
- );
75
- const bearer = headers["authorization"]?.startsWith("Bearer ")
76
- ? headers["authorization"].substring(7)
77
- : undefined;
78
- if (!hasCookie && bearer) {
79
- headers["cookie"] =
80
- `${headers["cookie"] ? headers["cookie"] + "; " : ""}better-auth.session_token=${bearer}`;
81
- }
82
- return headers;
83
- },
84
- getCookies: (request: any) => {
85
- const cookies = request.cookies || {};
86
- if (
87
- !cookies["better-auth.session_token"] &&
88
- request.headers.authorization?.startsWith("Bearer ")
89
- ) {
90
- cookies["better-auth.session_token"] =
91
- request.headers.authorization.substring(7);
92
- }
93
- return cookies;
94
- },
95
- setContext: (request: any, key: "user" | "session", value: any) => {
96
- if (key === "user" && value) {
97
- const u = value as any;
98
- request.user = {
99
- userId: u.id,
100
- storeId: u.activeOrganizationId || u.organizationId || "",
101
- role: u.role || "USER",
102
- permissions: DEFAULT_ROLE_PERMISSIONS[u.role || "USER"] || [],
103
- organizationId: u.organizationId,
104
- activeOrganizationId: u.activeOrganizationId,
105
- iat: u.iat,
106
- exp: u.exp,
107
- } satisfies SharedUserContext;
108
- } else if (key === "session" && value) {
109
- const s = value as any;
110
- if (request.user && !request.user.storeId)
111
- request.user.storeId =
112
- s.activeOrganizationId || request.user.storeId;
113
- }
114
- },
115
- createResponse: (_request: any, body: unknown, status: number) => ({
116
- status,
117
- body,
118
- }),
119
- },
120
- });
121
- return auth;
122
- }
123
-
124
- // Pre-handler that runs authentication; emits response when not authorized
125
- export const AuthPreHandler = async (
126
- request: FastifyRequest,
127
- reply: FastifyReply,
128
- ) => {
129
- const auth = createFastifyAuthHandler();
130
- const result = await auth(request, request, async () => {});
131
- if (result) {
132
- reply.code(result.status).send(result.body);
133
- }
134
- };
135
-
136
- // Fastify plugin for easy registration
137
- export const fastifyUserAuthPlugin: FastifyPluginAsync = fp(
138
- async (fastify: any) => {
139
- fastify.addHook("preHandler", AuthPreHandler as any);
140
- },
141
- );
142
-
143
- // ---------- Helper utilities ----------
144
- export function getAuthTokenFromRequest(
145
- request: FastifyRequest,
146
- ): string | undefined {
147
- const cookies = (request as any).cookies || {};
148
- const tokenFromCookie = cookies["better-auth.session_token"] as
149
- | string
150
- | undefined;
151
- if (tokenFromCookie) return tokenFromCookie;
152
- const cookieHeader = request.headers.cookie;
153
- if (cookieHeader) {
154
- const match = cookieHeader.match(/better-auth\.session_token=([^;]+)/);
155
- if (match) return match[1];
156
- }
157
- const authHeader = request.headers.authorization;
158
- if (authHeader?.startsWith("Bearer ")) return authHeader.substring(7);
159
- return undefined;
160
- }
161
-
162
- export function getAuthHeadersFromRequest(
163
- request: FastifyRequest,
164
- ): Record<string, string> {
165
- const headers: Record<string, string> = {
166
- "Content-Type": "application/json",
167
- };
168
- const token = getAuthTokenFromRequest(request);
169
- if (token) {
170
- headers["Cookie"] = `better-auth.session_token=${token}`;
171
- headers["Authorization"] = `Bearer ${token}`;
172
- }
173
- return headers;
174
- }
175
-
176
- export function getUserDataFromRequest(request: FastifyRequest): {
177
- userId: string;
178
- organizationId?: string;
179
- role?: string;
180
- permissions?: string[];
181
- } | null {
182
- const user = (request as any).user as SharedUserContext | undefined;
183
- if (user) {
184
- return {
185
- userId: user.userId,
186
- organizationId: user.storeId || user.organizationId,
187
- role: user.role,
188
- permissions: user.permissions,
189
- };
190
- }
191
-
192
- const userIdFromHeader = request.headers["x-user-id"] as string | undefined;
193
- const storeIdFromHeader = request.headers["x-store-id"] as string | undefined;
194
- const roleFromHeader = request.headers["x-user-role"] as string | undefined;
195
- if (userIdFromHeader) {
196
- return {
197
- userId: userIdFromHeader,
198
- organizationId: storeIdFromHeader,
199
- role: roleFromHeader || "USER",
200
- permissions: DEFAULT_ROLE_PERMISSIONS[roleFromHeader || "USER"] || [],
201
- };
202
- }
203
- return null;
204
- }
205
-
206
- export function getUserIdFromRequest(request: FastifyRequest): string | null {
207
- return getUserDataFromRequest(request)?.userId || null;
208
- }
209
-
210
- export function hasPermission(
211
- request: FastifyRequest,
212
- permission: string,
213
- ): boolean {
214
- const user = (request as any).user as SharedUserContext | undefined;
215
- const perms = user?.permissions || [];
216
- return perms.includes("*") || perms.includes(permission);
217
- }
218
-
219
- export function hasRole(request: FastifyRequest, role: string): boolean {
220
- const user = (request as any).user as SharedUserContext | undefined;
221
- return (user?.role || "").toUpperCase() === role.toUpperCase();
222
- }
223
-
224
- export function requirePermission(permission: string) {
225
- return async (request: FastifyRequest, reply: FastifyReply) => {
226
- if (!hasPermission(request, permission)) {
227
- reply.code(403).send({
228
- success: false,
229
- error: "Insufficient permissions",
230
- message: `Required permission: ${permission}`,
231
- code: "FORBIDDEN",
232
- });
233
- }
234
- };
235
- }
236
-
237
- export function requireRole(role: string) {
238
- return async (request: FastifyRequest, reply: FastifyReply) => {
239
- if (!hasRole(request, role)) {
240
- reply.code(403).send({
241
- success: false,
242
- error: "Insufficient role",
243
- message: `Required role: ${role}`,
244
- code: "FORBIDDEN",
245
- });
246
- }
247
- };
248
- }
1
+ import { createAuthMiddleware } from "better-middleware";
2
+ import type { FastifyPluginAsync, FastifyReply, FastifyRequest } from "fastify";
3
+ import fp from "fastify-plugin";
4
+
5
+ // Standardized user context aligned with existing request augmentation in this package
6
+ export interface SharedUserContext {
7
+ userId: string;
8
+ storeId: string;
9
+ role: string;
10
+ permissions: string[];
11
+ organizationId?: string;
12
+ activeOrganizationId?: string;
13
+ iat?: number;
14
+ exp?: number;
15
+ }
16
+
17
+ // Optional role → permission mapping (used for helpers)
18
+ export const DEFAULT_ROLE_PERMISSIONS: Record<string, string[]> = {
19
+ SUPER_ADMIN: ["*"],
20
+ STORE_ADMIN: [
21
+ "store:read",
22
+ "store:write",
23
+ "store:delete",
24
+ "orders:read",
25
+ "orders:write",
26
+ "products:read",
27
+ "products:write",
28
+ ],
29
+ STORE_MANAGER: [
30
+ "store:read",
31
+ "store:write",
32
+ "orders:read",
33
+ "orders:write",
34
+ "products:read",
35
+ "products:write",
36
+ ],
37
+ STORE_EMPLOYEE: ["store:read", "orders:read", "products:read"],
38
+ USER: ["store:read"],
39
+ };
40
+
41
+ // Core adapter of better-middleware to Fastify
42
+ function createFastifyAuthHandler() {
43
+ const auth = createAuthMiddleware<FastifyRequest>({
44
+ baseURL: process.env.NEXT_PUBLIC_AUTH_URL || "http://localhost:4000",
45
+ cache: { enabled: true, ttl: 300, max: 1000 },
46
+ onError: async () => ({
47
+ status: 401,
48
+ body: {
49
+ success: false,
50
+ error: "Authentication required",
51
+ code: "UNAUTHORIZED",
52
+ },
53
+ }),
54
+ logger: {
55
+ info: (m, d) =>
56
+ process.env.NODE_ENV === "development"
57
+ ? console.log(`[Auth] ${m}`, d)
58
+ : undefined,
59
+ error: (m, d) => console.error(`[Auth] ${m}`, d),
60
+ debug: (m, d) =>
61
+ process.env.NODE_ENV === "development"
62
+ ? console.debug(`[Auth] ${m}`, d)
63
+ : undefined,
64
+ },
65
+ framework: {
66
+ getHeaders: (request: any) => {
67
+ const headers: Record<string, string> = {};
68
+ Object.entries(request.headers || {}).forEach(([k, v]) => {
69
+ if (typeof v === "string") headers[k] = v;
70
+ else if (Array.isArray(v)) headers[k] = v.join(", ");
71
+ });
72
+ const hasCookie = (headers["cookie"] || "").includes(
73
+ "better-auth.session_token=",
74
+ );
75
+ const bearer = headers["authorization"]?.startsWith("Bearer ")
76
+ ? headers["authorization"].substring(7)
77
+ : undefined;
78
+ if (!hasCookie && bearer) {
79
+ headers["cookie"] =
80
+ `${headers["cookie"] ? headers["cookie"] + "; " : ""}better-auth.session_token=${bearer}`;
81
+ }
82
+ return headers;
83
+ },
84
+ getCookies: (request: any) => {
85
+ const cookies = request.cookies || {};
86
+ if (
87
+ !cookies["better-auth.session_token"] &&
88
+ request.headers.authorization?.startsWith("Bearer ")
89
+ ) {
90
+ cookies["better-auth.session_token"] =
91
+ request.headers.authorization.substring(7);
92
+ }
93
+ return cookies;
94
+ },
95
+ setContext: (request: any, key: "user" | "session", value: any) => {
96
+ if (key === "user" && value) {
97
+ const u = value as any;
98
+ request.user = {
99
+ userId: u.id,
100
+ storeId: u.activeOrganizationId || u.organizationId || "",
101
+ role: u.role || "USER",
102
+ permissions: DEFAULT_ROLE_PERMISSIONS[u.role || "USER"] || [],
103
+ organizationId: u.organizationId,
104
+ activeOrganizationId: u.activeOrganizationId,
105
+ iat: u.iat,
106
+ exp: u.exp,
107
+ } satisfies SharedUserContext;
108
+ } else if (key === "session" && value) {
109
+ const s = value as any;
110
+ if (request.user && !request.user.storeId)
111
+ request.user.storeId =
112
+ s.activeOrganizationId || request.user.storeId;
113
+ }
114
+ },
115
+ createResponse: (_request: any, body: unknown, status: number) => ({
116
+ status,
117
+ body,
118
+ }),
119
+ },
120
+ });
121
+ return auth;
122
+ }
123
+
124
+ // Pre-handler that runs authentication; emits response when not authorized
125
+ export const AuthPreHandler = async (
126
+ request: FastifyRequest,
127
+ reply: FastifyReply,
128
+ ) => {
129
+ const auth = createFastifyAuthHandler();
130
+ const result = await auth(request, request, async () => {});
131
+ if (result) {
132
+ reply.code(result.status).send(result.body);
133
+ }
134
+ };
135
+
136
+ // Fastify plugin for easy registration
137
+ export const fastifyUserAuthPlugin: FastifyPluginAsync = fp(
138
+ async (fastify: any) => {
139
+ fastify.addHook("preHandler", AuthPreHandler as any);
140
+ },
141
+ );
142
+
143
+ // ---------- Helper utilities ----------
144
+ export function getAuthTokenFromRequest(
145
+ request: FastifyRequest,
146
+ ): string | undefined {
147
+ const cookies = (request as any).cookies || {};
148
+ const tokenFromCookie = cookies["better-auth.session_token"] as
149
+ | string
150
+ | undefined;
151
+ if (tokenFromCookie) return tokenFromCookie;
152
+ const cookieHeader = request.headers.cookie;
153
+ if (cookieHeader) {
154
+ const match = cookieHeader.match(/better-auth\.session_token=([^;]+)/);
155
+ if (match) return match[1];
156
+ }
157
+ const authHeader = request.headers.authorization;
158
+ if (authHeader?.startsWith("Bearer ")) return authHeader.substring(7);
159
+ return undefined;
160
+ }
161
+
162
+ export function getAuthHeadersFromRequest(
163
+ request: FastifyRequest,
164
+ ): Record<string, string> {
165
+ const headers: Record<string, string> = {
166
+ "Content-Type": "application/json",
167
+ };
168
+ const token = getAuthTokenFromRequest(request);
169
+ if (token) {
170
+ headers["Cookie"] = `better-auth.session_token=${token}`;
171
+ headers["Authorization"] = `Bearer ${token}`;
172
+ }
173
+ return headers;
174
+ }
175
+
176
+ export function getUserDataFromRequest(request: FastifyRequest): {
177
+ userId: string;
178
+ organizationId?: string;
179
+ role?: string;
180
+ permissions?: string[];
181
+ } | null {
182
+ const user = (request as any).user as SharedUserContext | undefined;
183
+ if (user) {
184
+ return {
185
+ userId: user.userId,
186
+ organizationId: user.storeId || user.organizationId,
187
+ role: user.role,
188
+ permissions: user.permissions,
189
+ };
190
+ }
191
+
192
+ const userIdFromHeader = request.headers["x-user-id"] as string | undefined;
193
+ const storeIdFromHeader = request.headers["x-store-id"] as string | undefined;
194
+ const roleFromHeader = request.headers["x-user-role"] as string | undefined;
195
+ if (userIdFromHeader) {
196
+ return {
197
+ userId: userIdFromHeader,
198
+ organizationId: storeIdFromHeader,
199
+ role: roleFromHeader || "USER",
200
+ permissions: DEFAULT_ROLE_PERMISSIONS[roleFromHeader || "USER"] || [],
201
+ };
202
+ }
203
+ return null;
204
+ }
205
+
206
+ export function getUserIdFromRequest(request: FastifyRequest): string | null {
207
+ return getUserDataFromRequest(request)?.userId || null;
208
+ }
209
+
210
+ export function hasPermission(
211
+ request: FastifyRequest,
212
+ permission: string,
213
+ ): boolean {
214
+ const user = (request as any).user as SharedUserContext | undefined;
215
+ const perms = user?.permissions || [];
216
+ return perms.includes("*") || perms.includes(permission);
217
+ }
218
+
219
+ export function hasRole(request: FastifyRequest, role: string): boolean {
220
+ const user = (request as any).user as SharedUserContext | undefined;
221
+ return (user?.role || "").toUpperCase() === role.toUpperCase();
222
+ }
223
+
224
+ export function requirePermission(permission: string) {
225
+ return async (request: FastifyRequest, reply: FastifyReply) => {
226
+ if (!hasPermission(request, permission)) {
227
+ reply.code(403).send({
228
+ success: false,
229
+ error: "Insufficient permissions",
230
+ message: `Required permission: ${permission}`,
231
+ code: "FORBIDDEN",
232
+ });
233
+ }
234
+ };
235
+ }
236
+
237
+ export function requireRole(role: string) {
238
+ return async (request: FastifyRequest, reply: FastifyReply) => {
239
+ if (!hasRole(request, role)) {
240
+ reply.code(403).send({
241
+ success: false,
242
+ error: "Insufficient role",
243
+ message: `Required role: ${role}`,
244
+ code: "FORBIDDEN",
245
+ });
246
+ }
247
+ };
248
+ }