lua-cli 2.5.5 → 2.5.7

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.
@@ -7,6 +7,7 @@ import { readSkillConfig } from '../utils/files.js';
7
7
  import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
8
8
  import { sortVersionsByDate, promptVersionSelection, confirmDeployment, validateDeployConfig, validateVersionsAvailable, promptSkillSelection, getAvailableSkills, } from '../utils/deploy-helpers.js';
9
9
  import { fetchVersions, publishVersion } from '../utils/deploy-api.js';
10
+ import { updateSkillVersionInYaml } from '../utils/push-helpers.js';
10
11
  /**
11
12
  * Main deploy command - deploys a skill version to production.
12
13
  *
@@ -82,6 +83,12 @@ export async function deployCommand() {
82
83
  // Step 7: Publish the selected version
83
84
  writeProgress("šŸ”„ Publishing version...");
84
85
  const publishResponse = await publishVersion(apiKey, config.agent.agentId, selectedSkill.skillId, selectedVersion);
85
- writeSuccess(`āœ… Version ${publishResponse.activeVersionId} of "${selectedSkill.name}" deployed successfully`);
86
+ const deployedVersion = publishResponse.activeVersionId;
87
+ writeSuccess(`āœ… Version ${deployedVersion} of "${selectedSkill.name}" deployed successfully`);
88
+ // Step 8: Update YAML with the deployed version
89
+ if (deployedVersion !== selectedSkill.version) {
90
+ writeInfo(`šŸ“ Updating YAML with deployed version: ${deployedVersion}`);
91
+ updateSkillVersionInYaml(selectedSkill.name, deployedVersion);
92
+ }
86
93
  }, "deployment");
87
94
  }
@@ -2,11 +2,13 @@
2
2
  * Init Command
3
3
  * Orchestrates the initialization of a new Lua skill project
4
4
  */
5
+ import inquirer from 'inquirer';
5
6
  import { loadApiKey, checkApiKey } from "../services/auth.js";
6
- import { withErrorHandling, writeProgress, writeSuccess, } from "../utils/cli.js";
7
+ import { withErrorHandling, writeProgress, writeSuccess, writeInfo, writeError, } from "../utils/cli.js";
7
8
  import { promptAgentChoice, promptOrganizationSelection, promptAgentSelection, promptMetadataCollection, promptFeatureConfiguration, promptBusinessConfiguration, } from "../utils/init-prompts.js";
8
- import { fetchAgentTypes, selectBaseAgentType, createNewAgent, } from "../utils/init-agent.js";
9
+ import { fetchAgentTypes, selectBaseAgentType, createNewAgent, fetchExistingAgentDetails, } from "../utils/init-agent.js";
9
10
  import { initializeProject, installDependencies, clearLinesIfNeeded, } from "../utils/init-helpers.js";
11
+ import { readSkillYaml, updateYamlAgent } from "../utils/files.js";
10
12
  /**
11
13
  * Main init command - initializes a new Lua skill project.
12
14
  *
@@ -40,40 +42,114 @@ export async function initCommand() {
40
42
  }
41
43
  const userData = await checkApiKey(apiKey);
42
44
  writeProgress("āœ… Authenticated");
43
- // Step 2: Choose between existing or new agent
45
+ // Step 2: Check for existing YAML file
46
+ const existingYaml = readSkillYaml();
47
+ const yamlExists = existingYaml !== null;
48
+ if (yamlExists) {
49
+ const existingAgentId = existingYaml?.agent?.agentId;
50
+ if (existingAgentId) {
51
+ // Check if user has access to this agent
52
+ const hasAccess = checkUserHasAccessToAgent(userData, existingAgentId);
53
+ if (!hasAccess) {
54
+ writeError("\nāš ļø You don't have access to the agent in this project");
55
+ writeInfo(` Agent ID: ${existingAgentId}\n`);
56
+ const { action } = await inquirer.prompt([
57
+ {
58
+ type: 'list',
59
+ name: 'action',
60
+ message: 'What would you like to do?',
61
+ choices: [
62
+ { name: 'šŸ“§ Contact the agent admin to request access', value: 'contact' },
63
+ { name: 'šŸ”„ Switch to a different agent', value: 'switch' },
64
+ { name: 'āŒ Cancel', value: 'cancel' }
65
+ ]
66
+ }
67
+ ]);
68
+ if (action === 'contact') {
69
+ writeInfo("\nšŸ’” Please contact the agent administrator to grant you access.");
70
+ writeInfo(` Agent ID: ${existingAgentId}\n`);
71
+ process.exit(0);
72
+ }
73
+ if (action === 'cancel') {
74
+ writeInfo("\nāŒ Initialization cancelled.\n");
75
+ process.exit(0);
76
+ }
77
+ // User chose to switch agent - update existing YAML only
78
+ await handleAgentSwitch(userData, apiKey, existingYaml);
79
+ return;
80
+ }
81
+ else {
82
+ // User has access - ask if they want to switch anyway
83
+ writeInfo("\nšŸ“‹ Found existing project configuration");
84
+ writeInfo(` Current Agent ID: ${existingAgentId}\n`);
85
+ const { wantSwitch } = await inquirer.prompt([
86
+ {
87
+ type: 'confirm',
88
+ name: 'wantSwitch',
89
+ message: 'Do you want to switch this project to a different agent?',
90
+ default: false
91
+ }
92
+ ]);
93
+ if (wantSwitch) {
94
+ // User wants to switch agent - update existing YAML only
95
+ await handleAgentSwitch(userData, apiKey, existingYaml);
96
+ return;
97
+ }
98
+ else {
99
+ writeInfo("\nāœ… Keeping current agent configuration\n");
100
+ process.exit(0);
101
+ }
102
+ }
103
+ }
104
+ }
105
+ // Step 3: Choose between existing or new agent
44
106
  const agentChoice = await promptAgentChoice();
45
107
  let selectedAgent;
46
108
  let selectedOrg;
47
109
  let persona;
48
110
  let welcomeMessage;
111
+ let skipProjectInit = false;
49
112
  if (agentChoice === "existing") {
50
- // Step 3a: Select existing agent
51
- const result = await selectExistingAgent(userData);
113
+ // Step 4a: Select existing agent
114
+ const result = await selectExistingAgent(userData, apiKey);
52
115
  selectedAgent = result.agent;
53
116
  selectedOrg = result.org;
117
+ persona = result.persona;
118
+ welcomeMessage = result.welcomeMessage;
54
119
  }
55
120
  else {
56
- // Step 3b: Create new agent
121
+ // Step 4b: Create new agent
57
122
  const result = await createNewAgentFlow(apiKey);
58
123
  selectedAgent = result.agent;
59
124
  selectedOrg = result.org;
60
125
  persona = result.persona;
61
126
  welcomeMessage = result.welcomeMessage;
62
127
  }
63
- // Step 4: Initialize project
64
- const currentDir = initializeProject(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
65
- // Step 5: Install dependencies
66
- await installDependencies(currentDir);
67
- writeSuccess("āœ… Lua skill project initialized successfully!");
128
+ // Step 5: Initialize or update project
129
+ if (yamlExists) {
130
+ // Update existing YAML only
131
+ writeInfo("šŸ“ Updating existing lua.skill.yaml with new agent...");
132
+ updateYamlAgent(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
133
+ writeSuccess("āœ… lua.skill.yaml updated successfully!");
134
+ }
135
+ else {
136
+ // Full project initialization
137
+ const currentDir = initializeProject(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
138
+ // Step 6: Install dependencies
139
+ await installDependencies(currentDir);
140
+ writeSuccess("āœ… Lua skill project initialized successfully!");
141
+ }
68
142
  }, "initialization");
69
143
  }
70
144
  /**
71
145
  * Handles the flow for selecting an existing agent.
146
+ * Fetches the agent details from the server to get persona and welcomeMessage.
72
147
  *
73
148
  * @param userData - User's data
74
- * @returns Selected agent and organization
149
+ * @param apiKey - User's API key
150
+ * @returns Selected agent, organization, and optional persona/welcome message
75
151
  */
76
- async function selectExistingAgent(userData) {
152
+ async function selectExistingAgent(userData, apiKey) {
77
153
  // Extract organizations
78
154
  const orgs = userData.admin.orgs;
79
155
  if (!orgs || orgs.length === 0) {
@@ -83,7 +159,14 @@ async function selectExistingAgent(userData) {
83
159
  const selectedOrg = await promptOrganizationSelection(orgs);
84
160
  // Select agent from organization
85
161
  const selectedAgent = await promptAgentSelection(selectedOrg);
86
- return { agent: selectedAgent, org: selectedOrg };
162
+ // Fetch agent details to get persona and welcomeMessage
163
+ const agentDetails = await fetchExistingAgentDetails(apiKey, selectedAgent.agentId);
164
+ return {
165
+ agent: selectedAgent,
166
+ org: selectedOrg,
167
+ persona: agentDetails.persona,
168
+ welcomeMessage: agentDetails.welcomeMessage
169
+ };
87
170
  }
88
171
  /**
89
172
  * Handles the flow for creating a new agent.
@@ -115,3 +198,103 @@ async function createNewAgentFlow(apiKey) {
115
198
  const result = await createNewAgent(apiKey, selectedAgentType, businessConfig, metadata, features);
116
199
  return result;
117
200
  }
201
+ /**
202
+ * Check if user has access to a specific agent
203
+ */
204
+ function checkUserHasAccessToAgent(userData, agentId) {
205
+ const orgs = userData.admin.orgs;
206
+ for (const org of orgs) {
207
+ const agent = org.agents.find((a) => a.agentId === agentId);
208
+ if (agent) {
209
+ return true;
210
+ }
211
+ }
212
+ return false;
213
+ }
214
+ /**
215
+ * Handle switching to a different agent
216
+ */
217
+ async function handleAgentSwitch(userData, apiKey, existingYaml) {
218
+ writeInfo("\nšŸ”„ Let's switch to a different agent...\n");
219
+ // Prompt for agent choice
220
+ const agentChoice = await promptAgentChoice();
221
+ let selectedAgent;
222
+ let selectedOrg;
223
+ let persona;
224
+ let welcomeMessage;
225
+ if (agentChoice === "existing") {
226
+ // Select existing agent
227
+ const result = await selectExistingAgent(userData, apiKey);
228
+ selectedAgent = result.agent;
229
+ selectedOrg = result.org;
230
+ persona = result.persona;
231
+ welcomeMessage = result.welcomeMessage;
232
+ }
233
+ else {
234
+ // Create new agent
235
+ const result = await createNewAgentFlow(apiKey);
236
+ selectedAgent = result.agent;
237
+ selectedOrg = result.org;
238
+ persona = result.persona;
239
+ welcomeMessage = result.welcomeMessage;
240
+ }
241
+ // Ask about persona and welcome message
242
+ const finalPersona = await promptPersonaReplacement(existingYaml, persona);
243
+ const finalWelcomeMessage = await promptWelcomeMessageReplacement(existingYaml, welcomeMessage);
244
+ // Update existing YAML file with new agent
245
+ writeInfo("\nšŸ“ Updating lua.skill.yaml with new agent...");
246
+ updateYamlAgent(selectedAgent.agentId, selectedOrg.id, finalPersona, finalWelcomeMessage);
247
+ writeSuccess("āœ… lua.skill.yaml updated successfully!");
248
+ writeInfo("\nšŸ’” Your project now uses the new agent. Run 'lua compile' to update your skills.\n");
249
+ }
250
+ /**
251
+ * Prompt user about replacing existing persona
252
+ */
253
+ async function promptPersonaReplacement(existingYaml, newPersona) {
254
+ const existingPersona = existingYaml?.agent?.persona;
255
+ // If no existing persona, use new one
256
+ if (!existingPersona) {
257
+ return newPersona;
258
+ }
259
+ // If no new persona, keep existing
260
+ if (!newPersona) {
261
+ return existingPersona;
262
+ }
263
+ // Both exist - ask user
264
+ writeInfo("\nšŸ“ Persona Configuration:");
265
+ writeInfo(" Existing persona found in project");
266
+ const { replacePersona } = await inquirer.prompt([
267
+ {
268
+ type: 'confirm',
269
+ name: 'replacePersona',
270
+ message: 'Replace existing persona with the new agent\'s persona?',
271
+ default: false
272
+ }
273
+ ]);
274
+ return replacePersona ? newPersona : existingPersona;
275
+ }
276
+ /**
277
+ * Prompt user about replacing existing welcome message
278
+ */
279
+ async function promptWelcomeMessageReplacement(existingYaml, newWelcomeMessage) {
280
+ const existingWelcomeMessage = existingYaml?.agent?.welcomeMessage;
281
+ // If no existing welcome message, use new one
282
+ if (!existingWelcomeMessage) {
283
+ return newWelcomeMessage;
284
+ }
285
+ // If no new welcome message, keep existing
286
+ if (!newWelcomeMessage) {
287
+ return existingWelcomeMessage;
288
+ }
289
+ // Both exist - ask user
290
+ writeInfo(" Existing welcome message found in project");
291
+ const { replaceWelcomeMessage } = await inquirer.prompt([
292
+ {
293
+ type: 'confirm',
294
+ name: 'replaceWelcomeMessage',
295
+ message: 'Replace existing welcome message with the new agent\'s welcome message?',
296
+ default: false
297
+ }
298
+ ]);
299
+ return replaceWelcomeMessage ? newWelcomeMessage : existingWelcomeMessage;
300
+ }
@@ -160,7 +160,9 @@ function displayLogs(logs, pagination, title) {
160
160
  writeInfo("No logs found.");
161
161
  return;
162
162
  }
163
- logs.forEach((log, index) => {
163
+ // Reverse logs so latest appears at the bottom (oldest first, newest last)
164
+ const reversedLogs = [...logs].reverse();
165
+ reversedLogs.forEach((log, index) => {
164
166
  const timestamp = new Date(log.timestamp).toLocaleString();
165
167
  const icon = getLogIcon(log.subType);
166
168
  const color = getLogColor(log.subType);
@@ -179,7 +181,7 @@ function displayLogs(logs, pagination, title) {
179
181
  ? log.message.substring(0, 200) + '...'
180
182
  : log.message;
181
183
  console.log(` ${message}`);
182
- if (index < logs.length - 1) {
184
+ if (index < reversedLogs.length - 1) {
183
185
  console.log(chalk.gray(` ${'-'.repeat(78)}`));
184
186
  }
185
187
  });
@@ -85,7 +85,14 @@ export async function pushCommand() {
85
85
  writeProgress("šŸ”„ Pushing version to server...");
86
86
  const result = await pushVersion(apiKey, agentId, skillId, skillDeployData);
87
87
  if (result.success && result.data) {
88
- writeSuccess(`āœ… Version ${result.data.version} of "${selectedSkill.name}" pushed successfully`);
88
+ const pushedVersion = result.data.version;
89
+ writeSuccess(`āœ… Version ${pushedVersion} of "${selectedSkill.name}" pushed successfully`);
90
+ // Update YAML with the version returned from server (in case it's different)
91
+ if (pushedVersion !== selectedSkill.version) {
92
+ writeInfo(`šŸ“ Updating YAML with server version: ${pushedVersion}`);
93
+ updateSkillVersionInYaml(selectedSkill.name, pushedVersion);
94
+ selectedSkill.version = pushedVersion;
95
+ }
89
96
  // Ask if user wants to deploy now
90
97
  const deployAnswer = await safePrompt([
91
98
  {
@@ -96,7 +103,7 @@ export async function pushCommand() {
96
103
  }
97
104
  ]);
98
105
  if (deployAnswer && deployAnswer.deployNow) {
99
- await deployVersionAfterPush(apiKey, config.agent.agentId, selectedSkill, result.data.version);
106
+ await deployVersionAfterPush(apiKey, config.agent.agentId, selectedSkill, pushedVersion);
100
107
  }
101
108
  }
102
109
  else if (result.error) {
@@ -145,6 +152,9 @@ async function deployVersionAfterPush(apiKey, agentId, selectedSkill, pushedVers
145
152
  writeProgress("šŸ”„ Publishing version...");
146
153
  const publishResponse = await publishVersion(apiKey, agentId, selectedSkill.skillId, pushedVersion);
147
154
  writeSuccess(`\nāœ… Version ${pushedVersion} of "${selectedSkill.name}" deployed successfully to production\n`);
155
+ // Update YAML with deployed version (should already be updated from push, but ensure consistency)
156
+ writeInfo(`šŸ“ Ensuring YAML is updated with deployed version: ${pushedVersion}`);
157
+ updateSkillVersionInYaml(selectedSkill.name, pushedVersion);
148
158
  }
149
159
  catch (error) {
150
160
  console.error('\nāŒ Error deploying version:', error);
@@ -12,15 +12,16 @@ export default class BasketInstance {
12
12
  * @returns Proxied instance that allows direct access to data and common properties
13
13
  */
14
14
  constructor(api, basket) {
15
- this.data = basket.data;
16
- this.common = basket.common;
15
+ // Ensure data and common are always objects, never null or undefined
16
+ this.data = basket.data && typeof basket.data === 'object' ? basket.data : {};
17
+ this.common = basket.common && typeof basket.common === 'object' ? basket.common : {};
17
18
  this.id = basket.id;
18
19
  this.userId = basket.userId;
19
20
  this.agentId = basket.agentId;
20
- this.metadata = basket.data.metadata;
21
- this.totalAmount = basket.common.totalAmount;
22
- this.itemCount = basket.common.itemCount;
23
- this.status = basket.common.status;
21
+ this.metadata = basket.data?.metadata || {};
22
+ this.totalAmount = basket.common?.totalAmount || 0;
23
+ this.itemCount = basket.common?.itemCount || 0;
24
+ this.status = basket.common?.status || BasketStatus.ACTIVE;
24
25
  // Make basketAPI non-enumerable so it doesn't show up in console.log
25
26
  Object.defineProperty(this, 'basketAPI', {
26
27
  value: api,
@@ -35,12 +36,12 @@ export default class BasketInstance {
35
36
  if (prop in target) {
36
37
  return Reflect.get(target, prop, receiver);
37
38
  }
38
- // Check data object
39
- if (typeof prop === 'string' && prop in target.data) {
39
+ // Check data object (with null check)
40
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object' && prop in target.data) {
40
41
  return target.data[prop];
41
42
  }
42
- // Check common object
43
- if (typeof prop === 'string' && prop in target.common) {
43
+ // Check common object (with null check)
44
+ if (typeof prop === 'string' && target.common && typeof target.common === 'object' && prop in target.common) {
44
45
  return target.common[prop];
45
46
  }
46
47
  return undefined;
@@ -53,6 +54,13 @@ export default class BasketInstance {
53
54
  }
54
55
  // Check if property exists in data or common, otherwise default to data
55
56
  if (typeof prop === 'string') {
57
+ // Initialize objects if they don't exist
58
+ if (!target.data || typeof target.data !== 'object') {
59
+ target.data = {};
60
+ }
61
+ if (!target.common || typeof target.common !== 'object') {
62
+ target.common = {};
63
+ }
56
64
  if (prop in target.common) {
57
65
  target.common[prop] = value;
58
66
  }
@@ -64,14 +72,25 @@ export default class BasketInstance {
64
72
  return false;
65
73
  },
66
74
  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));
75
+ // Check if property exists on instance, in data, or in common (with null checks)
76
+ if (prop in target) {
77
+ return true;
78
+ }
79
+ if (typeof prop === 'string') {
80
+ if (target.data && typeof target.data === 'object' && prop in target.data) {
81
+ return true;
82
+ }
83
+ if (target.common && typeof target.common === 'object' && prop in target.common) {
84
+ return true;
85
+ }
86
+ }
87
+ return false;
69
88
  },
70
89
  ownKeys(target) {
71
- // Return instance keys, data keys, and common keys
90
+ // Return instance keys, data keys, and common keys (with null checks)
72
91
  const instanceKeys = Reflect.ownKeys(target);
73
- const dataKeys = Object.keys(target.data);
74
- const commonKeys = Object.keys(target.common);
92
+ const dataKeys = target.data && typeof target.data === 'object' ? Object.keys(target.data) : [];
93
+ const commonKeys = target.common && typeof target.common === 'object' ? Object.keys(target.common) : [];
75
94
  return [...new Set([...instanceKeys, ...dataKeys, ...commonKeys])];
76
95
  },
77
96
  getOwnPropertyDescriptor(target, prop) {
@@ -80,8 +99,8 @@ export default class BasketInstance {
80
99
  if (instanceDesc) {
81
100
  return instanceDesc;
82
101
  }
83
- // Then check data properties
84
- if (typeof prop === 'string' && prop in target.data) {
102
+ // Then check data properties (with null check)
103
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object' && prop in target.data) {
85
104
  return {
86
105
  configurable: true,
87
106
  enumerable: true,
@@ -89,8 +108,8 @@ export default class BasketInstance {
89
108
  value: target.data[prop]
90
109
  };
91
110
  }
92
- // Then check common properties
93
- if (typeof prop === 'string' && prop in target.common) {
111
+ // Then check common properties (with null check)
112
+ if (typeof prop === 'string' && target.common && typeof target.common === 'object' && prop in target.common) {
94
113
  return {
95
114
  configurable: true,
96
115
  enumerable: true,
@@ -12,7 +12,8 @@ export default class DataEntryInstance {
12
12
  * @returns Proxied instance that allows direct access to data properties
13
13
  */
14
14
  constructor(api, entry, collectionName) {
15
- this.data = entry.data;
15
+ // Ensure data is always an object, never null or undefined
16
+ this.data = entry.data && typeof entry.data === 'object' ? entry.data : {};
16
17
  this.id = entry.id;
17
18
  this.collectionName = collectionName;
18
19
  this.score = entry.score;
@@ -30,8 +31,8 @@ export default class DataEntryInstance {
30
31
  if (prop in target) {
31
32
  return Reflect.get(target, prop, receiver);
32
33
  }
33
- // Otherwise, try to get it from the data object
34
- if (typeof prop === 'string' && prop in target.data) {
34
+ // Otherwise, try to get it from the data object (with null check)
35
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object' && prop in target.data) {
35
36
  return target.data[prop];
36
37
  }
37
38
  return undefined;
@@ -44,19 +45,29 @@ export default class DataEntryInstance {
44
45
  }
45
46
  // All other properties get set on the data object
46
47
  if (typeof prop === 'string') {
48
+ // Initialize data object if it doesn't exist
49
+ if (!target.data || typeof target.data !== 'object') {
50
+ target.data = {};
51
+ }
47
52
  target.data[prop] = value;
48
53
  return true;
49
54
  }
50
55
  return false;
51
56
  },
52
57
  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);
58
+ // Check if property exists on instance or in data (with null check)
59
+ if (prop in target) {
60
+ return true;
61
+ }
62
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object') {
63
+ return prop in target.data;
64
+ }
65
+ return false;
55
66
  },
56
67
  ownKeys(target) {
57
- // Return both instance keys and data keys
68
+ // Return both instance keys and data keys (with null check)
58
69
  const instanceKeys = Reflect.ownKeys(target);
59
- const dataKeys = Object.keys(target.data);
70
+ const dataKeys = target.data && typeof target.data === 'object' ? Object.keys(target.data) : [];
60
71
  return [...new Set([...instanceKeys, ...dataKeys])];
61
72
  },
62
73
  getOwnPropertyDescriptor(target, prop) {
@@ -65,8 +76,8 @@ export default class DataEntryInstance {
65
76
  if (instanceDesc) {
66
77
  return instanceDesc;
67
78
  }
68
- // Then check if it's a data property
69
- if (typeof prop === 'string' && prop in target.data) {
79
+ // Then check if it's a data property (with null check)
80
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object' && prop in target.data) {
70
81
  return {
71
82
  configurable: true,
72
83
  enumerable: true,
@@ -11,8 +11,9 @@ export default class OrderInstance {
11
11
  * @returns Proxied instance that allows direct access to data and common properties
12
12
  */
13
13
  constructor(api, order) {
14
- this.data = order.data;
15
- this.common = order.common;
14
+ // Ensure data and common are always objects, never null or undefined
15
+ this.data = order.data && typeof order.data === 'object' ? order.data : {};
16
+ this.common = order.common && typeof order.common === 'object' ? order.common : {};
16
17
  this.id = order.id;
17
18
  this.userId = order.userId;
18
19
  this.agentId = order.agentId;
@@ -31,12 +32,12 @@ export default class OrderInstance {
31
32
  if (prop in target) {
32
33
  return Reflect.get(target, prop, receiver);
33
34
  }
34
- // Check data object
35
- if (typeof prop === 'string' && prop in target.data) {
35
+ // Check data object (with null check)
36
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object' && prop in target.data) {
36
37
  return target.data[prop];
37
38
  }
38
- // Check common object
39
- if (typeof prop === 'string' && prop in target.common) {
39
+ // Check common object (with null check)
40
+ if (typeof prop === 'string' && target.common && typeof target.common === 'object' && prop in target.common) {
40
41
  return target.common[prop];
41
42
  }
42
43
  return undefined;
@@ -49,6 +50,13 @@ export default class OrderInstance {
49
50
  }
50
51
  // Check if property exists in data or common, otherwise default to data
51
52
  if (typeof prop === 'string') {
53
+ // Initialize objects if they don't exist
54
+ if (!target.data || typeof target.data !== 'object') {
55
+ target.data = {};
56
+ }
57
+ if (!target.common || typeof target.common !== 'object') {
58
+ target.common = {};
59
+ }
52
60
  if (prop in target.common) {
53
61
  target.common[prop] = value;
54
62
  }
@@ -60,14 +68,25 @@ export default class OrderInstance {
60
68
  return false;
61
69
  },
62
70
  has(target, prop) {
63
- // Check if property exists on instance, in data, or in common
64
- return prop in target || (typeof prop === 'string' && (prop in target.data || prop in target.common));
71
+ // Check if property exists on instance, in data, or in common (with null checks)
72
+ if (prop in target) {
73
+ return true;
74
+ }
75
+ if (typeof prop === 'string') {
76
+ if (target.data && typeof target.data === 'object' && prop in target.data) {
77
+ return true;
78
+ }
79
+ if (target.common && typeof target.common === 'object' && prop in target.common) {
80
+ return true;
81
+ }
82
+ }
83
+ return false;
65
84
  },
66
85
  ownKeys(target) {
67
- // Return instance keys, data keys, and common keys
86
+ // Return instance keys, data keys, and common keys (with null checks)
68
87
  const instanceKeys = Reflect.ownKeys(target);
69
- const dataKeys = Object.keys(target.data);
70
- const commonKeys = Object.keys(target.common);
88
+ const dataKeys = target.data && typeof target.data === 'object' ? Object.keys(target.data) : [];
89
+ const commonKeys = target.common && typeof target.common === 'object' ? Object.keys(target.common) : [];
71
90
  return [...new Set([...instanceKeys, ...dataKeys, ...commonKeys])];
72
91
  },
73
92
  getOwnPropertyDescriptor(target, prop) {
@@ -76,8 +95,8 @@ export default class OrderInstance {
76
95
  if (instanceDesc) {
77
96
  return instanceDesc;
78
97
  }
79
- // Then check data properties
80
- if (typeof prop === 'string' && prop in target.data) {
98
+ // Then check data properties (with null check)
99
+ if (typeof prop === 'string' && target.data && typeof target.data === 'object' && prop in target.data) {
81
100
  return {
82
101
  configurable: true,
83
102
  enumerable: true,
@@ -85,8 +104,8 @@ export default class OrderInstance {
85
104
  value: target.data[prop]
86
105
  };
87
106
  }
88
- // Then check common properties
89
- if (typeof prop === 'string' && prop in target.common) {
107
+ // Then check common properties (with null check)
108
+ if (typeof prop === 'string' && target.common && typeof target.common === 'object' && prop in target.common) {
90
109
  return {
91
110
  configurable: true,
92
111
  enumerable: true,