n8n-nodes-amis-v1 0.1.5 → 0.1.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.
@@ -132,8 +132,9 @@ class MisaAmis {
132
132
  // 1. Load Session
133
133
  const credentials = await this.getCredentials('misaAmisUser');
134
134
  const userIdentity = credentials.userIdentity;
135
+ const safeIdentity = userIdentity.replace(/[^a-z0-9]/gi, '_').toLowerCase();
135
136
  const n8nDir = process.env.N8N_USER_FOLDER || path.join(os.homedir(), '.n8n');
136
- const sessionFilePath = path.join(n8nDir, 'misa_sessions', `${userIdentity}.json`);
137
+ const sessionFilePath = path.join(n8nDir, 'misa_sessions', `${safeIdentity}.json`);
137
138
  if (!fs.existsSync(sessionFilePath)) {
138
139
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Session file not found for user: ${userIdentity}. Please run Login Node first.`);
139
140
  }
@@ -99,19 +99,7 @@ class MisaAmisLogin {
99
99
  },
100
100
  },
101
101
  },
102
- {
103
- displayName: 'Request ID',
104
- name: 'requestId',
105
- type: 'string',
106
- default: '',
107
- required: true,
108
- displayOptions: {
109
- show: {
110
- operation: ['checkLogin'],
111
- },
112
- },
113
- description: 'The CDRequestId returned from "Generate QR" step',
114
- },
102
+ // Removed requestId and cookieJar inputs because we use file-based state
115
103
  ],
116
104
  };
117
105
  }
@@ -120,11 +108,20 @@ class MisaAmisLogin {
120
108
  const returnData = [];
121
109
  const operation = this.getNodeParameter('operation', 0);
122
110
  const userIdentity = this.getNodeParameter('userIdentity', 0);
111
+ const safeIdentity = userIdentity.replace(/[^a-z0-9]/gi, '_').toLowerCase();
123
112
  const n8nDir = process.env.N8N_USER_FOLDER || path.join(os.homedir(), '.n8n');
124
113
  const storagePath = path.join(n8nDir, 'misa_sessions');
125
- if (!fs.existsSync(storagePath)) {
126
- fs.mkdirSync(storagePath, { recursive: true });
114
+ try {
115
+ if (!fs.existsSync(storagePath)) {
116
+ fs.mkdirSync(storagePath, { recursive: true });
117
+ }
118
+ }
119
+ catch (error) {
120
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to create storage directory '${storagePath}': ${error.message}. Please check permissions.`);
127
121
  }
122
+ // File paths
123
+ const sessionFilePath = path.join(storagePath, `${safeIdentity}.json`);
124
+ const pendingFilePath = path.join(storagePath, `${safeIdentity}.pending.json`);
128
125
  const clientId = '6bcbc4d1-5426-42f7-bc61-69cac2e229f4';
129
126
  const headers = {
130
127
  'Content-Type': 'application/json',
@@ -155,11 +152,19 @@ class MisaAmisLogin {
155
152
  const cdRequestId = genQrRes.data.CDRequestId;
156
153
  const qrContent = `https://amisapp.misa.vn/shared?app=qrlogin&qrid=${cdRequestId}&domain=amisapp.misa.vn`;
157
154
  const qrBuffer = await qrcode_1.default.toBuffer(qrContent);
155
+ // SAVE PENDING STATE
156
+ const serializedJar = await jar.serialize();
157
+ const pendingState = {
158
+ requestId: cdRequestId,
159
+ cookieJar: serializedJar,
160
+ timestamp: Date.now()
161
+ };
162
+ fs.writeFileSync(pendingFilePath, JSON.stringify(pendingState, null, 2));
158
163
  returnData.push({
159
164
  json: {
160
- message: "QR Generated. Scan it and then use 'Check Login' step.",
165
+ message: "QR Generated. Please Scan. Pending session saved.",
166
+ userIdentity: userIdentity,
161
167
  requestId: cdRequestId,
162
- clientId: clientId,
163
168
  qrContent: qrContent
164
169
  },
165
170
  binary: {
@@ -173,16 +178,31 @@ class MisaAmisLogin {
173
178
  }
174
179
  else if (operation === 'checkLogin') {
175
180
  // --- Operation: Check Login ---
176
- const cdRequestId = this.getNodeParameter('requestId', 0);
177
- const sessionFilePath = path.join(storagePath, `${userIdentity}.json`);
181
+ // READ PENDING STATE
182
+ if (!fs.existsSync(pendingFilePath)) {
183
+ const allFiles = fs.readdirSync(storagePath);
184
+ const pendingFiles = allFiles.filter(f => f.endsWith('.pending.json'));
185
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No pending login found for user '${userIdentity}'. Path: ${pendingFilePath}. Available pending sessions: ${pendingFiles.join(', ')}`);
186
+ }
187
+ const pendingState = JSON.parse(fs.readFileSync(pendingFilePath, 'utf8'));
188
+ const cdRequestId = pendingState.requestId;
189
+ // Restore Cookies
190
+ if (pendingState.cookieJar) {
191
+ const deserialized = await tough_cookie_1.CookieJar.deserialize(pendingState.cookieJar);
192
+ await jar.removeAllCookies();
193
+ for (const cookie of await deserialized.getCookies('https://id.misa.vn')) {
194
+ await jar.setCookie(cookie, 'https://id.misa.vn');
195
+ }
196
+ }
178
197
  let pollingSuccess = false;
179
198
  let attempts = 0;
180
- const maxAttempts = 60; // 2 minutes (2s interval)
199
+ const maxAttempts = 60; // 2 minutes
181
200
  while (!pollingSuccess && attempts < maxAttempts) {
182
201
  attempts++;
183
202
  await new Promise(resolve => setTimeout(resolve, 2000));
184
203
  try {
185
204
  const pollUrl = `https://id.misa.vn/api/login-cross-device/v2/polling?cdRequestId=${cdRequestId}&clientId=${clientId}&deviceId=${clientId}`;
205
+ console.log(`[MISA Debug] Polling Attempt ${attempts}: ${pollUrl}`);
186
206
  const pollRes = await client.get(pollUrl, { headers });
187
207
  if (JSON.stringify(pollRes.data).includes("Success") || JSON.stringify(pollRes.data).includes("v1/auth/token")) {
188
208
  pollingSuccess = true;
@@ -190,15 +210,19 @@ class MisaAmisLogin {
190
210
  }
191
211
  catch (error) {
192
212
  if (error.response && error.response.status >= 400 && error.response.status < 500) {
193
- // Client Error (400/404) -> Request ID invalid or expired
194
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Polling Error ${error.response.status}: ${JSON.stringify(error.response.data)}. Please Generate QR again.`);
213
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Polling Error: ${JSON.stringify(error.response.data)}. Please Generate QR again.`);
195
214
  }
196
- // Ignore server errors or network glitches (retry)
197
215
  }
198
216
  }
199
217
  if (pollingSuccess) {
218
+ // Save FINAL Session
200
219
  const serializedJar = await jar.serialize();
201
220
  fs.writeFileSync(sessionFilePath, JSON.stringify(serializedJar, null, 2));
221
+ // Cleanup Pending
222
+ try {
223
+ fs.unlinkSync(pendingFilePath);
224
+ }
225
+ catch (e) { }
202
226
  returnData.push({
203
227
  json: {
204
228
  message: "Login Successful",
@@ -208,7 +232,7 @@ class MisaAmisLogin {
208
232
  });
209
233
  }
210
234
  else {
211
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Login timeout or failed. Please scan QR Code again.');
235
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Login timeout. Please scan QR Code again.');
212
236
  }
213
237
  }
214
238
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-amis-v1",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "n8n node for AMIS v1",
5
5
  "keywords": [
6
6
  "n8n-community-node-package"