lua-cli 2.5.1 → 2.5.3
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/CHANGELOG.md +29 -0
- package/CLI_REFERENCE.md +90 -0
- package/INSTANCE_TYPES.md +1158 -0
- package/README.md +6 -0
- package/dist/api/agent.api.service.d.ts +52 -0
- package/dist/api/agent.api.service.js +63 -0
- package/dist/api/logs.api.service.d.ts +35 -0
- package/dist/api/logs.api.service.js +43 -0
- package/dist/api/products.api.service.js +2 -0
- package/dist/cli/command-definitions.js +17 -1
- package/dist/commands/admin.d.ts +23 -0
- package/dist/commands/admin.js +62 -0
- package/dist/commands/channels.d.ts +17 -0
- package/dist/commands/channels.js +676 -0
- package/dist/commands/docs.d.ts +19 -0
- package/dist/commands/docs.js +30 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/logs.d.ts +17 -0
- package/dist/commands/logs.js +271 -0
- package/dist/common/basket.instance.d.ts +4 -1
- package/dist/common/basket.instance.js +76 -1
- package/dist/common/data.entry.instance.d.ts +4 -1
- package/dist/common/data.entry.instance.js +57 -1
- package/dist/common/http.client.js +11 -1
- package/dist/common/order.instance.d.ts +4 -1
- package/dist/common/order.instance.js +76 -1
- package/dist/common/product.instance.d.ts +4 -1
- package/dist/common/product.instance.js +57 -1
- package/dist/common/product.pagination.instance.d.ts +58 -0
- package/dist/common/product.pagination.instance.js +78 -0
- package/dist/common/product.search.instance.d.ts +58 -0
- package/dist/common/product.search.instance.js +78 -0
- package/dist/common/user.instance.d.ts +4 -12
- package/dist/common/user.instance.js +5 -24
- package/dist/index.js +3 -0
- package/dist/interfaces/agent.d.ts +218 -0
- package/dist/interfaces/logs.d.ts +40 -0
- package/dist/interfaces/logs.js +5 -0
- package/package.json +2 -1
- package/template/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs Command
|
|
3
|
+
* Opens the Lua documentation website in the user's default browser
|
|
4
|
+
*/
|
|
5
|
+
import open from 'open';
|
|
6
|
+
import { withErrorHandling, writeSuccess, writeProgress } from '../utils/cli.js';
|
|
7
|
+
/**
|
|
8
|
+
* Docs command - opens the Lua documentation in the browser.
|
|
9
|
+
*
|
|
10
|
+
* This command opens https://docs.heylua.ai in the user's default browser,
|
|
11
|
+
* providing quick access to:
|
|
12
|
+
* - Platform overview and concepts
|
|
13
|
+
* - CLI command reference
|
|
14
|
+
* - API documentation
|
|
15
|
+
* - Tool examples and guides
|
|
16
|
+
* - Integration tutorials
|
|
17
|
+
* - Best practices
|
|
18
|
+
*
|
|
19
|
+
* @returns Promise that resolves when browser is launched
|
|
20
|
+
*/
|
|
21
|
+
export async function docsCommand() {
|
|
22
|
+
return withErrorHandling(async () => {
|
|
23
|
+
writeProgress('Opening Lua Documentation...');
|
|
24
|
+
// Open the documentation website
|
|
25
|
+
const docsUrl = 'https://docs.heylua.ai';
|
|
26
|
+
await open(docsUrl);
|
|
27
|
+
writeSuccess('Lua Documentation opened in your browser');
|
|
28
|
+
console.log(`\n Documentation: ${docsUrl}\n`);
|
|
29
|
+
}, 'docs');
|
|
30
|
+
}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -13,3 +13,7 @@ export { envCommand } from "./env.js";
|
|
|
13
13
|
export { personaCommand } from "./persona.js";
|
|
14
14
|
export { productionCommand } from "./production.js";
|
|
15
15
|
export { resourcesCommand } from "./resources.js";
|
|
16
|
+
export { adminCommand } from "./admin.js";
|
|
17
|
+
export { docsCommand } from "./docs.js";
|
|
18
|
+
export { channelsCommand } from "./channels.js";
|
|
19
|
+
export { logsCommand } from "./logs.js";
|
package/dist/commands/index.js
CHANGED
|
@@ -13,3 +13,7 @@ export { envCommand } from "./env.js";
|
|
|
13
13
|
export { personaCommand } from "./persona.js";
|
|
14
14
|
export { productionCommand } from "./production.js";
|
|
15
15
|
export { resourcesCommand } from "./resources.js";
|
|
16
|
+
export { adminCommand } from "./admin.js";
|
|
17
|
+
export { docsCommand } from "./docs.js";
|
|
18
|
+
export { channelsCommand } from "./channels.js";
|
|
19
|
+
export { logsCommand } from "./logs.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs Command
|
|
3
|
+
* View and navigate agent/skill logs with pagination
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Main logs command - displays agent/skill logs with navigation
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - View all agent logs or filter by specific skill
|
|
10
|
+
* - Interactive pagination
|
|
11
|
+
* - Color-coded log types
|
|
12
|
+
* - Real-time navigation
|
|
13
|
+
*
|
|
14
|
+
* @returns Promise that resolves when the command completes
|
|
15
|
+
* @throws Error if API key or configuration is not found
|
|
16
|
+
*/
|
|
17
|
+
export declare function logsCommand(): Promise<void>;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs Command
|
|
3
|
+
* View and navigate agent/skill logs with pagination
|
|
4
|
+
*/
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { loadApiKey } from "../services/auth.js";
|
|
8
|
+
import { readSkillConfig } from "../utils/files.js";
|
|
9
|
+
import { withErrorHandling, writeSuccess, writeInfo, writeError, clearPromptLines } from "../utils/cli.js";
|
|
10
|
+
import LogsApi from '../api/logs.api.service.js';
|
|
11
|
+
import { BASE_URLS } from '../config/constants.js';
|
|
12
|
+
/**
|
|
13
|
+
* Main logs command - displays agent/skill logs with navigation
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - View all agent logs or filter by specific skill
|
|
17
|
+
* - Interactive pagination
|
|
18
|
+
* - Color-coded log types
|
|
19
|
+
* - Real-time navigation
|
|
20
|
+
*
|
|
21
|
+
* @returns Promise that resolves when the command completes
|
|
22
|
+
* @throws Error if API key or configuration is not found
|
|
23
|
+
*/
|
|
24
|
+
export async function logsCommand() {
|
|
25
|
+
return withErrorHandling(async () => {
|
|
26
|
+
// Load API key
|
|
27
|
+
const apiKey = await loadApiKey();
|
|
28
|
+
if (!apiKey) {
|
|
29
|
+
console.error("❌ No API key found. Run `lua auth configure` first.");
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
// Load agent ID from configuration
|
|
33
|
+
const config = readSkillConfig();
|
|
34
|
+
const agentId = config?.agent?.agentId;
|
|
35
|
+
if (!agentId) {
|
|
36
|
+
throw new Error("No agent ID found in lua.skill.yaml. Please ensure you are in a Lua skill directory, or run 'lua init' to create a new skill.");
|
|
37
|
+
}
|
|
38
|
+
writeInfo(`📊 Viewing logs for agent: ${agentId}\n`);
|
|
39
|
+
const logsApi = new LogsApi(BASE_URLS.API, apiKey);
|
|
40
|
+
// Ask if user wants all logs or specific skill
|
|
41
|
+
const { viewType } = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: "list",
|
|
44
|
+
name: "viewType",
|
|
45
|
+
message: "What logs do you want to view?",
|
|
46
|
+
choices: [
|
|
47
|
+
{ name: "📋 All agent logs", value: "all" },
|
|
48
|
+
{ name: "🎯 Specific skill logs", value: "skill" }
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]);
|
|
52
|
+
clearPromptLines(2);
|
|
53
|
+
if (viewType === "all") {
|
|
54
|
+
await viewAgentLogs(logsApi, agentId);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
await viewSkillLogs(logsApi, agentId, config);
|
|
58
|
+
}
|
|
59
|
+
}, "logs viewing");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* View all logs for an agent with pagination
|
|
63
|
+
*/
|
|
64
|
+
async function viewAgentLogs(logsApi, agentId) {
|
|
65
|
+
let currentPage = 1;
|
|
66
|
+
const limit = 20;
|
|
67
|
+
let keepViewing = true;
|
|
68
|
+
while (keepViewing) {
|
|
69
|
+
const response = await logsApi.getAgentLogs(agentId, limit, currentPage);
|
|
70
|
+
if (!response.success) {
|
|
71
|
+
writeError(`❌ Error: ${response.error?.message || 'Unknown error'}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
const data = response.data;
|
|
75
|
+
displayLogs(data.logs, data.pagination, "All Agent Logs");
|
|
76
|
+
// Navigation menu
|
|
77
|
+
const { action } = await inquirer.prompt([
|
|
78
|
+
{
|
|
79
|
+
type: "list",
|
|
80
|
+
name: "action",
|
|
81
|
+
message: "Navigation:",
|
|
82
|
+
choices: getNavigationChoices(data.pagination)
|
|
83
|
+
}
|
|
84
|
+
]);
|
|
85
|
+
clearPromptLines(2);
|
|
86
|
+
keepViewing = await handleNavigation(action, data.pagination, (page) => {
|
|
87
|
+
currentPage = page;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* View logs for a specific skill with pagination
|
|
93
|
+
*/
|
|
94
|
+
async function viewSkillLogs(logsApi, agentId, config) {
|
|
95
|
+
// Get skills from config
|
|
96
|
+
const skills = config?.skills || [];
|
|
97
|
+
if (skills.length === 0) {
|
|
98
|
+
writeError("❌ No skills found in lua.skill.yaml");
|
|
99
|
+
writeInfo("💡 Run 'lua push' to deploy skills first.\n");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Let user select a skill
|
|
103
|
+
const skillChoices = skills.map((skill) => ({
|
|
104
|
+
name: `${skill.name} (${skill.skillId || 'No ID'})`,
|
|
105
|
+
value: skill.skillId
|
|
106
|
+
}));
|
|
107
|
+
skillChoices.push({
|
|
108
|
+
name: '← Back to main menu',
|
|
109
|
+
value: null
|
|
110
|
+
});
|
|
111
|
+
const { skillId } = await inquirer.prompt([
|
|
112
|
+
{
|
|
113
|
+
type: "list",
|
|
114
|
+
name: "skillId",
|
|
115
|
+
message: "Select a skill:",
|
|
116
|
+
choices: skillChoices
|
|
117
|
+
}
|
|
118
|
+
]);
|
|
119
|
+
if (!skillId) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
clearPromptLines(2);
|
|
123
|
+
let currentPage = 1;
|
|
124
|
+
const limit = 20;
|
|
125
|
+
let keepViewing = true;
|
|
126
|
+
const selectedSkill = skills.find((s) => s.skillId === skillId);
|
|
127
|
+
const skillName = selectedSkill?.name || skillId;
|
|
128
|
+
while (keepViewing) {
|
|
129
|
+
const response = await logsApi.getSkillLogs(agentId, skillId, limit, currentPage);
|
|
130
|
+
if (!response.success) {
|
|
131
|
+
writeError(`❌ Error: ${response.error?.message || 'Unknown error'}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
const data = response.data;
|
|
135
|
+
displayLogs(data.logs, data.pagination, `Logs for ${skillName}`);
|
|
136
|
+
// Navigation menu
|
|
137
|
+
const { action } = await inquirer.prompt([
|
|
138
|
+
{
|
|
139
|
+
type: "list",
|
|
140
|
+
name: "action",
|
|
141
|
+
message: "Navigation:",
|
|
142
|
+
choices: getNavigationChoices(data.pagination)
|
|
143
|
+
}
|
|
144
|
+
]);
|
|
145
|
+
clearPromptLines(2);
|
|
146
|
+
keepViewing = await handleNavigation(action, data.pagination, (page) => {
|
|
147
|
+
currentPage = page;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Display logs with color coding
|
|
153
|
+
*/
|
|
154
|
+
function displayLogs(logs, pagination, title) {
|
|
155
|
+
console.clear();
|
|
156
|
+
writeSuccess(`\n${title}\n`);
|
|
157
|
+
writeInfo(`${'─'.repeat(80)}`);
|
|
158
|
+
writeInfo(`Page ${pagination.currentPage} of ${pagination.totalPages} (${pagination.totalCount} total logs)\n`);
|
|
159
|
+
if (logs.length === 0) {
|
|
160
|
+
writeInfo("No logs found.");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
logs.forEach((log, index) => {
|
|
164
|
+
const timestamp = new Date(log.timestamp).toLocaleString();
|
|
165
|
+
const icon = getLogIcon(log.subType);
|
|
166
|
+
const color = getLogColor(log.subType);
|
|
167
|
+
console.log(color(`${icon} [${timestamp}] ${log.subType.toUpperCase()}`));
|
|
168
|
+
if (log.metadata.skillName) {
|
|
169
|
+
console.log(chalk.gray(` Skill: ${log.metadata.skillName}`));
|
|
170
|
+
}
|
|
171
|
+
if (log.metadata.toolId) {
|
|
172
|
+
console.log(chalk.gray(` Tool: ${log.metadata.toolId}`));
|
|
173
|
+
}
|
|
174
|
+
if (log.duration !== undefined) {
|
|
175
|
+
console.log(chalk.gray(` Duration: ${log.duration}ms`));
|
|
176
|
+
}
|
|
177
|
+
// Display message (truncate if too long)
|
|
178
|
+
const message = log.message.length > 200
|
|
179
|
+
? log.message.substring(0, 200) + '...'
|
|
180
|
+
: log.message;
|
|
181
|
+
console.log(` ${message}`);
|
|
182
|
+
if (index < logs.length - 1) {
|
|
183
|
+
console.log(chalk.gray(` ${'-'.repeat(78)}`));
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
writeInfo(`\n${'─'.repeat(80)}\n`);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get navigation choices based on pagination state
|
|
190
|
+
*/
|
|
191
|
+
function getNavigationChoices(pagination) {
|
|
192
|
+
const choices = [];
|
|
193
|
+
if (pagination.hasPrevPage) {
|
|
194
|
+
choices.push({ name: '← Previous Page', value: 'prev' });
|
|
195
|
+
}
|
|
196
|
+
if (pagination.hasNextPage) {
|
|
197
|
+
choices.push({ name: 'Next Page →', value: 'next' });
|
|
198
|
+
}
|
|
199
|
+
if (pagination.totalPages > 1) {
|
|
200
|
+
choices.push({ name: '🔢 Go to specific page', value: 'goto' });
|
|
201
|
+
}
|
|
202
|
+
choices.push({ name: '🔄 Refresh', value: 'refresh' });
|
|
203
|
+
choices.push({ name: '❌ Exit', value: 'exit' });
|
|
204
|
+
return choices;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Handle navigation actions
|
|
208
|
+
*/
|
|
209
|
+
async function handleNavigation(action, pagination, setPage) {
|
|
210
|
+
switch (action) {
|
|
211
|
+
case 'prev':
|
|
212
|
+
if (pagination.hasPrevPage) {
|
|
213
|
+
setPage(pagination.prevPage);
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
case 'next':
|
|
217
|
+
if (pagination.hasNextPage) {
|
|
218
|
+
setPage(pagination.nextPage);
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
case 'goto':
|
|
222
|
+
const { page } = await inquirer.prompt({
|
|
223
|
+
type: "number",
|
|
224
|
+
name: "page",
|
|
225
|
+
message: `Enter page number (1-${pagination.totalPages}):`,
|
|
226
|
+
validate: (input) => {
|
|
227
|
+
if (input === undefined || input < 1 || input > pagination.totalPages) {
|
|
228
|
+
return `Please enter a number between 1 and ${pagination.totalPages}`;
|
|
229
|
+
}
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
setPage(page);
|
|
234
|
+
return true;
|
|
235
|
+
case 'refresh':
|
|
236
|
+
return true;
|
|
237
|
+
case 'exit':
|
|
238
|
+
writeInfo("👋 Exiting logs viewer\n");
|
|
239
|
+
return false;
|
|
240
|
+
default:
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get icon for log type
|
|
246
|
+
*/
|
|
247
|
+
function getLogIcon(subType) {
|
|
248
|
+
const icons = {
|
|
249
|
+
'error': '❌',
|
|
250
|
+
'warn': '⚠️',
|
|
251
|
+
'debug': '🔍',
|
|
252
|
+
'info': 'ℹ️',
|
|
253
|
+
'start': '▶️',
|
|
254
|
+
'complete': '✅'
|
|
255
|
+
};
|
|
256
|
+
return icons[subType] || '📝';
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get color function for log type
|
|
260
|
+
*/
|
|
261
|
+
function getLogColor(subType) {
|
|
262
|
+
const colors = {
|
|
263
|
+
'error': chalk.red,
|
|
264
|
+
'warn': chalk.yellow,
|
|
265
|
+
'debug': chalk.blue,
|
|
266
|
+
'info': chalk.cyan,
|
|
267
|
+
'start': chalk.green,
|
|
268
|
+
'complete': chalk.green
|
|
269
|
+
};
|
|
270
|
+
return colors[subType] || chalk.white;
|
|
271
|
+
}
|
|
@@ -4,6 +4,7 @@ import OrderInstance from "./order.instance.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* Basket instance class providing a fluent API for managing user baskets
|
|
6
6
|
* Provides methods for adding/removing items, updating metadata, and placing orders
|
|
7
|
+
* Supports direct property access (e.g., basket.items) for accessing data and common properties
|
|
7
8
|
*/
|
|
8
9
|
export default class BasketInstance {
|
|
9
10
|
private id;
|
|
@@ -16,10 +17,12 @@ export default class BasketInstance {
|
|
|
16
17
|
itemCount: number;
|
|
17
18
|
status: BasketStatus;
|
|
18
19
|
private basketAPI;
|
|
20
|
+
[key: string]: any;
|
|
19
21
|
/**
|
|
20
|
-
* Creates a new BasketInstance
|
|
22
|
+
* Creates a new BasketInstance with proxy support for direct property access
|
|
21
23
|
* @param api - The BasketAPI instance for making API calls
|
|
22
24
|
* @param basket - The basket data from the API
|
|
25
|
+
* @returns Proxied instance that allows direct access to data and common properties
|
|
23
26
|
*/
|
|
24
27
|
constructor(api: BasketAPI, basket: Basket);
|
|
25
28
|
/**
|
|
@@ -2,12 +2,14 @@ import { BasketStatus } from "../interfaces/baskets.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Basket instance class providing a fluent API for managing user baskets
|
|
4
4
|
* Provides methods for adding/removing items, updating metadata, and placing orders
|
|
5
|
+
* Supports direct property access (e.g., basket.items) for accessing data and common properties
|
|
5
6
|
*/
|
|
6
7
|
export default class BasketInstance {
|
|
7
8
|
/**
|
|
8
|
-
* Creates a new BasketInstance
|
|
9
|
+
* Creates a new BasketInstance with proxy support for direct property access
|
|
9
10
|
* @param api - The BasketAPI instance for making API calls
|
|
10
11
|
* @param basket - The basket data from the API
|
|
12
|
+
* @returns Proxied instance that allows direct access to data and common properties
|
|
11
13
|
*/
|
|
12
14
|
constructor(api, basket) {
|
|
13
15
|
this.data = basket.data;
|
|
@@ -26,6 +28,79 @@ export default class BasketInstance {
|
|
|
26
28
|
enumerable: false,
|
|
27
29
|
configurable: true
|
|
28
30
|
});
|
|
31
|
+
// Return a proxy that allows direct property access
|
|
32
|
+
return new Proxy(this, {
|
|
33
|
+
get(target, prop, receiver) {
|
|
34
|
+
// If the property exists on the instance itself, return it
|
|
35
|
+
if (prop in target) {
|
|
36
|
+
return Reflect.get(target, prop, receiver);
|
|
37
|
+
}
|
|
38
|
+
// Check data object
|
|
39
|
+
if (typeof prop === 'string' && prop in target.data) {
|
|
40
|
+
return target.data[prop];
|
|
41
|
+
}
|
|
42
|
+
// Check common object
|
|
43
|
+
if (typeof prop === 'string' && prop in target.common) {
|
|
44
|
+
return target.common[prop];
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
},
|
|
48
|
+
set(target, prop, value, receiver) {
|
|
49
|
+
// Reserved properties that should be set on the instance itself
|
|
50
|
+
const reservedProps = ['id', 'userId', 'agentId', 'data', 'common', 'metadata', 'totalAmount', 'itemCount', 'status', 'basketAPI', 'updateMetadata', 'updateStatus', 'addItem', 'removeItem', 'clear', 'placeOrder', 'toJSON'];
|
|
51
|
+
if (typeof prop === 'string' && reservedProps.includes(prop)) {
|
|
52
|
+
return Reflect.set(target, prop, value, receiver);
|
|
53
|
+
}
|
|
54
|
+
// Check if property exists in data or common, otherwise default to data
|
|
55
|
+
if (typeof prop === 'string') {
|
|
56
|
+
if (prop in target.common) {
|
|
57
|
+
target.common[prop] = value;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
target.data[prop] = value;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
},
|
|
66
|
+
has(target, prop) {
|
|
67
|
+
// Check if property exists on instance, in data, or in common
|
|
68
|
+
return prop in target || (typeof prop === 'string' && (prop in target.data || prop in target.common));
|
|
69
|
+
},
|
|
70
|
+
ownKeys(target) {
|
|
71
|
+
// Return instance keys, data keys, and common keys
|
|
72
|
+
const instanceKeys = Reflect.ownKeys(target);
|
|
73
|
+
const dataKeys = Object.keys(target.data);
|
|
74
|
+
const commonKeys = Object.keys(target.common);
|
|
75
|
+
return [...new Set([...instanceKeys, ...dataKeys, ...commonKeys])];
|
|
76
|
+
},
|
|
77
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
78
|
+
// First check if it's an instance property
|
|
79
|
+
const instanceDesc = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
80
|
+
if (instanceDesc) {
|
|
81
|
+
return instanceDesc;
|
|
82
|
+
}
|
|
83
|
+
// Then check data properties
|
|
84
|
+
if (typeof prop === 'string' && prop in target.data) {
|
|
85
|
+
return {
|
|
86
|
+
configurable: true,
|
|
87
|
+
enumerable: true,
|
|
88
|
+
writable: true,
|
|
89
|
+
value: target.data[prop]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// Then check common properties
|
|
93
|
+
if (typeof prop === 'string' && prop in target.common) {
|
|
94
|
+
return {
|
|
95
|
+
configurable: true,
|
|
96
|
+
enumerable: true,
|
|
97
|
+
writable: true,
|
|
98
|
+
value: target.common[prop]
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
29
104
|
}
|
|
30
105
|
/**
|
|
31
106
|
* Custom toJSON method to control what gets serialized when logging
|
|
@@ -3,6 +3,7 @@ import { CreateCustomDataResponse } from "../interfaces/custom.data.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Data entry instance class providing a fluent API for managing custom data entries
|
|
5
5
|
* Provides methods for updating and deleting individual data entries
|
|
6
|
+
* Supports direct property access (e.g., entry.fieldName) for accessing data properties
|
|
6
7
|
*/
|
|
7
8
|
export default class DataEntryInstance {
|
|
8
9
|
data: Record<string, any>;
|
|
@@ -10,11 +11,13 @@ export default class DataEntryInstance {
|
|
|
10
11
|
collectionName: string;
|
|
11
12
|
score?: number;
|
|
12
13
|
private customDataAPI;
|
|
14
|
+
[key: string]: any;
|
|
13
15
|
/**
|
|
14
|
-
* Creates a new DataEntryInstance
|
|
16
|
+
* Creates a new DataEntryInstance with proxy support for direct property access
|
|
15
17
|
* @param api - The CustomDataAPI instance for making API calls
|
|
16
18
|
* @param entry - The custom data entry response from the API
|
|
17
19
|
* @param collectionName - The name of the collection this entry belongs to
|
|
20
|
+
* @returns Proxied instance that allows direct access to data properties
|
|
18
21
|
*/
|
|
19
22
|
constructor(api: CustomDataAPI, entry: CreateCustomDataResponse, collectionName: string);
|
|
20
23
|
/**
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Data entry instance class providing a fluent API for managing custom data entries
|
|
3
3
|
* Provides methods for updating and deleting individual data entries
|
|
4
|
+
* Supports direct property access (e.g., entry.fieldName) for accessing data properties
|
|
4
5
|
*/
|
|
5
6
|
export default class DataEntryInstance {
|
|
6
7
|
/**
|
|
7
|
-
* Creates a new DataEntryInstance
|
|
8
|
+
* Creates a new DataEntryInstance with proxy support for direct property access
|
|
8
9
|
* @param api - The CustomDataAPI instance for making API calls
|
|
9
10
|
* @param entry - The custom data entry response from the API
|
|
10
11
|
* @param collectionName - The name of the collection this entry belongs to
|
|
12
|
+
* @returns Proxied instance that allows direct access to data properties
|
|
11
13
|
*/
|
|
12
14
|
constructor(api, entry, collectionName) {
|
|
13
15
|
this.data = entry.data;
|
|
@@ -21,6 +23,60 @@ export default class DataEntryInstance {
|
|
|
21
23
|
enumerable: false,
|
|
22
24
|
configurable: true
|
|
23
25
|
});
|
|
26
|
+
// Return a proxy that allows direct property access
|
|
27
|
+
return new Proxy(this, {
|
|
28
|
+
get(target, prop, receiver) {
|
|
29
|
+
// If the property exists on the instance itself, return it
|
|
30
|
+
if (prop in target) {
|
|
31
|
+
return Reflect.get(target, prop, receiver);
|
|
32
|
+
}
|
|
33
|
+
// Otherwise, try to get it from the data object
|
|
34
|
+
if (typeof prop === 'string' && prop in target.data) {
|
|
35
|
+
return target.data[prop];
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
},
|
|
39
|
+
set(target, prop, value, receiver) {
|
|
40
|
+
// Reserved properties that should be set on the instance itself
|
|
41
|
+
const reservedProps = ['data', 'id', 'collectionName', 'score', 'customDataAPI', 'update', 'delete', 'toJSON'];
|
|
42
|
+
if (typeof prop === 'string' && reservedProps.includes(prop)) {
|
|
43
|
+
return Reflect.set(target, prop, value, receiver);
|
|
44
|
+
}
|
|
45
|
+
// All other properties get set on the data object
|
|
46
|
+
if (typeof prop === 'string') {
|
|
47
|
+
target.data[prop] = value;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
},
|
|
52
|
+
has(target, prop) {
|
|
53
|
+
// Check if property exists on instance or in data
|
|
54
|
+
return prop in target || (typeof prop === 'string' && prop in target.data);
|
|
55
|
+
},
|
|
56
|
+
ownKeys(target) {
|
|
57
|
+
// Return both instance keys and data keys
|
|
58
|
+
const instanceKeys = Reflect.ownKeys(target);
|
|
59
|
+
const dataKeys = Object.keys(target.data);
|
|
60
|
+
return [...new Set([...instanceKeys, ...dataKeys])];
|
|
61
|
+
},
|
|
62
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
63
|
+
// First check if it's an instance property
|
|
64
|
+
const instanceDesc = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
65
|
+
if (instanceDesc) {
|
|
66
|
+
return instanceDesc;
|
|
67
|
+
}
|
|
68
|
+
// Then check if it's a data property
|
|
69
|
+
if (typeof prop === 'string' && prop in target.data) {
|
|
70
|
+
return {
|
|
71
|
+
configurable: true,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
writable: true,
|
|
74
|
+
value: target.data[prop]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
24
80
|
}
|
|
25
81
|
/**
|
|
26
82
|
* Custom toJSON method to control what gets serialized when logging
|
|
@@ -32,11 +32,21 @@ export class HttpClient {
|
|
|
32
32
|
if (response.status === 401) {
|
|
33
33
|
throw new AuthenticationError("Invalid API key");
|
|
34
34
|
}
|
|
35
|
+
// Try to parse error body as JSON
|
|
36
|
+
let errorData;
|
|
37
|
+
try {
|
|
38
|
+
errorData = await response.json();
|
|
39
|
+
}
|
|
40
|
+
catch (jsonError) {
|
|
41
|
+
errorData = {};
|
|
42
|
+
}
|
|
35
43
|
return {
|
|
36
44
|
success: false,
|
|
37
45
|
error: {
|
|
38
|
-
message: `HTTP ${response.status}: ${response.statusText}`,
|
|
46
|
+
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
39
47
|
statusCode: response.status,
|
|
48
|
+
error: errorData.error,
|
|
49
|
+
...errorData
|
|
40
50
|
},
|
|
41
51
|
};
|
|
42
52
|
}
|
|
@@ -3,6 +3,7 @@ import { OrderResponse, OrderStatus } from "../interfaces/orders.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Order instance class providing a fluent API for managing orders
|
|
5
5
|
* Provides methods for updating order status and order data
|
|
6
|
+
* Supports direct property access (e.g., order.shippingAddress) for accessing data and common properties
|
|
6
7
|
*/
|
|
7
8
|
export default class OrderInstance {
|
|
8
9
|
private data;
|
|
@@ -12,10 +13,12 @@ export default class OrderInstance {
|
|
|
12
13
|
private agentId;
|
|
13
14
|
private orderId;
|
|
14
15
|
private orderAPI;
|
|
16
|
+
[key: string]: any;
|
|
15
17
|
/**
|
|
16
|
-
* Creates a new OrderInstance
|
|
18
|
+
* Creates a new OrderInstance with proxy support for direct property access
|
|
17
19
|
* @param api - The OrderApi instance for making API calls
|
|
18
20
|
* @param order - The order response data from the API
|
|
21
|
+
* @returns Proxied instance that allows direct access to data and common properties
|
|
19
22
|
*/
|
|
20
23
|
constructor(api: OrderApi, order: OrderResponse);
|
|
21
24
|
/**
|