@mcp-abap-adt/core 4.6.0 → 4.7.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/CHANGELOG.md +5 -0
- package/dist/lib/config/ServerConfigManager.js +1 -1
- package/dist/server/launcher.js +1 -1
- package/docs/installation/RFC_SETUP.md +6 -6
- package/docs/roadmaps/LEGACY_SUPPORT.md +2 -2
- package/docs/superpowers/plans/2026-04-01-sap-rfc-lite.md +848 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [4.7.0] - 2026-04-01
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Replace archived `node-rfc` with `@mcp-abap-adt/sap-rfc-lite` — a lightweight maintained fork with the same API surface. This change only affects RFC connections to legacy SAP systems (BASIS < 7.50). HTTP connections are not affected. If you experience issues with legacy RFC connections, please open an issue and downgrade to v4.6.0.
|
|
9
|
+
|
|
5
10
|
## [4.6.0] - 2026-03-31
|
|
6
11
|
|
|
7
12
|
### Added
|
|
@@ -234,7 +234,7 @@ AUTHENTICATION:
|
|
|
234
234
|
--mcp=<destination> Default MCP destination name (for auth-broker mode)
|
|
235
235
|
Example: --mcp=TRIAL
|
|
236
236
|
--connection-type=<type> SAP connection type: http (default) or rfc
|
|
237
|
-
RFC requires SAP NW RFC SDK +
|
|
237
|
+
RFC requires SAP NW RFC SDK + @mcp-abap-adt/sap-rfc-lite installed
|
|
238
238
|
Alternative: SAP_CONNECTION_TYPE env var in .env
|
|
239
239
|
--system-type=<type> SAP system type: cloud (default) | onprem | legacy
|
|
240
240
|
Controls which tools are available
|
package/dist/server/launcher.js
CHANGED
|
@@ -159,7 +159,7 @@ SAP CONNECTION (.env file):
|
|
|
159
159
|
SAP_USERNAME SAP username
|
|
160
160
|
SAP_PASSWORD SAP password
|
|
161
161
|
SAP_CLIENT SAP client number
|
|
162
|
-
Requires: SAP NW RFC SDK +
|
|
162
|
+
Requires: SAP NW RFC SDK + @mcp-abap-adt/sap-rfc-lite package installed
|
|
163
163
|
|
|
164
164
|
System Context (on-premise):
|
|
165
165
|
SAP_MASTER_SYSTEM SAP system ID (e.g., DEV, QAS). Required for on-prem
|
|
@@ -40,18 +40,18 @@ export PATH=$SAPNWRFC_HOME/lib:$PATH
|
|
|
40
40
|
export LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib:${LD_LIBRARY_PATH:-}
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
### 3.
|
|
43
|
+
### 3. @mcp-abap-adt/sap-rfc-lite Package
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install
|
|
46
|
+
npm install @mcp-abap-adt/sap-rfc-lite
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
`node-rfc` is loaded dynamically at runtime — it is not a declared dependency.
|
|
49
|
+
`@mcp-abap-adt/sap-rfc-lite` is a lightweight fork of the archived `node-rfc` package, containing only the API surface needed for ADT RFC connections. It is loaded dynamically at runtime — it is not a declared dependency.
|
|
50
50
|
|
|
51
51
|
Verify installation:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
node -e "try { require('
|
|
54
|
+
node -e "try { require('@mcp-abap-adt/sap-rfc-lite'); console.log('OK'); } catch(e) { console.log(e.message); }"
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### 4. SAP Authorization
|
|
@@ -83,13 +83,13 @@ SAP_CONNECTION_TYPE=rfc
|
|
|
83
83
|
|
|
84
84
|
## Troubleshooting
|
|
85
85
|
|
|
86
|
-
### "
|
|
86
|
+
### "@mcp-abap-adt/sap-rfc-lite is not available"
|
|
87
87
|
|
|
88
88
|
SAP NW RFC SDK is not installed or not in PATH. Check:
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
91
|
echo $SAPNWRFC_HOME
|
|
92
|
-
node -e "require('
|
|
92
|
+
node -e "require('@mcp-abap-adt/sap-rfc-lite')"
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
### "The specified module could not be found: sapnwrfc.node"
|
|
@@ -89,7 +89,7 @@ if (process.env.SAP_AUTH_TYPE === 'rfc') {
|
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
`createAbapConnection()` from connection package already handles `authType: 'rfc'`.
|
|
92
|
-
|
|
92
|
+
`@mcp-abap-adt/sap-rfc-lite` is loaded dynamically — no error if not installed and not used.
|
|
93
93
|
|
|
94
94
|
### Step 5: Launcher CLI support [DONE]
|
|
95
95
|
|
|
@@ -155,7 +155,7 @@ The [abapfs_extensions](https://github.com/marcellourbani/abapfs_extensions) pro
|
|
|
155
155
|
|
|
156
156
|
| Risk | Mitigation |
|
|
157
157
|
|------|-----------|
|
|
158
|
-
|
|
|
158
|
+
| @mcp-abap-adt/sap-rfc-lite needs SAP NW RFC SDK native lib | Dynamic import; graceful error if not installed; only loaded for `connectionType: 'rfc'` |
|
|
159
159
|
| Docker images need SDK | Document; provide Dockerfile with SDK layer |
|
|
160
160
|
| Legacy endpoint differences between versions | Discovery-based detection, not hardcoded |
|
|
161
161
|
| One extra HTTP call at startup (core/discovery) | Cached, happens once |
|
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
# SAP RFC Lite — Lightweight node-rfc Fork
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Create a minimal, maintainable Node.js native addon that wraps SAP NW RFC SDK — replacing the archived `node-rfc` package with only the API surface we actually use.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Fork and strip `node-rfc` (Apache-2.0) down to a single `Client` class with `open()`, `call()`, `close()`, and `alive`. Remove Pool, Server, Throughput, and all unused client methods. Keep the full data type marshalling layer (nwrfcsdk.cc) since SAP FM parameter types are determined at runtime by the SDK.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** C++17, Node-Addon-API (N-API v8), node-gyp, TypeScript, SAP NW RFC SDK
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## File Structure
|
|
14
|
+
|
|
15
|
+
### New package: `sap-rfc-lite/`
|
|
16
|
+
|
|
17
|
+
Location: `/home/okyslytsia/prj/sap-rfc-lite/` (separate repo, publishable to npm)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
sap-rfc-lite/
|
|
21
|
+
├── package.json
|
|
22
|
+
├── tsconfig.json
|
|
23
|
+
├── binding.gyp
|
|
24
|
+
├── LICENSE # Apache-2.0 (from node-rfc)
|
|
25
|
+
├── NOTICE # Attribution to original SAP authors
|
|
26
|
+
├── src/
|
|
27
|
+
│ ├── cpp/
|
|
28
|
+
│ │ ├── addon.cc # Entry point (Client only, no Pool/Server/Throughput)
|
|
29
|
+
│ │ ├── Client.cc # Client: Open, Close, Invoke, AliveGetter, connectionCheck
|
|
30
|
+
│ │ ├── Client.h # Client class header (no Pool friend, no Pool*)
|
|
31
|
+
│ │ ├── nwrfcsdk.cc # Full data type marshalling (keep all types)
|
|
32
|
+
│ │ ├── nwrfcsdk.h # Types/structs (remove Pool/Server refs)
|
|
33
|
+
│ │ └── noderfc.h # Constants (remove Pool/Server constants)
|
|
34
|
+
│ └── ts/
|
|
35
|
+
│ ├── index.ts # Exports: Client, types
|
|
36
|
+
│ ├── client.ts # Client class (Promise-only, no callback API)
|
|
37
|
+
│ ├── binding.ts # Native addon loader
|
|
38
|
+
│ └── types.ts # Minimal type definitions
|
|
39
|
+
├── test/
|
|
40
|
+
│ ├── client.test.ts # Unit tests (mocked native binding)
|
|
41
|
+
│ └── integration.test.ts # Integration test (requires SAP NW RFC SDK)
|
|
42
|
+
└── .github/
|
|
43
|
+
└── workflows/
|
|
44
|
+
└── build.yml # CI: lint + typecheck (no SDK on CI)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Files removed vs node-rfc
|
|
48
|
+
|
|
49
|
+
| Removed file | Reason |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `Pool.cc/h` (747+85 LOC) | Connection pooling not used |
|
|
52
|
+
| `Server.cc/h` (634+144 LOC) | RFC inbound server not used |
|
|
53
|
+
| `server_api.cc/h` (814+229 LOC) | Server API not used |
|
|
54
|
+
| `Throughput.cc/h` (196+53 LOC) | Performance monitoring not used |
|
|
55
|
+
| `Log.cc/h` (57+142 LOC) | Replace with minimal stderr logging |
|
|
56
|
+
| `ext/date.h` | Only used by Log.h for formatting |
|
|
57
|
+
| `sapnwrfc-pool.ts` | Pool class |
|
|
58
|
+
| `sapnwrfc-server.ts` | Server class |
|
|
59
|
+
| `sapnwrfc-throughput.ts` | Throughput class |
|
|
60
|
+
|
|
61
|
+
**Reduction:** ~2,902 lines of C++ removed (Pool+Server+server_api+Throughput+Log). ~600 lines C++ remain (Client+addon). nwrfcsdk.cc (1,158 lines) kept intact — types are determined at runtime, removing "unused" ones would cause crashes.
|
|
62
|
+
|
|
63
|
+
### Dependencies
|
|
64
|
+
|
|
65
|
+
**Keep:**
|
|
66
|
+
- `node-addon-api` ^6.1.0 — N-API C++ wrapper
|
|
67
|
+
- `node-gyp-build` ^4.6.0 — native module loader
|
|
68
|
+
|
|
69
|
+
**Remove:**
|
|
70
|
+
- `bluebird` — unused (Promise-only API, no callback)
|
|
71
|
+
- `decimal.js` — unused (BCD returns string by default)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Tasks
|
|
76
|
+
|
|
77
|
+
### Task 1: Initialize package structure
|
|
78
|
+
|
|
79
|
+
**Files:**
|
|
80
|
+
- Create: `sap-rfc-lite/package.json`
|
|
81
|
+
- Create: `sap-rfc-lite/tsconfig.json`
|
|
82
|
+
- Create: `sap-rfc-lite/LICENSE`
|
|
83
|
+
- Create: `sap-rfc-lite/NOTICE`
|
|
84
|
+
- Create: `sap-rfc-lite/.gitignore`
|
|
85
|
+
|
|
86
|
+
- [ ] **Step 1: Create directory and init git**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
mkdir -p /home/okyslytsia/prj/sap-rfc-lite
|
|
90
|
+
cd /home/okyslytsia/prj/sap-rfc-lite
|
|
91
|
+
git init
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- [ ] **Step 2: Create package.json**
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"name": "sap-rfc-lite",
|
|
99
|
+
"version": "0.1.0",
|
|
100
|
+
"description": "Lightweight Node.js bindings for SAP NW RFC SDK",
|
|
101
|
+
"license": "Apache-2.0",
|
|
102
|
+
"main": "./lib/index.js",
|
|
103
|
+
"types": "./lib/index.d.ts",
|
|
104
|
+
"files": ["binding.gyp", "src", "lib"],
|
|
105
|
+
"scripts": {
|
|
106
|
+
"install": "node-gyp-build",
|
|
107
|
+
"build:ts": "tsc",
|
|
108
|
+
"build:cpp": "node-gyp rebuild",
|
|
109
|
+
"build": "npm run build:ts && npm run build:cpp",
|
|
110
|
+
"test": "jest --testTimeout 60000"
|
|
111
|
+
},
|
|
112
|
+
"config": {
|
|
113
|
+
"napi_version": 8
|
|
114
|
+
},
|
|
115
|
+
"dependencies": {
|
|
116
|
+
"node-addon-api": "^6.1.0",
|
|
117
|
+
"node-gyp-build": "^4.6.0"
|
|
118
|
+
},
|
|
119
|
+
"devDependencies": {
|
|
120
|
+
"@types/node": "^20.0.0",
|
|
121
|
+
"typescript": "^5.0.0",
|
|
122
|
+
"jest": "^29.0.0",
|
|
123
|
+
"ts-jest": "^29.0.0",
|
|
124
|
+
"@types/jest": "^29.0.0"
|
|
125
|
+
},
|
|
126
|
+
"engines": {
|
|
127
|
+
"node": ">=18"
|
|
128
|
+
},
|
|
129
|
+
"gypfile": true
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- [ ] **Step 3: Create tsconfig.json**
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"compilerOptions": {
|
|
138
|
+
"target": "ES2020",
|
|
139
|
+
"module": "commonjs",
|
|
140
|
+
"lib": ["ES2020"],
|
|
141
|
+
"outDir": "./lib",
|
|
142
|
+
"rootDir": "./src/ts",
|
|
143
|
+
"declaration": true,
|
|
144
|
+
"strict": true,
|
|
145
|
+
"esModuleInterop": true,
|
|
146
|
+
"skipLibCheck": true,
|
|
147
|
+
"forceConsistentCasingInFileNames": true
|
|
148
|
+
},
|
|
149
|
+
"include": ["src/ts/**/*"]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- [ ] **Step 4: Create LICENSE (Apache-2.0) and NOTICE**
|
|
154
|
+
|
|
155
|
+
Copy Apache-2.0 license. NOTICE file:
|
|
156
|
+
```
|
|
157
|
+
This project is based on node-rfc (https://github.com/SAP/node-rfc)
|
|
158
|
+
Copyright 2014 SAP SE, Srdjan Boskovic <srdjan.boskovic@sap.com>
|
|
159
|
+
Licensed under the Apache License, Version 2.0
|
|
160
|
+
|
|
161
|
+
Modifications: Removed Pool, Server, Throughput classes. Simplified Client API to Promise-only.
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- [ ] **Step 5: Create .gitignore**
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
node_modules/
|
|
168
|
+
lib/
|
|
169
|
+
build/
|
|
170
|
+
prebuilds/
|
|
171
|
+
*.node
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- [ ] **Step 6: Commit**
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
git add -A
|
|
178
|
+
git commit -m "chore: init sap-rfc-lite package structure"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### Task 2: Port C++ source — noderfc.h (common header)
|
|
184
|
+
|
|
185
|
+
**Files:**
|
|
186
|
+
- Create: `sap-rfc-lite/src/cpp/noderfc.h`
|
|
187
|
+
|
|
188
|
+
- [ ] **Step 1: Create stripped noderfc.h**
|
|
189
|
+
|
|
190
|
+
Keep from original (`/tmp/node-rfc-source/src/cpp/noderfc.h`):
|
|
191
|
+
- All includes (`napi.h`, `sapnwrfc.h`)
|
|
192
|
+
- `ERRMSG_LENGTH`, `ERROR_PATH_NAME_LEN`
|
|
193
|
+
- `uint_t`, `pointer_t`, `UNUSED`
|
|
194
|
+
- `ENV_UNDEFINED`
|
|
195
|
+
- `CLIENT_OPTION_BCD*`, `CLIENT_OPTION_DATE/TIME/FILTER/STATELESS/TIMEOUT`
|
|
196
|
+
- `CALL_OPTION_KEY_*`
|
|
197
|
+
|
|
198
|
+
Remove:
|
|
199
|
+
- `SRV_OPTION_*` (server constants) — **including `SRV_OPTION_LOG_LEVEL`** which is referenced in `checkClientOptions()` in nwrfcsdk.cc; that branch must also be removed (see Task 3)
|
|
200
|
+
- `POOL_*` (pool constants)
|
|
201
|
+
|
|
202
|
+
Change `NODERFC_VERSION` to `"0.1.0"`.
|
|
203
|
+
|
|
204
|
+
Add minimal debug logging macro (replaces entire Log class):
|
|
205
|
+
```cpp
|
|
206
|
+
// Minimal logging — no-op by default, stderr in debug builds
|
|
207
|
+
#ifdef SAP_RFC_LITE_DEBUG
|
|
208
|
+
#include <cstdio>
|
|
209
|
+
#define RFC_LOG(fmt, ...) fprintf(stderr, "[sap-rfc-lite] " fmt "\n", ##__VA_ARGS__)
|
|
210
|
+
#else
|
|
211
|
+
#define RFC_LOG(fmt, ...) ((void)0)
|
|
212
|
+
#endif
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- [ ] **Step 2: Commit**
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
git add src/cpp/noderfc.h
|
|
219
|
+
git commit -m "feat: add noderfc.h common header (stripped)"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### Task 3: Port C++ source — nwrfcsdk.h and nwrfcsdk.cc (data marshalling)
|
|
225
|
+
|
|
226
|
+
**Files:**
|
|
227
|
+
- Create: `sap-rfc-lite/src/cpp/nwrfcsdk.h`
|
|
228
|
+
- Create: `sap-rfc-lite/src/cpp/nwrfcsdk.cc`
|
|
229
|
+
|
|
230
|
+
**IMPORTANT:** All Log.h references must be removed NOW (not deferred). Every file must be compilable once all C++ files are in place.
|
|
231
|
+
|
|
232
|
+
- [ ] **Step 1: Create nwrfcsdk.h**
|
|
233
|
+
|
|
234
|
+
Copy from original, with these changes:
|
|
235
|
+
- **Remove** `#include "Log.h"` — replace with `#include "noderfc.h"` only (which now has the `RFC_LOG` macro)
|
|
236
|
+
- **Remove** `extern Log _log;` declaration
|
|
237
|
+
- Remove `Pool`-related forward declarations if any
|
|
238
|
+
- Keep all type definitions: `ConnectionParamsStruct`, `ClientOptionsStruct`, `RfmErrorPath`, `ValuePair`, `ErrorPair`
|
|
239
|
+
- Keep all function declarations: `setString`, `setRfmParameter`, `setStructure`, `setVariable`, `getStructure`, `getVariable`, `getRfmParameters`, `getConnectionAttributes`
|
|
240
|
+
- Keep error functions: `RfcLibError`, `AbapError`, `rfcSdkError`, `nodeRfcError`
|
|
241
|
+
- Keep parsers: `getConnectionParams`, `checkClientOptions`
|
|
242
|
+
|
|
243
|
+
- [ ] **Step 2: Create nwrfcsdk.cc**
|
|
244
|
+
|
|
245
|
+
Copy from original (1,158 lines). This is the most critical file — handles all ABAP type conversions. Apply these targeted changes:
|
|
246
|
+
|
|
247
|
+
1. **Replace all `_log.*()` calls** (5-6 occurrences):
|
|
248
|
+
- Lines 34-44: `_log.fatal(logClass::nwrfc, ...)` → keep the `Napi::Error::Fatal(...)` that follows it, remove the `_log.fatal` call itself (it's just informational before abort)
|
|
249
|
+
- Lines 68-78: same pattern
|
|
250
|
+
- Line 419-430: `_log.record(logClass::nwrfc, logLevel::all, ...)` → remove entirely (verbose trace, not useful)
|
|
251
|
+
- Lines 684-688: `_log.warning(logClass::nwrfc, ...)` → `RFC_LOG("Buffer for BCD type too small")`
|
|
252
|
+
- Lines 735-738: same pattern for DECF16/34
|
|
253
|
+
|
|
254
|
+
2. **Remove the `logLevel` client option branch in `checkClientOptions()`** (line 1103-1105):
|
|
255
|
+
```cpp
|
|
256
|
+
// REMOVE this entire block — SRV_OPTION_LOG_LEVEL is removed and Log class is gone:
|
|
257
|
+
else if (key == SRV_OPTION_LOG_LEVEL) {
|
|
258
|
+
_log.set_log_level(logClass::client, opt);
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
Let it fall through to the "unknown option" error handler. This is correct because our lite version does not support per-client log level configuration.
|
|
262
|
+
|
|
263
|
+
3. **Remove** `extern Log _log;` if present at top of file.
|
|
264
|
+
|
|
265
|
+
- [ ] **Step 3: Commit**
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
git add src/cpp/nwrfcsdk.h src/cpp/nwrfcsdk.cc
|
|
269
|
+
git commit -m "feat: add nwrfcsdk data marshalling layer (Log-free)"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
### Task 4: Port C++ source — Client.h and Client.cc
|
|
275
|
+
|
|
276
|
+
**Files:**
|
|
277
|
+
- Create: `sap-rfc-lite/src/cpp/Client.h`
|
|
278
|
+
- Create: `sap-rfc-lite/src/cpp/Client.cc`
|
|
279
|
+
|
|
280
|
+
- [ ] **Step 1: Create Client.h**
|
|
281
|
+
|
|
282
|
+
From original, remove:
|
|
283
|
+
- `#include "Log.h"` — replace with `#include "nwrfcsdk.h"` only
|
|
284
|
+
- `extern Log _log;` declaration
|
|
285
|
+
- `friend class Pool`, `friend class AcquireAsync`, `friend class ReleaseAsync`, `friend class CheckPoolAsync`
|
|
286
|
+
- `friend class ResetServerAsync`, `friend class PingAsync`
|
|
287
|
+
- `class Pool;` forward declaration
|
|
288
|
+
- `Pool* pool` member
|
|
289
|
+
- `Release()`, `Cancel()`, `ResetServerContext()`, `Ping()` method declarations
|
|
290
|
+
- `ConfigGetter()`, `ConnectionHandleGetter()`, `PoolIdGetter()`, `ConnectionInfo()` — not needed
|
|
291
|
+
- `log_id()` method (logging)
|
|
292
|
+
|
|
293
|
+
Keep:
|
|
294
|
+
- `friend class OpenAsync`, `friend class CloseAsync`, `friend class PrepareAsync`, `friend class InvokeAsync`
|
|
295
|
+
- `Open()`, `Close()`, `Invoke()`, `AliveGetter()`, `IdGetter()`
|
|
296
|
+
- `connectionCheck()`, `getOperationError()`, `connectionClosedError()`
|
|
297
|
+
- `connectionHandle`, `client_params`, `client_options`, `errorPath`
|
|
298
|
+
- `invocationMutex`, `LockMutex()`, `UnlockMutex()`
|
|
299
|
+
- Constructor/destructor
|
|
300
|
+
|
|
301
|
+
- [ ] **Step 2: Create Client.cc**
|
|
302
|
+
|
|
303
|
+
From original (780 lines), keep:
|
|
304
|
+
- `Client::Init()` — remove `cancel`, `release`, `resetServerContext`, `ping`, `connectionInfo` from `DefineClass`. Remove `_connectionHandle`, `_pool_id`, `_config` accessors.
|
|
305
|
+
- `Client::AliveGetter()` — as-is
|
|
306
|
+
- `Client::IdGetter()` — as-is
|
|
307
|
+
- Constructor — remove pool-related logic, remove `clientOptionsRef` handling (not needed for our use case, but can keep for compatibility)
|
|
308
|
+
- Destructor — remove `pool->releaseClient()` branch, keep direct close only
|
|
309
|
+
- `OpenAsync` class — as-is
|
|
310
|
+
- `CloseAsync` class — as-is
|
|
311
|
+
- `PrepareAsync` class — as-is
|
|
312
|
+
- `InvokeAsync` class — as-is
|
|
313
|
+
- `Client::Open()` — remove pool check (`if (pool != nullptr)`)
|
|
314
|
+
- `Client::Close()` — remove pool check
|
|
315
|
+
- `Client::Invoke()` — as-is
|
|
316
|
+
- `Client::connectionCheck()` — remove pool branch (`if (pool != nullptr)`), keep direct reconnect only
|
|
317
|
+
- `Client::getOperationError()` — as-is
|
|
318
|
+
- `Client::connectionClosedError()` — as-is
|
|
319
|
+
- `Client::LockMutex()`, `Client::UnlockMutex()` — as-is
|
|
320
|
+
|
|
321
|
+
Remove:
|
|
322
|
+
- `Client::Release()` (~20 lines)
|
|
323
|
+
- `Client::Cancel()` and `cancelConnection()` (~30 lines)
|
|
324
|
+
- `Client::ResetServerContext()` (~15 lines)
|
|
325
|
+
- `Client::Ping()` (~15 lines)
|
|
326
|
+
- `ResetServerAsync` class (~35 lines)
|
|
327
|
+
- `PingAsync` class (~33 lines)
|
|
328
|
+
- `Client::ConnectionInfo()` (~6 lines)
|
|
329
|
+
- `Client::ConfigGetter()` (~20 lines)
|
|
330
|
+
- `Client::ConnectionHandleGetter()` (3 lines)
|
|
331
|
+
- `Client::PoolIdGetter()` (5 lines)
|
|
332
|
+
- `Client::NewInstance()` (4 lines)
|
|
333
|
+
- `#include "Pool.h"`
|
|
334
|
+
|
|
335
|
+
Replace all `_log.*()` calls (~10 occurrences) with `RFC_LOG(...)` macro or remove entirely. Remove `extern Log _log;` at file top. Replace `#include "Pool.h"` with nothing (Client.h already includes nwrfcsdk.h).
|
|
336
|
+
|
|
337
|
+
In `connectionCheck()`: remove the `pool != nullptr` branches entirely. Keep only the direct client reconnect path:
|
|
338
|
+
```cpp
|
|
339
|
+
// Direct client reconnect (pool branches removed)
|
|
340
|
+
this->connectionHandle = nullptr;
|
|
341
|
+
RFC_CONNECTION_HANDLE new_handle = RfcOpenConnection(
|
|
342
|
+
client_params.connectionParams, client_params.paramSize, &errorInfoOpen);
|
|
343
|
+
if (errorInfoOpen.code == RFC_OK) {
|
|
344
|
+
this->connectionHandle = new_handle;
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Also keep `connectionCheckErrorInit()` free function — it is used by `InvokeAsync`.
|
|
349
|
+
|
|
350
|
+
- [ ] **Step 3: Compile-check the header dependencies**
|
|
351
|
+
|
|
352
|
+
Verify Client.h includes are correct:
|
|
353
|
+
```cpp
|
|
354
|
+
#include "nwrfcsdk.h" // includes noderfc.h → napi.h, sapnwrfc.h
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
- [ ] **Step 4: Commit**
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
git add src/cpp/Client.h src/cpp/Client.cc
|
|
361
|
+
git commit -m "feat: add stripped Client class (open/close/invoke/alive)"
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### Task 5: Port C++ source — addon.cc (entry point)
|
|
367
|
+
|
|
368
|
+
**Files:**
|
|
369
|
+
- Create: `sap-rfc-lite/src/cpp/addon.cc`
|
|
370
|
+
|
|
371
|
+
- [ ] **Step 1: Create minimal addon.cc**
|
|
372
|
+
|
|
373
|
+
```cpp
|
|
374
|
+
// SPDX-FileCopyrightText: 2014 SAP SE Srdjan Boskovic <srdjan.boskovic@sap.com>
|
|
375
|
+
// SPDX-FileCopyrightText: 2026 sap-rfc-lite contributors
|
|
376
|
+
//
|
|
377
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
378
|
+
|
|
379
|
+
#include "Client.h"
|
|
380
|
+
|
|
381
|
+
namespace node_rfc {
|
|
382
|
+
|
|
383
|
+
Napi::Env __env = nullptr;
|
|
384
|
+
|
|
385
|
+
Napi::Value BindingVersions(Napi::Env env) {
|
|
386
|
+
uint_t major, minor, patchLevel;
|
|
387
|
+
Napi::EscapableHandleScope scope(env);
|
|
388
|
+
|
|
389
|
+
RfcGetVersion(&major, &minor, &patchLevel);
|
|
390
|
+
|
|
391
|
+
Napi::Object nwrfcsdk = Napi::Object::New(env);
|
|
392
|
+
nwrfcsdk.Set("major", major);
|
|
393
|
+
nwrfcsdk.Set("minor", minor);
|
|
394
|
+
nwrfcsdk.Set("patchLevel", patchLevel);
|
|
395
|
+
|
|
396
|
+
Napi::Object version = Napi::Object::New(env);
|
|
397
|
+
version.Set("version", "0.1.0");
|
|
398
|
+
version.Set("nwrfcsdk", nwrfcsdk);
|
|
399
|
+
|
|
400
|
+
return scope.Escape(version);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
Napi::Object RegisterModule(Napi::Env env, Napi::Object exports) {
|
|
404
|
+
if (node_rfc::__env == nullptr) {
|
|
405
|
+
node_rfc::__env = env;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
exports.Set("bindingVersions", BindingVersions(env));
|
|
409
|
+
Client::Init(env, exports);
|
|
410
|
+
|
|
411
|
+
return exports;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
NODE_API_MODULE(NODE_GYP_MODULE_NAME, RegisterModule)
|
|
415
|
+
|
|
416
|
+
} // namespace node_rfc
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
- [ ] **Step 2: Commit**
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
git add src/cpp/addon.cc
|
|
423
|
+
git commit -m "feat: add addon entry point (Client only)"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
### Task 6: Create binding.gyp
|
|
429
|
+
|
|
430
|
+
**Files:**
|
|
431
|
+
- Create: `sap-rfc-lite/binding.gyp`
|
|
432
|
+
|
|
433
|
+
- [ ] **Step 1: Create binding.gyp**
|
|
434
|
+
|
|
435
|
+
Copy from original, with these changes:
|
|
436
|
+
- Remove `Pool.cc`, `Server.cc`, `server_api.cc`, `Throughput.cc`, `Log.cc` from sources
|
|
437
|
+
- Keep all platform conditions (mac/linux/win) — identical logic
|
|
438
|
+
- Keep all defines (UNICODE, SAPwithTHREADS, NAPI_CPP_EXCEPTIONS, etc.)
|
|
439
|
+
- Sources list becomes:
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
'sources': [
|
|
443
|
+
'src/cpp/addon.cc',
|
|
444
|
+
'src/cpp/nwrfcsdk.cc',
|
|
445
|
+
'src/cpp/Client.cc',
|
|
446
|
+
]
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
- [ ] **Step 2: Compile-verify C++ (requires SAP NW RFC SDK)**
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
cd /home/okyslytsia/prj/sap-rfc-lite
|
|
453
|
+
npm install
|
|
454
|
+
npm run build:cpp 2>&1
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
All C++ files should compile cleanly at this point — no Log.h, no Pool.h, no Server.h dependencies. If SDK is not available locally, at least verify `tsc` passes for TS and review C++ for any remaining `_log` / `Log` / `logClass` / `logLevel` references:
|
|
458
|
+
```bash
|
|
459
|
+
grep -rn '_log\.\|Log\|logClass\|logLevel' src/cpp/
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
- [ ] **Step 3: Commit**
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
git add binding.gyp
|
|
466
|
+
git commit -m "feat: add binding.gyp build configuration"
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
### Task 7: Port TypeScript — types.ts
|
|
472
|
+
|
|
473
|
+
**Files:**
|
|
474
|
+
- Create: `sap-rfc-lite/src/ts/types.ts`
|
|
475
|
+
|
|
476
|
+
- [ ] **Step 1: Create minimal type definitions**
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
// Connection parameters — same keys as SAP NW RFC SDK
|
|
480
|
+
export type RfcConnectionParameters = Record<string, string>;
|
|
481
|
+
|
|
482
|
+
// RFC data types
|
|
483
|
+
export type RfcVariable = string | number | Buffer;
|
|
484
|
+
export type RfcStructure = { [key: string]: RfcVariable | RfcStructure | RfcTable };
|
|
485
|
+
export type RfcTable = Array<RfcVariable | RfcStructure>;
|
|
486
|
+
export type RfcParameterValue = RfcVariable | RfcStructure | RfcTable;
|
|
487
|
+
export type RfcObject = { [key: string]: RfcParameterValue };
|
|
488
|
+
|
|
489
|
+
// Binding versions
|
|
490
|
+
export interface RfcSdkVersions {
|
|
491
|
+
version: string;
|
|
492
|
+
nwrfcsdk: { major: number; minor: number; patchLevel: number };
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Error types
|
|
496
|
+
export interface RfcLibError {
|
|
497
|
+
name: 'RfcLibError';
|
|
498
|
+
group: number;
|
|
499
|
+
code: number;
|
|
500
|
+
codeString: string;
|
|
501
|
+
key: string;
|
|
502
|
+
message: string;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export interface AbapError {
|
|
506
|
+
name: 'ABAPError';
|
|
507
|
+
group: number;
|
|
508
|
+
code: number;
|
|
509
|
+
codeString: string;
|
|
510
|
+
key: string;
|
|
511
|
+
message: string;
|
|
512
|
+
abapMsgClass: string;
|
|
513
|
+
abapMsgType: string;
|
|
514
|
+
abapMsgNumber: string;
|
|
515
|
+
abapMsgV1: string;
|
|
516
|
+
abapMsgV2: string;
|
|
517
|
+
abapMsgV3: string;
|
|
518
|
+
abapMsgV4: string;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
export interface NodeRfcError {
|
|
522
|
+
name: 'nodeRfcError';
|
|
523
|
+
message: string;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export type RfcError = RfcLibError | AbapError | NodeRfcError;
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
- [ ] **Step 2: Commit**
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
git add src/ts/types.ts
|
|
533
|
+
git commit -m "feat: add minimal type definitions"
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
### Task 8: Port TypeScript — binding.ts (native addon loader)
|
|
539
|
+
|
|
540
|
+
**Files:**
|
|
541
|
+
- Create: `sap-rfc-lite/src/ts/binding.ts`
|
|
542
|
+
|
|
543
|
+
- [ ] **Step 1: Create binding loader**
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
import path from 'path';
|
|
547
|
+
import { RfcConnectionParameters, RfcObject, RfcSdkVersions } from './types';
|
|
548
|
+
|
|
549
|
+
export interface RfcClientBinding {
|
|
550
|
+
new (connectionParameters: RfcConnectionParameters): RfcClientBinding;
|
|
551
|
+
_id: number;
|
|
552
|
+
_alive: boolean;
|
|
553
|
+
open(callback: Function): void;
|
|
554
|
+
close(callback: Function): void;
|
|
555
|
+
invoke(
|
|
556
|
+
rfmName: string,
|
|
557
|
+
rfmParams: RfcObject,
|
|
558
|
+
callback: Function,
|
|
559
|
+
callOptions?: object
|
|
560
|
+
): void;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export interface NativeBinding {
|
|
564
|
+
Client: RfcClientBinding;
|
|
565
|
+
bindingVersions: RfcSdkVersions;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
let binding: NativeBinding;
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
572
|
+
binding = require('node-gyp-build')(
|
|
573
|
+
path.resolve(__dirname, '..')
|
|
574
|
+
) as NativeBinding;
|
|
575
|
+
} catch (ex) {
|
|
576
|
+
const err = ex as Error;
|
|
577
|
+
const env = {
|
|
578
|
+
SAPNWRFC_HOME: process.env.SAPNWRFC_HOME || '(not set)',
|
|
579
|
+
platform: process.platform,
|
|
580
|
+
arch: process.arch,
|
|
581
|
+
node: process.version,
|
|
582
|
+
};
|
|
583
|
+
err.message += `\nEnvironment: ${JSON.stringify(env, null, 2)}`;
|
|
584
|
+
throw err;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
export { binding };
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
- [ ] **Step 2: Commit**
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
git add src/ts/binding.ts
|
|
594
|
+
git commit -m "feat: add native binding loader"
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
### Task 9: Port TypeScript — client.ts (Client class, Promise-only)
|
|
600
|
+
|
|
601
|
+
**Files:**
|
|
602
|
+
- Create: `sap-rfc-lite/src/ts/client.ts`
|
|
603
|
+
|
|
604
|
+
- [ ] **Step 1: Create Client class**
|
|
605
|
+
|
|
606
|
+
Key difference from node-rfc: **Promise-only API**, no callback overloads, no pool support, no cancel/ping/resetServerContext.
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
import { binding, RfcClientBinding } from './binding';
|
|
610
|
+
import { RfcConnectionParameters, RfcObject } from './types';
|
|
611
|
+
|
|
612
|
+
export class Client {
|
|
613
|
+
private __client: RfcClientBinding;
|
|
614
|
+
|
|
615
|
+
constructor(connectionParameters: RfcConnectionParameters) {
|
|
616
|
+
if (!connectionParameters || typeof connectionParameters !== 'object') {
|
|
617
|
+
throw new TypeError('Client constructor requires connection parameters object');
|
|
618
|
+
}
|
|
619
|
+
this.__client = new binding.Client(connectionParameters);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
get id(): number {
|
|
623
|
+
return this.__client._id;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
get alive(): boolean {
|
|
627
|
+
return this.__client._alive;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
open(): Promise<this> {
|
|
631
|
+
return new Promise((resolve, reject) => {
|
|
632
|
+
try {
|
|
633
|
+
this.__client.open((err: unknown) => {
|
|
634
|
+
if (err !== undefined) {
|
|
635
|
+
reject(err);
|
|
636
|
+
} else {
|
|
637
|
+
resolve(this);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
} catch (ex) {
|
|
641
|
+
reject(ex);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
close(): Promise<void> {
|
|
647
|
+
return new Promise((resolve, reject) => {
|
|
648
|
+
try {
|
|
649
|
+
this.__client.close((err: unknown) => {
|
|
650
|
+
if (err === undefined) {
|
|
651
|
+
resolve();
|
|
652
|
+
} else {
|
|
653
|
+
reject(err);
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
} catch (ex) {
|
|
657
|
+
reject(ex);
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
call(rfmName: string, rfmParams: RfcObject = {}): Promise<RfcObject> {
|
|
663
|
+
return new Promise((resolve, reject) => {
|
|
664
|
+
if (typeof rfmName !== 'string' || rfmName.length === 0) {
|
|
665
|
+
reject(new TypeError('Function module name must be a non-empty string'));
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
try {
|
|
669
|
+
this.__client.invoke(
|
|
670
|
+
rfmName,
|
|
671
|
+
rfmParams,
|
|
672
|
+
(err: unknown, res: RfcObject) => {
|
|
673
|
+
if (err !== undefined && err !== null) {
|
|
674
|
+
reject(err);
|
|
675
|
+
} else {
|
|
676
|
+
resolve(res);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
);
|
|
680
|
+
} catch (ex) {
|
|
681
|
+
reject(ex);
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
- [ ] **Step 2: Commit**
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
git add src/ts/client.ts
|
|
692
|
+
git commit -m "feat: add Client class (Promise-only API)"
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
---
|
|
696
|
+
|
|
697
|
+
### Task 10: Port TypeScript — index.ts (entry point)
|
|
698
|
+
|
|
699
|
+
**Files:**
|
|
700
|
+
- Create: `sap-rfc-lite/src/ts/index.ts`
|
|
701
|
+
|
|
702
|
+
- [ ] **Step 1: Create index.ts**
|
|
703
|
+
|
|
704
|
+
```typescript
|
|
705
|
+
export { Client } from './client';
|
|
706
|
+
export { binding } from './binding';
|
|
707
|
+
export * from './types';
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
- [ ] **Step 2: Commit**
|
|
711
|
+
|
|
712
|
+
```bash
|
|
713
|
+
git add src/ts/index.ts
|
|
714
|
+
git commit -m "feat: add package entry point"
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
719
|
+
### Task 11: Write tests
|
|
720
|
+
|
|
721
|
+
**Files:**
|
|
722
|
+
- Create: `sap-rfc-lite/test/client.test.ts`
|
|
723
|
+
- Create: `sap-rfc-lite/jest.config.ts`
|
|
724
|
+
|
|
725
|
+
- [ ] **Step 1: Create jest.config.ts**
|
|
726
|
+
|
|
727
|
+
```typescript
|
|
728
|
+
export default {
|
|
729
|
+
preset: 'ts-jest',
|
|
730
|
+
testEnvironment: 'node',
|
|
731
|
+
roots: ['<rootDir>/test'],
|
|
732
|
+
};
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
- [ ] **Step 2: Write unit test for Client class (type/API checks)**
|
|
736
|
+
|
|
737
|
+
```typescript
|
|
738
|
+
import { Client } from '../src/ts/client';
|
|
739
|
+
|
|
740
|
+
// These tests verify the TypeScript API surface without requiring SAP NW RFC SDK.
|
|
741
|
+
// Integration tests that actually call RFC need SDK + SAP system.
|
|
742
|
+
|
|
743
|
+
describe('Client API surface', () => {
|
|
744
|
+
it('constructor requires connection parameters', () => {
|
|
745
|
+
expect(() => new Client(undefined as any)).toThrow(TypeError);
|
|
746
|
+
expect(() => new Client(null as any)).toThrow(TypeError);
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
it('exports expected types', () => {
|
|
750
|
+
// Verify the module exports compile correctly
|
|
751
|
+
const mod = require('../src/ts/index');
|
|
752
|
+
expect(mod.Client).toBeDefined();
|
|
753
|
+
expect(typeof mod.Client).toBe('function');
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
Note: Full integration tests will be written after first successful build with SDK.
|
|
759
|
+
|
|
760
|
+
- [ ] **Step 3: Commit**
|
|
761
|
+
|
|
762
|
+
```bash
|
|
763
|
+
git add test/ jest.config.ts
|
|
764
|
+
git commit -m "test: add Client API surface tests"
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
### Task 12: Integrate into mcp-abap-adt
|
|
770
|
+
|
|
771
|
+
**Files:**
|
|
772
|
+
- Modify: `mcp-abap-adt/package.json` — replace `node-rfc` with `sap-rfc-lite`
|
|
773
|
+
- Modify: `mcp-abap-adt-clients` repo — update `require('node-rfc')` to `require('sap-rfc-lite')` in RfcAbapConnection **source** (not compiled .js in node_modules)
|
|
774
|
+
|
|
775
|
+
- [ ] **Step 1: Update mcp-abap-adt package.json**
|
|
776
|
+
|
|
777
|
+
Replace in `optionalDependencies`:
|
|
778
|
+
```json
|
|
779
|
+
"node-rfc": "^3.3.1"
|
|
780
|
+
```
|
|
781
|
+
with:
|
|
782
|
+
```json
|
|
783
|
+
"sap-rfc-lite": "file:../sap-rfc-lite"
|
|
784
|
+
```
|
|
785
|
+
(or npm registry path once published)
|
|
786
|
+
|
|
787
|
+
- [ ] **Step 2: Update RfcAbapConnection import in mcp-abap-adt-clients repo**
|
|
788
|
+
|
|
789
|
+
In `/home/okyslytsia/prj/mcp-abap-adt-clients` — the **source** of `@mcp-abap-adt/connection` package — change:
|
|
790
|
+
```javascript
|
|
791
|
+
const noderfc = require('node-rfc');
|
|
792
|
+
Client = noderfc.Client;
|
|
793
|
+
```
|
|
794
|
+
to:
|
|
795
|
+
```javascript
|
|
796
|
+
const { Client } = require('sap-rfc-lite');
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
The API is identical: `Client` constructor takes connection params object, has `open()`, `call()`, `close()`, `alive`.
|
|
800
|
+
|
|
801
|
+
- [ ] **Step 3: Verify RfcAbapConnection still works**
|
|
802
|
+
|
|
803
|
+
The `call()` method in sap-rfc-lite wraps `invoke()` with a Promise — same as the original node-rfc `Client.call()`. Return structure is identical since nwrfcsdk.cc is unchanged.
|
|
804
|
+
|
|
805
|
+
- [ ] **Step 4: Commit both repos**
|
|
806
|
+
|
|
807
|
+
```bash
|
|
808
|
+
# sap-rfc-lite
|
|
809
|
+
cd /home/okyslytsia/prj/sap-rfc-lite
|
|
810
|
+
git add -A
|
|
811
|
+
git commit -m "chore: ready for integration"
|
|
812
|
+
|
|
813
|
+
# mcp-abap-adt
|
|
814
|
+
cd /home/okyslytsia/prj/mcp-abap-adt
|
|
815
|
+
git add package.json
|
|
816
|
+
git commit -m "feat: replace node-rfc with sap-rfc-lite"
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
---
|
|
820
|
+
|
|
821
|
+
## API Compatibility Matrix
|
|
822
|
+
|
|
823
|
+
| node-rfc API | sap-rfc-lite | Notes |
|
|
824
|
+
|---|---|---|
|
|
825
|
+
| `new Client(params)` | `new Client(params)` | Identical |
|
|
826
|
+
| `client.open()` → Promise | `client.open()` → Promise | Identical |
|
|
827
|
+
| `client.call(name, params)` → Promise | `client.call(name, params)` → Promise | Identical |
|
|
828
|
+
| `client.close()` → Promise | `client.close()` → Promise | Identical |
|
|
829
|
+
| `client.alive` | `client.alive` | Identical |
|
|
830
|
+
| `client.open(callback)` | ❌ removed | Promise-only |
|
|
831
|
+
| `client.ping()` | ❌ removed | Use `alive` property |
|
|
832
|
+
| `client.cancel()` | ❌ removed | Not used |
|
|
833
|
+
| `client.resetServerContext()` | ❌ removed | Not used |
|
|
834
|
+
| `client.release()` | ❌ removed | Pool-only, removed |
|
|
835
|
+
| `client.connectionInfo` | ❌ removed | Not used |
|
|
836
|
+
| `Pool` class | ❌ removed | Not used |
|
|
837
|
+
| `Server` class | ❌ removed | Not used |
|
|
838
|
+
| `Throughput` class | ❌ removed | Not used |
|
|
839
|
+
|
|
840
|
+
## Risk Assessment
|
|
841
|
+
|
|
842
|
+
| Risk | Mitigation |
|
|
843
|
+
|---|---|
|
|
844
|
+
| nwrfcsdk.cc has subtle bugs we don't catch | Keep it verbatim — zero modifications to marshalling logic |
|
|
845
|
+
| SAP NW RFC SDK version incompatibility | Same N-API version (8), same SDK API surface as node-rfc 3.3.1 |
|
|
846
|
+
| Build fails on some platforms | Keep binding.gyp platform conditions identical to node-rfc |
|
|
847
|
+
| connectionCheck() auto-reconnect breaks without Pool | Remove pool branch, keep direct client reconnect — simpler and correct |
|
|
848
|
+
| SNC/TLS via RFC not supported | `loadCryptoLibrary()` and `setIniFileDirectory()` removed from addon.cc. Can be added back later if needed. Document as known limitation |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/core",
|
|
3
3
|
"mcpName": "io.github.fr0ster/mcp-abap-adt",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.7.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"zod": "^4.3.6"
|
|
155
155
|
},
|
|
156
156
|
"optionalDependencies": {
|
|
157
|
-
"
|
|
157
|
+
"@mcp-abap-adt/sap-rfc-lite": "^0.1.0"
|
|
158
158
|
},
|
|
159
159
|
"engines": {
|
|
160
160
|
"node": ">=20.0.0",
|