@teincfood/core 0.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.
- package/README.md +44 -0
- package/dist/adapters/auth.d.ts +13 -0
- package/dist/adapters/auth.js +14 -0
- package/dist/adapters/business.d.ts +13 -0
- package/dist/adapters/business.js +14 -0
- package/dist/adapters/connectivity.d.ts +17 -0
- package/dist/adapters/connectivity.js +38 -0
- package/dist/adapters/devices.d.ts +5 -0
- package/dist/adapters/devices.js +14 -0
- package/dist/adapters/http.d.ts +30 -0
- package/dist/adapters/http.js +37 -0
- package/dist/adapters/image-cache.d.ts +8 -0
- package/dist/adapters/image-cache.js +12 -0
- package/dist/adapters/kv-types.d.ts +5 -0
- package/dist/adapters/kv-types.js +2 -0
- package/dist/adapters/kv.d.ts +20 -0
- package/dist/adapters/kv.js +81 -0
- package/dist/adapters/local-node.d.ts +34 -0
- package/dist/adapters/local-node.js +40 -0
- package/dist/adapters/pending-orders.d.ts +17 -0
- package/dist/adapters/pending-orders.js +31 -0
- package/dist/adapters/query-keys.d.ts +17 -0
- package/dist/adapters/query-keys.js +20 -0
- package/dist/adapters/services.d.ts +62 -0
- package/dist/adapters/services.js +95 -0
- package/dist/adapters/sqlite.d.ts +20 -0
- package/dist/adapters/sqlite.js +23 -0
- package/dist/db/connection.d.ts +8 -0
- package/dist/db/connection.js +87 -0
- package/dist/db/migrations.d.ts +9 -0
- package/dist/db/migrations.js +106 -0
- package/dist/db/operations.d.ts +45 -0
- package/dist/db/operations.js +192 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +118 -0
- package/dist/reference/api.d.ts +10 -0
- package/dist/reference/api.js +24 -0
- package/dist/reference/events.d.ts +54 -0
- package/dist/reference/events.js +144 -0
- package/dist/reference/operations.d.ts +11 -0
- package/dist/reference/operations.js +46 -0
- package/dist/reference/service.d.ts +27 -0
- package/dist/reference/service.js +270 -0
- package/dist/reference/types.d.ts +47 -0
- package/dist/reference/types.js +12 -0
- package/dist/repositories/order.repository.d.ts +44 -0
- package/dist/repositories/order.repository.js +132 -0
- package/dist/repositories/pos.repository.d.ts +20 -0
- package/dist/repositories/pos.repository.js +28 -0
- package/dist/sync/command-builder.d.ts +17 -0
- package/dist/sync/command-builder.js +30 -0
- package/dist/sync/command-queue.service.d.ts +41 -0
- package/dist/sync/command-queue.service.js +253 -0
- package/dist/sync/engine.d.ts +53 -0
- package/dist/sync/engine.js +216 -0
- package/dist/sync/order-number.d.ts +20 -0
- package/dist/sync/order-number.js +58 -0
- package/dist/sync/order-snapshots.service.d.ts +46 -0
- package/dist/sync/order-snapshots.service.js +151 -0
- package/dist/sync/pending-orders.service.d.ts +45 -0
- package/dist/sync/pending-orders.service.js +163 -0
- package/dist/sync/transport-local-node.d.ts +14 -0
- package/dist/sync/transport-local-node.js +67 -0
- package/dist/sync/transport-rest.d.ts +17 -0
- package/dist/sync/transport-rest.js +112 -0
- package/dist/sync/types.d.ts +102 -0
- package/dist/sync/types.js +13 -0
- package/dist/sync/use-sync-reconciliation.d.ts +10 -0
- package/dist/sync/use-sync-reconciliation.js +106 -0
- package/dist/types/api/auth.api.d.ts +61 -0
- package/dist/types/api/auth.api.js +3 -0
- package/dist/types/api/business.api.d.ts +137 -0
- package/dist/types/api/business.api.js +3 -0
- package/dist/types/api/conversation.api.d.ts +46 -0
- package/dist/types/api/conversation.api.js +2 -0
- package/dist/types/api/error.api.d.ts +8 -0
- package/dist/types/api/error.api.js +2 -0
- package/dist/types/api/fleet.api.d.ts +98 -0
- package/dist/types/api/fleet.api.js +3 -0
- package/dist/types/api/index.d.ts +11 -0
- package/dist/types/api/index.js +27 -0
- package/dist/types/api/kiosk.api.d.ts +4 -0
- package/dist/types/api/kiosk.api.js +2 -0
- package/dist/types/api/menu.api.d.ts +90 -0
- package/dist/types/api/menu.api.js +2 -0
- package/dist/types/api/pagination.d.ts +10 -0
- package/dist/types/api/pagination.js +2 -0
- package/dist/types/api/rider.api.d.ts +179 -0
- package/dist/types/api/rider.api.js +2 -0
- package/dist/types/api/seller.api.d.ts +164 -0
- package/dist/types/api/seller.api.js +2 -0
- package/dist/types/api/wallet.api.d.ts +27 -0
- package/dist/types/api/wallet.api.js +2 -0
- package/dist/types/pos.types.d.ts +33 -0
- package/dist/types/pos.types.js +5 -0
- package/dist/utils/constants.d.ts +85 -0
- package/dist/utils/constants.js +72 -0
- package/dist/utils/copyToClipBoard.d.ts +5 -0
- package/dist/utils/copyToClipBoard.js +23 -0
- package/dist/utils/currency.d.ts +9 -0
- package/dist/utils/currency.js +37 -0
- package/dist/utils/error.d.ts +4 -0
- package/dist/utils/error.js +73 -0
- package/dist/utils/formatCurrency.d.ts +4 -0
- package/dist/utils/formatCurrency.js +16 -0
- package/dist/utils/formatDate.d.ts +8 -0
- package/dist/utils/formatDate.js +42 -0
- package/dist/utils/phone.d.ts +10 -0
- package/dist/utils/phone.js +71 -0
- package/dist/utils/responsive.d.ts +13 -0
- package/dist/utils/responsive.js +21 -0
- package/dist/utils/storage.d.ts +15 -0
- package/dist/utils/storage.js +60 -0
- package/dist/utils/sync-logger.d.ts +22 -0
- package/dist/utils/sync-logger.js +79 -0
- package/dist/utils/uuid.d.ts +7 -0
- package/dist/utils/uuid.js +47 -0
- package/dist/utils/validation.d.ts +31 -0
- package/dist/utils/validation.js +170 -0
- package/package.json +49 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validation Utilities
|
|
4
|
+
* Provides schema validation for REST/WS/SSE/push payloads
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.validation = void 0;
|
|
8
|
+
exports.validateEmail = validateEmail;
|
|
9
|
+
exports.validatePhone = validatePhone;
|
|
10
|
+
exports.validateUsername = validateUsername;
|
|
11
|
+
exports.validatePassword = validatePassword;
|
|
12
|
+
exports.validateOrderPayload = validateOrderPayload;
|
|
13
|
+
exports.validateChatMessage = validateChatMessage;
|
|
14
|
+
exports.validateEventEnvelope = validateEventEnvelope;
|
|
15
|
+
exports.validatePromoCode = validatePromoCode;
|
|
16
|
+
exports.validateAddress = validateAddress;
|
|
17
|
+
exports.validatePaymentMethod = validatePaymentMethod;
|
|
18
|
+
function validateEmail(email) {
|
|
19
|
+
const errors = [];
|
|
20
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
21
|
+
if (!email) {
|
|
22
|
+
errors.push('Email is required');
|
|
23
|
+
}
|
|
24
|
+
else if (!emailRegex.test(email)) {
|
|
25
|
+
errors.push('Invalid email format');
|
|
26
|
+
}
|
|
27
|
+
return { valid: errors.length === 0, errors };
|
|
28
|
+
}
|
|
29
|
+
function validatePhone(phone) {
|
|
30
|
+
const errors = [];
|
|
31
|
+
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
|
|
32
|
+
if (!phone) {
|
|
33
|
+
errors.push('Phone number is required');
|
|
34
|
+
}
|
|
35
|
+
else if (!phoneRegex.test(phone.replace(/\s/g, ''))) {
|
|
36
|
+
errors.push('Invalid phone number format');
|
|
37
|
+
}
|
|
38
|
+
return { valid: errors.length === 0, errors };
|
|
39
|
+
}
|
|
40
|
+
function validateUsername(username) {
|
|
41
|
+
const errors = [];
|
|
42
|
+
const usernameRegex = /^[a-zA-Z0-9_]{3,20}$/;
|
|
43
|
+
if (!username) {
|
|
44
|
+
errors.push('Username is required');
|
|
45
|
+
}
|
|
46
|
+
else if (!usernameRegex.test(username)) {
|
|
47
|
+
errors.push('Username must be 3-20 characters and contain only letters, numbers, and underscores');
|
|
48
|
+
}
|
|
49
|
+
return { valid: errors.length === 0, errors };
|
|
50
|
+
}
|
|
51
|
+
function validatePassword(password) {
|
|
52
|
+
const errors = [];
|
|
53
|
+
if (!password) {
|
|
54
|
+
errors.push('Password is required');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
if (password.length < 8) {
|
|
58
|
+
errors.push('Password must be at least 8 characters');
|
|
59
|
+
}
|
|
60
|
+
if (!/[A-Z]/.test(password)) {
|
|
61
|
+
errors.push('Password must contain at least one uppercase letter');
|
|
62
|
+
}
|
|
63
|
+
if (!/[a-z]/.test(password)) {
|
|
64
|
+
errors.push('Password must contain at least one lowercase letter');
|
|
65
|
+
}
|
|
66
|
+
if (!/[0-9]/.test(password)) {
|
|
67
|
+
errors.push('Password must contain at least one number');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { valid: errors.length === 0, errors };
|
|
71
|
+
}
|
|
72
|
+
function validateOrderPayload(payload) {
|
|
73
|
+
const errors = [];
|
|
74
|
+
if (!payload || typeof payload !== 'object') {
|
|
75
|
+
errors.push('Order payload must be an object');
|
|
76
|
+
return { valid: false, errors };
|
|
77
|
+
}
|
|
78
|
+
const order = payload;
|
|
79
|
+
if (!order.id || typeof order.id !== 'string') {
|
|
80
|
+
errors.push('Order ID is required');
|
|
81
|
+
}
|
|
82
|
+
if (!order.items || !Array.isArray(order.items)) {
|
|
83
|
+
errors.push('Order items must be an array');
|
|
84
|
+
}
|
|
85
|
+
if (typeof order.total !== 'number' || order.total < 0) {
|
|
86
|
+
errors.push('Order total must be a non-negative number');
|
|
87
|
+
}
|
|
88
|
+
return { valid: errors.length === 0, errors };
|
|
89
|
+
}
|
|
90
|
+
function validateChatMessage(payload) {
|
|
91
|
+
const errors = [];
|
|
92
|
+
if (!payload || typeof payload !== 'object') {
|
|
93
|
+
errors.push('Chat message payload must be an object');
|
|
94
|
+
return { valid: false, errors };
|
|
95
|
+
}
|
|
96
|
+
const message = payload;
|
|
97
|
+
if (!message.messageId || typeof message.messageId !== 'string') {
|
|
98
|
+
errors.push('Message ID is required');
|
|
99
|
+
}
|
|
100
|
+
if (!message.chatId || typeof message.chatId !== 'string') {
|
|
101
|
+
errors.push('Chat ID is required');
|
|
102
|
+
}
|
|
103
|
+
if (!message.text || typeof message.text !== 'string') {
|
|
104
|
+
errors.push('Message text is required');
|
|
105
|
+
}
|
|
106
|
+
return { valid: errors.length === 0, errors };
|
|
107
|
+
}
|
|
108
|
+
function validateEventEnvelope(payload) {
|
|
109
|
+
const errors = [];
|
|
110
|
+
if (!payload || typeof payload !== 'object') {
|
|
111
|
+
errors.push('Event envelope must be an object');
|
|
112
|
+
return { valid: false, errors };
|
|
113
|
+
}
|
|
114
|
+
const event = payload;
|
|
115
|
+
if (!event.eventId || typeof event.eventId !== 'string') {
|
|
116
|
+
errors.push('Event ID is required');
|
|
117
|
+
}
|
|
118
|
+
if (!event.type || typeof event.type !== 'string') {
|
|
119
|
+
errors.push('Event type is required');
|
|
120
|
+
}
|
|
121
|
+
if (!event.occurredAt || typeof event.occurredAt !== 'string') {
|
|
122
|
+
errors.push('Event timestamp is required');
|
|
123
|
+
}
|
|
124
|
+
if (typeof event.sequence !== 'number') {
|
|
125
|
+
errors.push('Event sequence must be a number');
|
|
126
|
+
}
|
|
127
|
+
return { valid: errors.length === 0, errors };
|
|
128
|
+
}
|
|
129
|
+
function validatePromoCode(code) {
|
|
130
|
+
const errors = [];
|
|
131
|
+
const promoRegex = /^[A-Z0-9]{3,20}$/;
|
|
132
|
+
if (!code) {
|
|
133
|
+
errors.push('Promo code is required');
|
|
134
|
+
}
|
|
135
|
+
else if (!promoRegex.test(code.toUpperCase())) {
|
|
136
|
+
errors.push('Promo code must be 3-20 uppercase letters or numbers');
|
|
137
|
+
}
|
|
138
|
+
return { valid: errors.length === 0, errors };
|
|
139
|
+
}
|
|
140
|
+
function validateAddress(address) {
|
|
141
|
+
const errors = [];
|
|
142
|
+
if (!address.street || typeof address.street !== 'string') {
|
|
143
|
+
errors.push('Street address is required');
|
|
144
|
+
}
|
|
145
|
+
if (!address.city || typeof address.city !== 'string') {
|
|
146
|
+
errors.push('City is required');
|
|
147
|
+
}
|
|
148
|
+
if (!address.label || typeof address.label !== 'string') {
|
|
149
|
+
errors.push('Address label is required');
|
|
150
|
+
}
|
|
151
|
+
return { valid: errors.length === 0, errors };
|
|
152
|
+
}
|
|
153
|
+
function validatePaymentMethod(payment) {
|
|
154
|
+
const errors = [];
|
|
155
|
+
if (!payment.type || !['card', 'mobile_money'].includes(payment.type)) {
|
|
156
|
+
errors.push('Payment type must be card or mobile_money');
|
|
157
|
+
}
|
|
158
|
+
if (!payment.last4 || typeof payment.last4 !== 'string') {
|
|
159
|
+
errors.push('Payment last4 digits are required');
|
|
160
|
+
}
|
|
161
|
+
return { valid: errors.length === 0, errors };
|
|
162
|
+
}
|
|
163
|
+
// ─── Convenience object for screen-level validation ───
|
|
164
|
+
exports.validation = {
|
|
165
|
+
isNotEmpty: (value) => value.trim().length > 0,
|
|
166
|
+
isValid: (value, validator) => validator(value).valid,
|
|
167
|
+
email: Object.assign((v) => validateEmail(v), { message: "Invalid email format" }),
|
|
168
|
+
phone: Object.assign((v) => validatePhone(v), { message: "Invalid phone number format" }),
|
|
169
|
+
password: Object.assign((v) => validatePassword(v), { message: "Password must be at least 8 characters" }),
|
|
170
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@teincfood/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TeincFood shared offline-first core — types, sync engine, local DB, reference data, and repositories for mobile + desktop",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@tanstack/react-query": "^5.0.0",
|
|
19
|
+
"axios": "^1.0.0",
|
|
20
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
21
|
+
"zustand": "^5.0.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependenciesMeta": {
|
|
24
|
+
"react": {
|
|
25
|
+
"optional": true
|
|
26
|
+
},
|
|
27
|
+
"@tanstack/react-query": {
|
|
28
|
+
"optional": true
|
|
29
|
+
},
|
|
30
|
+
"zustand": {
|
|
31
|
+
"optional": true
|
|
32
|
+
},
|
|
33
|
+
"axios": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@tanstack/react-query": "^5.102.2",
|
|
39
|
+
"@types/node": "^26.2.0",
|
|
40
|
+
"@types/react": "^19.2.18",
|
|
41
|
+
"react": "^19.2.8",
|
|
42
|
+
"typescript": "^7.0.2",
|
|
43
|
+
"vitest": "^3.1.0"
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
}
|
|
49
|
+
}
|