lua-cli 2.1.0-alpha.6 → 2.2.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 +2 -2
- package/dist/commands/compile.js +58 -2
- package/dist/custom-data-api.d.ts +72 -0
- package/dist/custom-data-api.js +174 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/product-api.d.ts +142 -1
- package/dist/product-api.js +124 -10
- package/dist/services/api.d.ts +288 -5
- package/dist/services/api.js +322 -9
- package/dist/utils/files.js +2 -2
- package/dist/utils/sandbox.js +77 -2
- package/dist/web/app.css +505 -4
- package/dist/web/app.js +20 -20
- package/dist/web/index.html +2 -1
- package/package.json +5 -3
- package/template/lua.skill.yaml +8 -5
- package/template/package.json +2 -1
- package/template/src/index.ts +27 -2
- package/template/src/tools/CustomDataTool.ts +116 -0
- package/template/src/tools/ProductsTool.ts +126 -7
- package/template/package-lock.json +0 -1511
package/README.md
CHANGED
|
@@ -195,7 +195,7 @@ This command will:
|
|
|
195
195
|
- Available at `http://localhost:3000` (opens automatically)
|
|
196
196
|
- **Live Log Panel**:
|
|
197
197
|
- Real-time log feed showing execution details
|
|
198
|
-
- WebSocket connection to `wss://api.
|
|
198
|
+
- WebSocket connection to `wss://api.heylua.ai/feed`
|
|
199
199
|
- Console-style interface with color-coded log levels
|
|
200
200
|
- Shows tool calls, errors, metrics, and execution metadata
|
|
201
201
|
- Displays detailed information in expandable sections
|
|
@@ -498,7 +498,7 @@ For more details, see [USER_DATA_API.md](./USER_DATA_API.md).
|
|
|
498
498
|
|
|
499
499
|
For support and questions:
|
|
500
500
|
- Create an issue on [GitHub](https://github.com/lua-ai-global/lua-cli/issues)
|
|
501
|
-
- Contact: stefan@
|
|
501
|
+
- Contact: stefan@heylua.ai
|
|
502
502
|
|
|
503
503
|
## Changelog
|
|
504
504
|
|
package/dist/commands/compile.js
CHANGED
|
@@ -227,7 +227,7 @@ async function bundleTool(tool, distDir) {
|
|
|
227
227
|
platform: 'node',
|
|
228
228
|
target: 'node16',
|
|
229
229
|
outfile: outputPath,
|
|
230
|
-
external: ['lua-cli/skill', 'lua-cli/user-data-api', 'zod'], // Exclude lua-cli modules
|
|
230
|
+
external: ['lua-cli/skill', 'lua-cli/user-data-api', 'lua-cli/product-api', 'lua-cli/custom-data-api', 'zod', 'keytar', 'esbuild', 'commander', 'inquirer', 'node-fetch', 'ws', 'socket.io-client', 'ts-morph'], // Exclude lua-cli modules, zod, and native modules
|
|
231
231
|
minify: true, // Minify for smaller file sizes
|
|
232
232
|
sourcemap: false,
|
|
233
233
|
resolveExtensions: ['.ts', '.js', '.json'],
|
|
@@ -272,6 +272,56 @@ async function wrapToolForVM(outputPath, tool) {
|
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
};
|
|
275
|
+
|
|
276
|
+
// Mock lua-cli/product-api module
|
|
277
|
+
const luaCliProductApi = {
|
|
278
|
+
product: typeof product !== 'undefined' ? product : {
|
|
279
|
+
data: {
|
|
280
|
+
get: async (page = 1, limit = 10) => ({ success: true, data: [], pagination: { currentPage: page, totalPages: 1, totalCount: 0, limit, hasNextPage: false, hasPrevPage: false, nextPage: null, prevPage: null } }),
|
|
281
|
+
update: async (data, productId) => ({ updated: true, isNew: false, product: data }),
|
|
282
|
+
create: async (data) => ({ updated: false, isNew: true, product: data }),
|
|
283
|
+
delete: async (productId) => ({ deleted: true }),
|
|
284
|
+
search: async (searchQuery) => ({ success: true, message: \`Found 0 products for "\${searchQuery}"\`, data: [] })
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// Mock lua-cli/custom-data-api module
|
|
290
|
+
const luaCliCustomDataApi = {
|
|
291
|
+
customData: typeof customData !== 'undefined' ? customData : {
|
|
292
|
+
create: async (collectionName, data) => ({
|
|
293
|
+
id: 'mock-id-' + Date.now(),
|
|
294
|
+
data: data.data,
|
|
295
|
+
createdAt: Date.now(),
|
|
296
|
+
updatedAt: Date.now(),
|
|
297
|
+
searchText: data.searchText
|
|
298
|
+
}),
|
|
299
|
+
get: async (collectionName, filter, page = 1, limit = 10) => ({
|
|
300
|
+
data: [],
|
|
301
|
+
pagination: {
|
|
302
|
+
currentPage: page,
|
|
303
|
+
totalPages: 1,
|
|
304
|
+
totalCount: 0,
|
|
305
|
+
limit,
|
|
306
|
+
hasNextPage: false,
|
|
307
|
+
hasPrevPage: false
|
|
308
|
+
}
|
|
309
|
+
}),
|
|
310
|
+
getEntry: async (collectionName, entryId) => null,
|
|
311
|
+
update: async (collectionName, entryId, data) => ({
|
|
312
|
+
status: 'success',
|
|
313
|
+
message: 'Custom data entry updated'
|
|
314
|
+
}),
|
|
315
|
+
search: async (collectionName, searchText, limit = 10, scoreThreshold = 0.6) => ({
|
|
316
|
+
data: [],
|
|
317
|
+
count: 0
|
|
318
|
+
}),
|
|
319
|
+
delete: async (collectionName, entryId) => ({
|
|
320
|
+
status: 'success',
|
|
321
|
+
message: 'Custom data entry deleted'
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
};
|
|
275
325
|
|
|
276
326
|
// Mock zod module
|
|
277
327
|
const zodModule = (() => {
|
|
@@ -313,6 +363,12 @@ async function wrapToolForVM(outputPath, tool) {
|
|
|
313
363
|
if (id === 'lua-cli/user-data-api') {
|
|
314
364
|
return luaCliUserDataApi;
|
|
315
365
|
}
|
|
366
|
+
if (id === 'lua-cli/product-api') {
|
|
367
|
+
return luaCliProductApi;
|
|
368
|
+
}
|
|
369
|
+
if (id === 'lua-cli/custom-data-api') {
|
|
370
|
+
return luaCliCustomDataApi;
|
|
371
|
+
}
|
|
316
372
|
if (id === 'zod') {
|
|
317
373
|
return zodModule;
|
|
318
374
|
}
|
|
@@ -344,7 +400,7 @@ async function bundleMainIndex(indexPath, distDir) {
|
|
|
344
400
|
platform: 'node',
|
|
345
401
|
target: 'node16',
|
|
346
402
|
outfile: path.join(distDir, 'index.js'),
|
|
347
|
-
external: ['lua-cli/skill', 'lua-cli/user-data-api', 'zod'], // Exclude lua-cli modules and
|
|
403
|
+
external: ['lua-cli/skill', 'lua-cli/user-data-api', 'lua-cli/product-api', 'lua-cli/custom-data-api', 'zod', 'keytar', 'esbuild', 'commander', 'inquirer', 'node-fetch', 'ws', 'socket.io-client', 'ts-morph'], // Exclude lua-cli modules, zod, and native modules
|
|
348
404
|
minify: true, // Minify for smaller file sizes
|
|
349
405
|
sourcemap: false,
|
|
350
406
|
resolveExtensions: ['.ts', '.js', '.json'],
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface CustomDataEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
data: any;
|
|
4
|
+
createdAt: number;
|
|
5
|
+
updatedAt: number;
|
|
6
|
+
searchText?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CreateCustomDataRequest {
|
|
9
|
+
data: any;
|
|
10
|
+
searchText?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateCustomDataResponse {
|
|
13
|
+
id: string;
|
|
14
|
+
data: any;
|
|
15
|
+
createdAt: number;
|
|
16
|
+
updatedAt: number;
|
|
17
|
+
searchText?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface GetCustomDataResponse {
|
|
20
|
+
data: CustomDataEntry[];
|
|
21
|
+
pagination: {
|
|
22
|
+
currentPage: number;
|
|
23
|
+
totalPages: number;
|
|
24
|
+
totalCount: number;
|
|
25
|
+
limit: number;
|
|
26
|
+
hasNextPage: boolean;
|
|
27
|
+
hasPrevPage: boolean;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface UpdateCustomDataRequest {
|
|
31
|
+
data: any;
|
|
32
|
+
searchText?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface UpdateCustomDataResponse {
|
|
35
|
+
status: string;
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
export interface SearchCustomDataResponse {
|
|
39
|
+
data: Array<CustomDataEntry & {
|
|
40
|
+
score: number;
|
|
41
|
+
}>;
|
|
42
|
+
count: number;
|
|
43
|
+
}
|
|
44
|
+
export interface DeleteCustomDataResponse {
|
|
45
|
+
status: string;
|
|
46
|
+
message: string;
|
|
47
|
+
}
|
|
48
|
+
export declare class CustomDataAPI {
|
|
49
|
+
private collections;
|
|
50
|
+
constructor();
|
|
51
|
+
private generateId;
|
|
52
|
+
private getCollection;
|
|
53
|
+
create(collectionName: string, data: CreateCustomDataRequest): Promise<CreateCustomDataResponse>;
|
|
54
|
+
get(collectionName: string, filter?: any, page?: number, limit?: number): Promise<GetCustomDataResponse>;
|
|
55
|
+
getEntry(collectionName: string, entryId: string): Promise<CustomDataEntry | null>;
|
|
56
|
+
update(collectionName: string, entryId: string, data: UpdateCustomDataRequest): Promise<UpdateCustomDataResponse>;
|
|
57
|
+
search(collectionName: string, searchText: string, limit?: number, scoreThreshold?: number): Promise<SearchCustomDataResponse>;
|
|
58
|
+
delete(collectionName: string, entryId: string): Promise<DeleteCustomDataResponse>;
|
|
59
|
+
private matchesFilter;
|
|
60
|
+
private calculateSimilarity;
|
|
61
|
+
getAllCollections(): Map<string, CustomDataEntry[]>;
|
|
62
|
+
clearCollection(collectionName: string): void;
|
|
63
|
+
clearAllCollections(): void;
|
|
64
|
+
}
|
|
65
|
+
export declare const customData: {
|
|
66
|
+
create: (collectionName: string, data: CreateCustomDataRequest) => Promise<CreateCustomDataResponse>;
|
|
67
|
+
get: (collectionName: string, filter?: any, page?: number, limit?: number) => Promise<GetCustomDataResponse>;
|
|
68
|
+
getEntry: (collectionName: string, entryId: string) => Promise<CustomDataEntry | null>;
|
|
69
|
+
update: (collectionName: string, entryId: string, data: UpdateCustomDataRequest) => Promise<UpdateCustomDataResponse>;
|
|
70
|
+
search: (collectionName: string, searchText: string, limit?: number, scoreThreshold?: number) => Promise<SearchCustomDataResponse>;
|
|
71
|
+
delete: (collectionName: string, entryId: string) => Promise<DeleteCustomDataResponse>;
|
|
72
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export class CustomDataAPI {
|
|
2
|
+
constructor() {
|
|
3
|
+
// Store data by collection name
|
|
4
|
+
this.collections = new Map();
|
|
5
|
+
}
|
|
6
|
+
generateId() {
|
|
7
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
8
|
+
const r = Math.random() * 16 | 0;
|
|
9
|
+
const v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
10
|
+
return v.toString(16);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
getCollection(collectionName) {
|
|
14
|
+
if (!this.collections.has(collectionName)) {
|
|
15
|
+
this.collections.set(collectionName, []);
|
|
16
|
+
}
|
|
17
|
+
return this.collections.get(collectionName);
|
|
18
|
+
}
|
|
19
|
+
async create(collectionName, data) {
|
|
20
|
+
const collection = this.getCollection(collectionName);
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
const entry = {
|
|
23
|
+
id: this.generateId(),
|
|
24
|
+
data: data.data,
|
|
25
|
+
createdAt: now,
|
|
26
|
+
updatedAt: now,
|
|
27
|
+
searchText: data.searchText
|
|
28
|
+
};
|
|
29
|
+
collection.push(entry);
|
|
30
|
+
return {
|
|
31
|
+
id: entry.id,
|
|
32
|
+
data: entry.data,
|
|
33
|
+
createdAt: entry.createdAt,
|
|
34
|
+
updatedAt: entry.updatedAt,
|
|
35
|
+
searchText: entry.searchText
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async get(collectionName, filter, page = 1, limit = 10) {
|
|
39
|
+
const collection = this.getCollection(collectionName);
|
|
40
|
+
let filteredData = [...collection];
|
|
41
|
+
// Apply filter if provided
|
|
42
|
+
if (filter) {
|
|
43
|
+
filteredData = collection.filter(entry => {
|
|
44
|
+
return this.matchesFilter(entry.data, filter);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// Apply pagination
|
|
48
|
+
const startIndex = (page - 1) * limit;
|
|
49
|
+
const endIndex = startIndex + limit;
|
|
50
|
+
const paginatedData = filteredData.slice(startIndex, endIndex);
|
|
51
|
+
const totalCount = filteredData.length;
|
|
52
|
+
const totalPages = Math.ceil(totalCount / limit);
|
|
53
|
+
return {
|
|
54
|
+
data: paginatedData,
|
|
55
|
+
pagination: {
|
|
56
|
+
currentPage: page,
|
|
57
|
+
totalPages: totalPages,
|
|
58
|
+
totalCount: totalCount,
|
|
59
|
+
limit: limit,
|
|
60
|
+
hasNextPage: page < totalPages,
|
|
61
|
+
hasPrevPage: page > 1
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async getEntry(collectionName, entryId) {
|
|
66
|
+
const collection = this.getCollection(collectionName);
|
|
67
|
+
return collection.find(entry => entry.id === entryId) || null;
|
|
68
|
+
}
|
|
69
|
+
async update(collectionName, entryId, data) {
|
|
70
|
+
const collection = this.getCollection(collectionName);
|
|
71
|
+
const entryIndex = collection.findIndex(entry => entry.id === entryId);
|
|
72
|
+
if (entryIndex === -1) {
|
|
73
|
+
return {
|
|
74
|
+
status: 'error',
|
|
75
|
+
message: 'Custom data entry not found'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const entry = collection[entryIndex];
|
|
79
|
+
entry.data = { ...entry.data, ...data.data };
|
|
80
|
+
entry.updatedAt = Date.now();
|
|
81
|
+
if (data.searchText !== undefined) {
|
|
82
|
+
entry.searchText = data.searchText;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
status: 'success',
|
|
86
|
+
message: 'Custom data entry updated'
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async search(collectionName, searchText, limit = 10, scoreThreshold = 0.6) {
|
|
90
|
+
const collection = this.getCollection(collectionName);
|
|
91
|
+
const results = [];
|
|
92
|
+
for (const entry of collection) {
|
|
93
|
+
if (entry.searchText) {
|
|
94
|
+
const score = this.calculateSimilarity(searchText.toLowerCase(), entry.searchText.toLowerCase());
|
|
95
|
+
if (score >= scoreThreshold) {
|
|
96
|
+
results.push({ ...entry, score });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Sort by score descending
|
|
101
|
+
results.sort((a, b) => b.score - a.score);
|
|
102
|
+
// Apply limit
|
|
103
|
+
const limitedResults = results.slice(0, limit);
|
|
104
|
+
return {
|
|
105
|
+
data: limitedResults,
|
|
106
|
+
count: limitedResults.length
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async delete(collectionName, entryId) {
|
|
110
|
+
const collection = this.getCollection(collectionName);
|
|
111
|
+
const initialLength = collection.length;
|
|
112
|
+
const updatedCollection = collection.filter(entry => entry.id !== entryId);
|
|
113
|
+
this.collections.set(collectionName, updatedCollection);
|
|
114
|
+
if (updatedCollection.length < initialLength) {
|
|
115
|
+
return {
|
|
116
|
+
status: 'success',
|
|
117
|
+
message: 'Custom data entry deleted'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return {
|
|
122
|
+
status: 'error',
|
|
123
|
+
message: 'Custom data entry not found'
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Helper method to check if an object matches a filter
|
|
128
|
+
matchesFilter(obj, filter) {
|
|
129
|
+
for (const key in filter) {
|
|
130
|
+
if (filter.hasOwnProperty(key)) {
|
|
131
|
+
if (typeof filter[key] === 'object' && filter[key] !== null) {
|
|
132
|
+
if (typeof obj[key] !== 'object' || !this.matchesFilter(obj[key], filter[key])) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
if (obj[key] !== filter[key]) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
// Simple similarity calculation (Jaccard similarity for words)
|
|
146
|
+
calculateSimilarity(str1, str2) {
|
|
147
|
+
const words1 = new Set(str1.split(/\s+/));
|
|
148
|
+
const words2 = new Set(str2.split(/\s+/));
|
|
149
|
+
const intersection = new Set([...words1].filter(x => words2.has(x)));
|
|
150
|
+
const union = new Set([...words1, ...words2]);
|
|
151
|
+
return intersection.size / union.size;
|
|
152
|
+
}
|
|
153
|
+
// Method to get all collections (for debugging/testing)
|
|
154
|
+
getAllCollections() {
|
|
155
|
+
return this.collections;
|
|
156
|
+
}
|
|
157
|
+
// Method to clear a collection (for testing)
|
|
158
|
+
clearCollection(collectionName) {
|
|
159
|
+
this.collections.set(collectionName, []);
|
|
160
|
+
}
|
|
161
|
+
// Method to clear all collections (for testing)
|
|
162
|
+
clearAllCollections() {
|
|
163
|
+
this.collections.clear();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const customDataAPI = new CustomDataAPI();
|
|
167
|
+
export const customData = {
|
|
168
|
+
create: (collectionName, data) => customDataAPI.create(collectionName, data),
|
|
169
|
+
get: (collectionName, filter, page, limit) => customDataAPI.get(collectionName, filter, page, limit),
|
|
170
|
+
getEntry: (collectionName, entryId) => customDataAPI.getEntry(collectionName, entryId),
|
|
171
|
+
update: (collectionName, entryId, data) => customDataAPI.update(collectionName, entryId, data),
|
|
172
|
+
search: (collectionName, searchText, limit, scoreThreshold) => customDataAPI.search(collectionName, searchText, limit, scoreThreshold),
|
|
173
|
+
delete: (collectionName, entryId) => customDataAPI.delete(collectionName, entryId),
|
|
174
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/product-api.d.ts
CHANGED
|
@@ -34,15 +34,156 @@ export interface SearchProductsResponse {
|
|
|
34
34
|
message: string;
|
|
35
35
|
data: Product[];
|
|
36
36
|
}
|
|
37
|
+
export interface BasketItem {
|
|
38
|
+
id: string;
|
|
39
|
+
price: number;
|
|
40
|
+
quantity: number;
|
|
41
|
+
SKU?: string;
|
|
42
|
+
addedAt?: string;
|
|
43
|
+
[key: string]: any;
|
|
44
|
+
}
|
|
45
|
+
export interface Basket {
|
|
46
|
+
id: string;
|
|
47
|
+
userId: string;
|
|
48
|
+
agentId: string;
|
|
49
|
+
data: {
|
|
50
|
+
currency: string;
|
|
51
|
+
items: BasketItem[];
|
|
52
|
+
createdAt: string;
|
|
53
|
+
};
|
|
54
|
+
common: {
|
|
55
|
+
status: 'active' | 'checked_out' | 'abandoned' | 'expired';
|
|
56
|
+
totalAmount: string | number;
|
|
57
|
+
itemCount: number;
|
|
58
|
+
};
|
|
59
|
+
createdAt: string;
|
|
60
|
+
updatedAt: string;
|
|
61
|
+
__v: number;
|
|
62
|
+
}
|
|
63
|
+
export interface CreateBasketRequest {
|
|
64
|
+
currency: string;
|
|
65
|
+
}
|
|
66
|
+
export interface CreateBasketResponse {
|
|
67
|
+
success: boolean;
|
|
68
|
+
message: string;
|
|
69
|
+
data: Basket;
|
|
70
|
+
}
|
|
71
|
+
export interface GetBasketsResponse {
|
|
72
|
+
success: boolean;
|
|
73
|
+
message: string;
|
|
74
|
+
data: Basket[];
|
|
75
|
+
}
|
|
76
|
+
export interface AddItemToBasketRequest {
|
|
77
|
+
id: string;
|
|
78
|
+
price: number;
|
|
79
|
+
quantity: number;
|
|
80
|
+
[key: string]: any;
|
|
81
|
+
}
|
|
82
|
+
export interface AddItemToBasketResponse {
|
|
83
|
+
success: boolean;
|
|
84
|
+
message: string;
|
|
85
|
+
data: Basket;
|
|
86
|
+
}
|
|
87
|
+
export interface RemoveItemFromBasketResponse {
|
|
88
|
+
success: boolean;
|
|
89
|
+
message: string;
|
|
90
|
+
data: Basket;
|
|
91
|
+
}
|
|
92
|
+
export interface ClearBasketResponse {
|
|
93
|
+
success: boolean;
|
|
94
|
+
message: string;
|
|
95
|
+
data: Basket;
|
|
96
|
+
}
|
|
97
|
+
export interface UpdateBasketStatusResponse {
|
|
98
|
+
success: boolean;
|
|
99
|
+
message: string;
|
|
100
|
+
data: Basket;
|
|
101
|
+
}
|
|
102
|
+
export interface Order {
|
|
103
|
+
id: string;
|
|
104
|
+
userId: string;
|
|
105
|
+
agentId: string;
|
|
106
|
+
orderId: string;
|
|
107
|
+
data: {
|
|
108
|
+
currency: string;
|
|
109
|
+
items: BasketItem[];
|
|
110
|
+
createdAt: string;
|
|
111
|
+
basketId: string;
|
|
112
|
+
orderDate: string;
|
|
113
|
+
orderId: string;
|
|
114
|
+
[key: string]: any;
|
|
115
|
+
};
|
|
116
|
+
common: {
|
|
117
|
+
status: 'pending' | 'confirmed' | 'fulfilled' | 'cancelled';
|
|
118
|
+
totalAmount: string | number;
|
|
119
|
+
currency: string;
|
|
120
|
+
itemCount: number;
|
|
121
|
+
};
|
|
122
|
+
createdAt: string;
|
|
123
|
+
updatedAt: string;
|
|
124
|
+
__v: number;
|
|
125
|
+
}
|
|
126
|
+
export interface CreateOrderRequest {
|
|
127
|
+
basketId: string;
|
|
128
|
+
data: {
|
|
129
|
+
[key: string]: any;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export interface CreateOrderResponse {
|
|
133
|
+
success: boolean;
|
|
134
|
+
message: string;
|
|
135
|
+
data: Order;
|
|
136
|
+
}
|
|
137
|
+
export interface UpdateOrderStatusResponse {
|
|
138
|
+
success: boolean;
|
|
139
|
+
message: string;
|
|
140
|
+
data: Order;
|
|
141
|
+
}
|
|
142
|
+
export interface GetUserOrdersResponse {
|
|
143
|
+
success: boolean;
|
|
144
|
+
message: string;
|
|
145
|
+
data: Order[];
|
|
146
|
+
}
|
|
147
|
+
export type BasketStatus = 'active' | 'checked_out' | 'abandoned' | 'expired';
|
|
148
|
+
export type OrderStatus = 'pending' | 'confirmed' | 'fulfilled' | 'cancelled';
|
|
37
149
|
export declare class ProductAPI {
|
|
38
|
-
products:
|
|
150
|
+
products: Product[];
|
|
151
|
+
baskets: Basket[];
|
|
152
|
+
orders: Order[];
|
|
39
153
|
constructor();
|
|
40
154
|
get(page?: number, limit?: number): Promise<ProductsResponse>;
|
|
41
155
|
create(data: Record<string, any>): Promise<CreateProductResponse>;
|
|
42
156
|
update(data: Record<string, any>, productId: string): Promise<UpdateProductResponse>;
|
|
43
157
|
delete(productId: string): Promise<DeleteProductResponse>;
|
|
44
158
|
search(searchQuery: string): Promise<SearchProductsResponse>;
|
|
159
|
+
createBasket(data: CreateBasketRequest): Promise<CreateBasketResponse>;
|
|
160
|
+
getBaskets(status?: BasketStatus): Promise<GetBasketsResponse>;
|
|
161
|
+
addItemToBasket(basketId: string, data: AddItemToBasketRequest): Promise<AddItemToBasketResponse>;
|
|
162
|
+
removeItemFromBasket(basketId: string, itemId: string): Promise<RemoveItemFromBasketResponse>;
|
|
163
|
+
clearBasket(basketId: string): Promise<ClearBasketResponse>;
|
|
164
|
+
updateBasketStatus(basketId: string, status: BasketStatus): Promise<UpdateBasketStatusResponse>;
|
|
165
|
+
createOrder(data: CreateOrderRequest): Promise<CreateOrderResponse>;
|
|
166
|
+
updateOrderStatus(orderId: string, status: OrderStatus): Promise<UpdateOrderStatusResponse>;
|
|
167
|
+
getUserOrders(userId: string): Promise<GetUserOrdersResponse>;
|
|
45
168
|
}
|
|
46
169
|
export declare const product: {
|
|
170
|
+
create: (data: Record<string, any>) => Promise<CreateProductResponse>;
|
|
171
|
+
get: (page?: number, limit?: number) => Promise<ProductsResponse>;
|
|
172
|
+
update: (data: Record<string, any>, productId: string) => Promise<UpdateProductResponse>;
|
|
173
|
+
delete: (productId: string) => Promise<DeleteProductResponse>;
|
|
174
|
+
search: (searchQuery: string) => Promise<SearchProductsResponse>;
|
|
47
175
|
data: ProductAPI;
|
|
176
|
+
basket: {
|
|
177
|
+
create: (data: CreateBasketRequest) => Promise<CreateBasketResponse>;
|
|
178
|
+
get: (status?: BasketStatus) => Promise<GetBasketsResponse>;
|
|
179
|
+
addItem: (basketId: string, data: AddItemToBasketRequest) => Promise<AddItemToBasketResponse>;
|
|
180
|
+
removeItem: (basketId: string, itemId: string) => Promise<RemoveItemFromBasketResponse>;
|
|
181
|
+
clear: (basketId: string) => Promise<ClearBasketResponse>;
|
|
182
|
+
updateStatus: (basketId: string, status: BasketStatus) => Promise<UpdateBasketStatusResponse>;
|
|
183
|
+
};
|
|
184
|
+
order: {
|
|
185
|
+
create: (data: CreateOrderRequest) => Promise<CreateOrderResponse>;
|
|
186
|
+
updateStatus: (orderId: string, status: OrderStatus) => Promise<UpdateOrderStatusResponse>;
|
|
187
|
+
get: (userId: string) => Promise<GetUserOrdersResponse>;
|
|
188
|
+
};
|
|
48
189
|
};
|
package/dist/product-api.js
CHANGED
|
@@ -1,27 +1,141 @@
|
|
|
1
1
|
export class ProductAPI {
|
|
2
2
|
constructor() {
|
|
3
|
-
this.products =
|
|
3
|
+
this.products = [];
|
|
4
|
+
this.baskets = [];
|
|
5
|
+
this.orders = [];
|
|
4
6
|
}
|
|
5
7
|
async get(page = 1, limit = 10) {
|
|
6
|
-
return {
|
|
8
|
+
return {
|
|
9
|
+
success: true,
|
|
10
|
+
data: this.products,
|
|
11
|
+
pagination: {
|
|
12
|
+
currentPage: page,
|
|
13
|
+
totalPages: 1,
|
|
14
|
+
totalCount: this.products.length,
|
|
15
|
+
limit: limit,
|
|
16
|
+
hasNextPage: false,
|
|
17
|
+
hasPrevPage: false,
|
|
18
|
+
nextPage: null,
|
|
19
|
+
prevPage: null
|
|
20
|
+
}
|
|
21
|
+
};
|
|
7
22
|
}
|
|
8
23
|
async create(data) {
|
|
9
|
-
|
|
10
|
-
|
|
24
|
+
const product = data;
|
|
25
|
+
const existingIndex = this.products.findIndex(p => p.id === product.id);
|
|
26
|
+
if (existingIndex >= 0) {
|
|
27
|
+
this.products[existingIndex] = product;
|
|
28
|
+
return { updated: true, isNew: false, product };
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
this.products.push(product);
|
|
32
|
+
return { updated: false, isNew: true, product };
|
|
33
|
+
}
|
|
11
34
|
}
|
|
12
35
|
async update(data, productId) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
36
|
+
const product = data;
|
|
37
|
+
const existingIndex = this.products.findIndex(p => p.id === productId);
|
|
38
|
+
if (existingIndex >= 0) {
|
|
39
|
+
this.products[existingIndex] = { ...this.products[existingIndex], ...product };
|
|
40
|
+
return { updated: true, isNew: false, product: this.products[existingIndex] };
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
this.products.push(product);
|
|
44
|
+
return { updated: false, isNew: true, product };
|
|
45
|
+
}
|
|
16
46
|
}
|
|
17
47
|
async delete(productId) {
|
|
48
|
+
const initialLength = this.products.length;
|
|
18
49
|
this.products = this.products.filter((product) => product.id !== productId);
|
|
19
|
-
return { deleted:
|
|
50
|
+
return { deleted: this.products.length < initialLength };
|
|
20
51
|
}
|
|
21
52
|
async search(searchQuery) {
|
|
22
|
-
|
|
53
|
+
const results = this.products.filter(product => Object.values(product).some(value => String(value).toLowerCase().includes(searchQuery.toLowerCase())));
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
message: `Successfully found ${results.length} products for "${searchQuery}"`,
|
|
57
|
+
data: results
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async createBasket(data) {
|
|
61
|
+
const basket = { ...data, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), __v: 0 };
|
|
62
|
+
this.baskets.push(basket);
|
|
63
|
+
return { success: true, message: 'Basket created successfully', data: basket };
|
|
64
|
+
}
|
|
65
|
+
async getBaskets(status) {
|
|
66
|
+
if (status) {
|
|
67
|
+
return { success: true, message: 'Baskets fetched successfully', data: this.baskets.filter((basket) => basket.common.status === status) };
|
|
68
|
+
}
|
|
69
|
+
return { success: true, message: 'Baskets fetched successfully', data: this.baskets };
|
|
70
|
+
}
|
|
71
|
+
async addItemToBasket(basketId, data) {
|
|
72
|
+
const basket = this.baskets.find((basket) => basket.id === basketId);
|
|
73
|
+
if (basket) {
|
|
74
|
+
basket.data.items.push(data);
|
|
75
|
+
return { success: true, message: 'Item added to basket successfully', data: basket };
|
|
76
|
+
}
|
|
77
|
+
return { success: false, message: 'Basket not found', data: null };
|
|
78
|
+
}
|
|
79
|
+
async removeItemFromBasket(basketId, itemId) {
|
|
80
|
+
const basket = this.baskets.find((basket) => basket.id === basketId);
|
|
81
|
+
if (basket) {
|
|
82
|
+
basket.data.items = basket.data.items.filter((item) => item.id !== itemId);
|
|
83
|
+
return { success: true, message: 'Item removed from basket successfully', data: basket };
|
|
84
|
+
}
|
|
85
|
+
return { success: false, message: 'Basket not found', data: null };
|
|
86
|
+
}
|
|
87
|
+
async clearBasket(basketId) {
|
|
88
|
+
const basket = this.baskets.find((basket) => basket.id === basketId);
|
|
89
|
+
if (basket) {
|
|
90
|
+
basket.data.items = [];
|
|
91
|
+
return { success: true, message: 'Basket cleared successfully', data: basket };
|
|
92
|
+
}
|
|
93
|
+
return { success: false, message: 'Basket not found', data: null };
|
|
94
|
+
}
|
|
95
|
+
async updateBasketStatus(basketId, status) {
|
|
96
|
+
const basket = this.baskets.find((basket) => basket.id === basketId);
|
|
97
|
+
if (basket) {
|
|
98
|
+
basket.common.status = status;
|
|
99
|
+
return { success: true, message: 'Basket status updated successfully', data: basket };
|
|
100
|
+
}
|
|
101
|
+
return { success: false, message: 'Basket not found', data: null };
|
|
102
|
+
}
|
|
103
|
+
async createOrder(data) {
|
|
104
|
+
const order = { ...data, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), __v: 0 };
|
|
105
|
+
this.orders.push(order);
|
|
106
|
+
return { success: true, message: 'Order created successfully', data: order };
|
|
107
|
+
}
|
|
108
|
+
async updateOrderStatus(orderId, status) {
|
|
109
|
+
const order = this.orders.find((order) => order.id === orderId);
|
|
110
|
+
if (order) {
|
|
111
|
+
order.common.status = status;
|
|
112
|
+
return { success: true, message: 'Order status updated successfully', data: order };
|
|
113
|
+
}
|
|
114
|
+
return { success: false, message: 'Order not found', data: null };
|
|
115
|
+
}
|
|
116
|
+
async getUserOrders(userId) {
|
|
117
|
+
return { success: true, message: 'User orders fetched successfully', data: this.orders.filter((order) => order.userId === userId) };
|
|
23
118
|
}
|
|
24
119
|
}
|
|
120
|
+
const productAPI = new ProductAPI();
|
|
25
121
|
export const product = {
|
|
26
|
-
|
|
122
|
+
create: productAPI.create,
|
|
123
|
+
get: productAPI.get,
|
|
124
|
+
update: productAPI.update,
|
|
125
|
+
delete: productAPI.delete,
|
|
126
|
+
search: productAPI.search,
|
|
127
|
+
data: productAPI,
|
|
128
|
+
basket: {
|
|
129
|
+
create: productAPI.createBasket,
|
|
130
|
+
get: productAPI.getBaskets,
|
|
131
|
+
addItem: productAPI.addItemToBasket,
|
|
132
|
+
removeItem: productAPI.removeItemFromBasket,
|
|
133
|
+
clear: productAPI.clearBasket,
|
|
134
|
+
updateStatus: productAPI.updateBasketStatus
|
|
135
|
+
},
|
|
136
|
+
order: {
|
|
137
|
+
create: productAPI.createOrder,
|
|
138
|
+
updateStatus: productAPI.updateOrderStatus,
|
|
139
|
+
get: productAPI.getUserOrders
|
|
140
|
+
}
|
|
27
141
|
};
|