abap-local-client 1.4.0 → 1.4.2

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/config-cli.mjs CHANGED
@@ -87,6 +87,10 @@ Usage:
87
87
  node config-cli.mjs show-config
88
88
  Show the full configuration (API key and passwords REDACTED).
89
89
 
90
+ node config-cli.mjs set-username <systemId> <sapUser>
91
+ Set the SAP username for a system (required for SNC connections).
92
+ Example: node config-cli.mjs set-username S4D FGALASTRI
93
+
90
94
  node config-cli.mjs arcanum-fallback <on|off>
91
95
  Enable or disable Arcanum fallback for unknown system IDs.
92
96
 
@@ -304,6 +308,26 @@ switch (command) {
304
308
  break;
305
309
  }
306
310
 
311
+ // ── set-username ────────────────────────────────────────────────────────
312
+ case 'set-username': {
313
+ const systemId = args[1];
314
+ const username = args[2];
315
+ if (!systemId || !username) {
316
+ console.error('Usage: node config-cli.mjs set-username <systemId> <sapUser>');
317
+ console.error(' Example: node config-cli.mjs set-username S4D FGALASTRI');
318
+ process.exit(1);
319
+ }
320
+ const sys = config.getSystem(systemId);
321
+ if (!sys) {
322
+ console.error(`System "${systemId}" not found. Run list-systems to see configured systems.`);
323
+ process.exit(1);
324
+ }
325
+ sys.connection = { ...(sys.connection || {}), username: username.toUpperCase() };
326
+ config.addOrUpdateSystem(systemId, sys);
327
+ console.log(`✅ Username for "${systemId}" set to: ${username.toUpperCase()}`);
328
+ break;
329
+ }
330
+
307
331
  // ── set-ws-url ──────────────────────────────────────────────────────────
308
332
  case 'set-ws-url': {
309
333
  const url = args[1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abap-local-client",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "SAP Local Client — WebSocket bridge with Basic, SPNEGO, X.509, SAML & SNC authentication",
5
5
  "main": "sso-sap-client.mjs",
6
6
  "type": "module",
@@ -16,6 +16,11 @@ import * as config from './config-manager.mjs';
16
16
  try { process.loadEnvFile?.(); } catch {}
17
17
  const env = process.env;
18
18
 
19
+ /** Resolve the SAP username from connection config. For SNC, set conn.username explicitly. */
20
+ function resolveUsername(conn) {
21
+ return (conn.username || '').toUpperCase();
22
+ }
23
+
19
24
  // ════════════════════════════════════════════════════════════════════════════
20
25
  // Multi-system auth session cache
21
26
  // ════════════════════════════════════════════════════════════════════════════
@@ -63,13 +68,22 @@ async function _createSession(resolvedId) {
63
68
  let useRfc = (authMode === 'snc' || hasSaprouter);
64
69
 
65
70
  if (useRfc) {
66
- console.log(` 🛰️ RFC mode (no HTTP)`);
67
- rfcClient = new SAPRFCClient({
71
+ console.log(` 🛰️ RFC mode (${authMode === 'snc' ? 'SNC' : 'Basic'})`);
72
+ const rfcParams = {
68
73
  host: conn.host, sysnr: conn.sysnr || '00',
69
74
  client: conn.client || '100', username: conn.username || '',
70
75
  password: conn.password || '', language: conn.language || 'EN',
71
76
  saprouter: conn.saprouter || '',
72
- });
77
+ };
78
+ if (authMode === 'snc') {
79
+ rfcParams.sncMode = '1';
80
+ if (conn.sncPartnerName) rfcParams.sncPartnerName = conn.sncPartnerName;
81
+ if (conn.sncMyName) rfcParams.sncMyName = conn.sncMyName;
82
+ if (conn.sncQop) rfcParams.sncQop = conn.sncQop;
83
+ if (conn.sncLib) rfcParams.sncLib = conn.sncLib;
84
+ console.log(` 🔐 SNC partner: ${conn.sncPartnerName || '(not set)'}`);
85
+ }
86
+ rfcClient = new SAPRFCClient(rfcParams);
73
87
  try {
74
88
  await rfcClient.connect();
75
89
  console.log(` ✅ RFC connection established`);
@@ -85,8 +99,8 @@ async function _createSession(resolvedId) {
85
99
  conn.username || '', conn.password || '',
86
100
  { language: conn.language || 'EN' });
87
101
  await httpSession.init();
88
- } else if (!useRfc && authMode === 'snc') {
89
- throw new Error(`Auth mode not yet implemented: ${authMode}`);
102
+ } else if (!useRfc) {
103
+ throw new Error(`RFC connection required for auth mode "${authMode}" but failed to connect`);
90
104
  }
91
105
 
92
106
  return { useRfc, rfcClient, httpSession, authMode, sysConfig, resolvedId };
@@ -394,7 +408,7 @@ class SAPClient {
394
408
  if (typeof body === 'string') {
395
409
  const lang = conn.language || 'EN';
396
410
  const client = conn.client || '100';
397
- const user = (conn.username || '').toUpperCase();
411
+ const user = resolveUsername(conn);
398
412
  body = body
399
413
  .replace(/<SAP_LANGUAGE>/g, lang)
400
414
  .replace(/<SAP_CLIENT>/g, client)
@@ -466,7 +480,7 @@ class SAPClient {
466
480
  if (typeof rawBody === 'string') {
467
481
  const conn2 = this.session?.sysConfig?.connection || {};
468
482
  const lang2 = conn2.language || 'EN';
469
- const user2 = (conn2.username || '').toUpperCase();
483
+ const user2 = resolveUsername(conn2);
470
484
  rawBody = rawBody
471
485
  .replace(/<SAP_LANGUAGE>/g, lang2)
472
486
  .replace(/<SAP_CLIENT>/g, conn2.client || '100')
@@ -644,7 +658,8 @@ class WebSocketClient {
644
658
  if (!sys) { this.sendResponse(requestId, false, { error: `Unknown system: ${sid}` }); return; }
645
659
  this.currentSystemId = sid;
646
660
  this.lockManager.clearAll();
647
- await this.initSapClient();
661
+ const ok = await this.initSapClient();
662
+ if (!ok) { this.sendResponse(requestId, false, { error: `Failed to connect to ${sid}. Check RFC/SNC config and logs.` }); return; }
648
663
  this.sendResponse(requestId, true, [{ success: true, data: { system: sid, authMode: sys.authMode } }]);
649
664
  return;
650
665
  }