@axova/shared 1.0.2 → 1.1.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 (68) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +2 -0
  3. package/dist/lib/db.d.ts +34406 -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 +6 -6
  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 +8 -8
  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 +102 -102
  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 +20 -20
  24. package/dist/schemas/store/store-schema.d.ts +182 -2
  25. package/dist/schemas/store/store-schema.js +19 -0
  26. package/dist/schemas/store/storefront-config-schema.d.ts +434 -823
  27. package/dist/schemas/store/storefront-config-schema.js +35 -62
  28. package/dist/utils/subdomain.d.ts +1 -1
  29. package/dist/utils/subdomain.js +10 -15
  30. package/package.json +1 -1
  31. package/src/configs/index.ts +654 -654
  32. package/src/index.ts +26 -23
  33. package/src/interfaces/customer-events.ts +106 -106
  34. package/src/interfaces/inventory-events.ts +545 -545
  35. package/src/interfaces/inventory-types.ts +1004 -1004
  36. package/src/interfaces/order-events.ts +381 -381
  37. package/src/lib/auditLogger.ts +1117 -1117
  38. package/src/lib/authOrganization.ts +153 -153
  39. package/src/lib/db.ts +84 -64
  40. package/src/middleware/serviceAuth.ts +328 -328
  41. package/src/middleware/storeOwnership.ts +199 -181
  42. package/src/middleware/storeValidationMiddleware.ts +17 -50
  43. package/src/middleware/userAuth.ts +248 -248
  44. package/src/schemas/admin/admin-schema.ts +208 -208
  45. package/src/schemas/ai-moderation/ai-moderation-schema.ts +180 -180
  46. package/src/schemas/common/common-schemas.ts +108 -108
  47. package/src/schemas/compliance/compliance-schema.ts +927 -0
  48. package/src/schemas/compliance/kyc-schema.ts +649 -0
  49. package/src/schemas/customer/customer-schema.ts +576 -0
  50. package/src/schemas/index.ts +202 -3
  51. package/src/schemas/inventory/inventory-tables.ts +1927 -0
  52. package/src/schemas/inventory/lot-tables.ts +799 -0
  53. package/src/schemas/order/cart-schema.ts +652 -0
  54. package/src/schemas/order/order-schema.ts +1406 -0
  55. package/src/schemas/product/discount-relations.ts +44 -0
  56. package/src/schemas/product/discount-schema.ts +464 -0
  57. package/src/schemas/product/product-relations.ts +187 -0
  58. package/src/schemas/product/product-schema.ts +955 -0
  59. package/src/schemas/store/ethiopian_business_api.md.resolved +212 -0
  60. package/src/schemas/store/store-audit-schema.ts +1257 -0
  61. package/src/schemas/store/store-schema.ts +682 -0
  62. package/src/schemas/store/store-settings-schema.ts +231 -0
  63. package/src/schemas/store/storefront-config-schema.ts +382 -0
  64. package/src/schemas/types.ts +67 -67
  65. package/src/types/events.ts +646 -646
  66. package/src/utils/errorHandler.ts +44 -44
  67. package/src/utils/subdomain.ts +19 -23
  68. 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
+ }