catalyst-relay 0.2.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/README.md +418 -0
- package/dist/index.d.mts +438 -0
- package/dist/index.d.ts +438 -0
- package/dist/index.js +1744 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1715 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
# Catalyst-Relay
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/catalyst-relay)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
TypeScript middleware for bridging frontend applications to SAP ADT (ABAP Development Tools) servers.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Catalyst-Relay provides a clean, type-safe interface for interacting with SAP ADT services. It enables CRAUD operations (Create, Read, Activate, Update, Delete) on ABAP objects, package discovery, data preview, and search capabilities.
|
|
12
|
+
|
|
13
|
+
### Dual-Mode Architecture
|
|
14
|
+
|
|
15
|
+
This package operates in two modes:
|
|
16
|
+
|
|
17
|
+
**Library Mode** — Import functions directly into your TypeScript/Node.js application:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createClient } from 'catalyst-relay';
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Server Mode** — Run as an HTTP API server:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun run src/server.ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install catalyst-relay
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or with Bun:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bun add catalyst-relay
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### Library Mode
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { createClient } from 'catalyst-relay';
|
|
47
|
+
|
|
48
|
+
// Create client
|
|
49
|
+
const [client, error] = createClient({
|
|
50
|
+
url: 'https://sap-server:443',
|
|
51
|
+
client: '100',
|
|
52
|
+
auth: { type: 'basic', username: 'user', password: 'pass' },
|
|
53
|
+
insecure: true // For self-signed certificates
|
|
54
|
+
});
|
|
55
|
+
if (error) throw error;
|
|
56
|
+
|
|
57
|
+
// Login
|
|
58
|
+
const [session, loginError] = await client.login();
|
|
59
|
+
if (loginError) throw loginError;
|
|
60
|
+
console.log(`Logged in as ${session.username}`);
|
|
61
|
+
|
|
62
|
+
// Read ABAP objects
|
|
63
|
+
const [objects, readError] = await client.read([
|
|
64
|
+
{ name: 'ZCL_MY_CLASS', extension: 'aclass' },
|
|
65
|
+
{ name: 'ZTEST_PROGRAM', extension: 'asprog' }
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
// Logout when done
|
|
69
|
+
await client.logout();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Server Mode
|
|
73
|
+
|
|
74
|
+
Start the server:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Default port 3000
|
|
78
|
+
bun run src/server.ts
|
|
79
|
+
|
|
80
|
+
# Custom port
|
|
81
|
+
PORT=8080 bun run src/server.ts
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Make requests:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Login
|
|
88
|
+
curl -X POST http://localhost:3000/login \
|
|
89
|
+
-H "Content-Type: application/json" \
|
|
90
|
+
-d '{
|
|
91
|
+
"url": "https://sap-server:443",
|
|
92
|
+
"client": "100",
|
|
93
|
+
"auth": { "type": "basic", "username": "user", "password": "pass" }
|
|
94
|
+
}'
|
|
95
|
+
|
|
96
|
+
# Response: { "success": true, "data": { "sessionId": "abc123", "username": "USER" } }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Features
|
|
100
|
+
|
|
101
|
+
### Session Management
|
|
102
|
+
- Login/logout with session tokens
|
|
103
|
+
- Automatic CSRF token handling and refresh
|
|
104
|
+
- Session expiration with configurable cleanup
|
|
105
|
+
- Support for multiple concurrent sessions
|
|
106
|
+
|
|
107
|
+
### CRAUD Operations
|
|
108
|
+
- **Create** — Create new ABAP objects in a package
|
|
109
|
+
- **Read** — Batch read objects with full content
|
|
110
|
+
- **Activate** — Compile and validate objects
|
|
111
|
+
- **Update** — Modify existing objects (with automatic locking)
|
|
112
|
+
- **Delete** — Remove objects from the system
|
|
113
|
+
|
|
114
|
+
### Discovery
|
|
115
|
+
- List available packages
|
|
116
|
+
- Browse package trees hierarchically
|
|
117
|
+
- List transports for a package
|
|
118
|
+
- Create new transport requests
|
|
119
|
+
|
|
120
|
+
### Data Preview
|
|
121
|
+
- Query table/view data with filtering and sorting
|
|
122
|
+
- Get distinct column values
|
|
123
|
+
- Count rows
|
|
124
|
+
|
|
125
|
+
### Search
|
|
126
|
+
- Search objects by name pattern
|
|
127
|
+
- Filter by object types
|
|
128
|
+
- Find where-used dependencies
|
|
129
|
+
|
|
130
|
+
### Diff
|
|
131
|
+
- Compare local content with server version
|
|
132
|
+
- Git-style unified diff output
|
|
133
|
+
|
|
134
|
+
## Supported Object Types
|
|
135
|
+
|
|
136
|
+
| Extension | Object Type | ADT Type |
|
|
137
|
+
|-----------|-------------|----------|
|
|
138
|
+
| `asddls` | CDS View | DDLS/DF |
|
|
139
|
+
| `asdcls` | Access Control | DCLS/DL |
|
|
140
|
+
| `aclass` | ABAP Class | CLAS/OC |
|
|
141
|
+
| `asprog` | ABAP Program | PROG/P |
|
|
142
|
+
| `astabldt` | Table | TABL/DT |
|
|
143
|
+
|
|
144
|
+
## Library Mode API Reference
|
|
145
|
+
|
|
146
|
+
### Client Methods
|
|
147
|
+
|
|
148
|
+
| Method | Description |
|
|
149
|
+
|--------|-------------|
|
|
150
|
+
| `login()` | Authenticate and create session |
|
|
151
|
+
| `logout()` | End session |
|
|
152
|
+
| `read(objects)` | Batch read with content |
|
|
153
|
+
| `create(object, package, transport?)` | Create new object |
|
|
154
|
+
| `update(object, transport?)` | Update existing object |
|
|
155
|
+
| `upsert(objects, package, transport?)` | Create or update |
|
|
156
|
+
| `activate(objects)` | Compile and validate |
|
|
157
|
+
| `delete(objects, transport?)` | Remove objects |
|
|
158
|
+
| `getPackages()` | List packages |
|
|
159
|
+
| `getTree(query)` | Browse package tree |
|
|
160
|
+
| `getTransports(package)` | List transports |
|
|
161
|
+
| `createTransport(config)` | Create transport |
|
|
162
|
+
| `previewData(query)` | Query table/view |
|
|
163
|
+
| `getDistinctValues(object, column)` | Distinct values |
|
|
164
|
+
| `countRows(object, type)` | Row count |
|
|
165
|
+
| `search(query, types?)` | Search objects |
|
|
166
|
+
| `whereUsed(object)` | Find dependencies |
|
|
167
|
+
| `gitDiff(objects)` | Compare with server |
|
|
168
|
+
| `getObjectConfig()` | Supported object types |
|
|
169
|
+
|
|
170
|
+
### Usage Examples
|
|
171
|
+
|
|
172
|
+
#### Reading Objects
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const [objects, error] = await client.read([
|
|
176
|
+
{ name: 'ZCL_MY_CLASS', extension: 'aclass' },
|
|
177
|
+
{ name: 'ZSNAP_CDS_VIEW', extension: 'asddls' }
|
|
178
|
+
]);
|
|
179
|
+
|
|
180
|
+
if (error) {
|
|
181
|
+
console.error('Read failed:', error.message);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
for (const obj of objects) {
|
|
186
|
+
console.log(`${obj.name}: ${obj.content.length} bytes`);
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### Creating/Updating Objects (Upsert)
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const [results, error] = await client.upsert([
|
|
194
|
+
{
|
|
195
|
+
name: 'ZSNAP_NEW_VIEW',
|
|
196
|
+
extension: 'asddls',
|
|
197
|
+
content: `@AccessControl.authorizationCheck: #NOT_REQUIRED
|
|
198
|
+
define view entity ZSNAP_NEW_VIEW as select from t000 {
|
|
199
|
+
key mandt,
|
|
200
|
+
mtext
|
|
201
|
+
}`
|
|
202
|
+
}
|
|
203
|
+
], '$TMP'); // Package name
|
|
204
|
+
|
|
205
|
+
if (error) {
|
|
206
|
+
console.error('Upsert failed:', error.message);
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### Searching Objects
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const [results, error] = await client.search('ZSNAP*', ['DDLS/DF', 'CLAS/OC']);
|
|
214
|
+
|
|
215
|
+
if (!error) {
|
|
216
|
+
for (const result of results) {
|
|
217
|
+
console.log(`${result.name} (${result.type})`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Previewing Table Data
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const [data, error] = await client.previewData({
|
|
226
|
+
objectName: 'T000',
|
|
227
|
+
columns: ['MANDT', 'MTEXT'],
|
|
228
|
+
limit: 10,
|
|
229
|
+
where: "MANDT = '100'"
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Server Mode API Reference
|
|
234
|
+
|
|
235
|
+
### HTTP Endpoints
|
|
236
|
+
|
|
237
|
+
| Method | Endpoint | Description |
|
|
238
|
+
|--------|----------|-------------|
|
|
239
|
+
| POST | `/login` | Authenticate and get session ID |
|
|
240
|
+
| DELETE | `/logout` | End session |
|
|
241
|
+
| GET | `/object-config` | List supported object types |
|
|
242
|
+
| GET | `/packages` | List available packages |
|
|
243
|
+
| POST | `/tree` | Browse package tree |
|
|
244
|
+
| GET | `/transports/:package` | List transports |
|
|
245
|
+
| POST | `/transports` | Create transport |
|
|
246
|
+
| POST | `/objects/read` | Batch read objects |
|
|
247
|
+
| POST | `/objects/upsert/:package/:transport?` | Create/update objects |
|
|
248
|
+
| POST | `/objects/activate` | Activate objects |
|
|
249
|
+
| DELETE | `/objects/:transport?` | Delete objects |
|
|
250
|
+
| POST | `/preview/data` | Query table/view data |
|
|
251
|
+
| POST | `/preview/distinct` | Get distinct values |
|
|
252
|
+
| POST | `/preview/count` | Count rows |
|
|
253
|
+
| POST | `/search/:query` | Search objects |
|
|
254
|
+
| POST | `/where-used` | Find dependencies |
|
|
255
|
+
| POST | `/git-diff` | Compare with server |
|
|
256
|
+
|
|
257
|
+
### Authentication
|
|
258
|
+
|
|
259
|
+
All endpoints except `/login` require a session header:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
x-session-id: <session-id-from-login>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Example Requests
|
|
266
|
+
|
|
267
|
+
#### Read Objects
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
curl -X POST http://localhost:3000/objects/read \
|
|
271
|
+
-H "Content-Type: application/json" \
|
|
272
|
+
-H "x-session-id: abc123" \
|
|
273
|
+
-d '[{ "name": "ZCL_MY_CLASS", "extension": "aclass" }]'
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Preview Table Data
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
curl -X POST http://localhost:3000/preview/data \
|
|
280
|
+
-H "Content-Type: application/json" \
|
|
281
|
+
-H "x-session-id: abc123" \
|
|
282
|
+
-d '{
|
|
283
|
+
"objectName": "T000",
|
|
284
|
+
"columns": ["MANDT", "MTEXT"],
|
|
285
|
+
"limit": 10
|
|
286
|
+
}'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### Search Objects
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
curl -X POST "http://localhost:3000/search/ZSNAP*" \
|
|
293
|
+
-H "Content-Type: application/json" \
|
|
294
|
+
-H "x-session-id: abc123" \
|
|
295
|
+
-d '{ "types": ["DDLS/DF", "CLAS/OC"] }'
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Error Handling
|
|
299
|
+
|
|
300
|
+
Catalyst-Relay uses Go-style result tuples instead of throwing exceptions:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const [data, error] = await client.read(objects);
|
|
304
|
+
|
|
305
|
+
if (error) {
|
|
306
|
+
// Handle error
|
|
307
|
+
console.error(error.message);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Use data safely
|
|
312
|
+
console.log(data);
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Every async operation returns `[result, null]` on success or `[null, error]` on failure.
|
|
316
|
+
|
|
317
|
+
## SSL/TLS Configuration
|
|
318
|
+
|
|
319
|
+
SAP systems often use self-signed certificates. Use the `insecure` option to bypass SSL verification:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
const [client] = createClient({
|
|
323
|
+
url: 'https://sap-server:443',
|
|
324
|
+
client: '100',
|
|
325
|
+
auth: { type: 'basic', username: 'user', password: 'pass' },
|
|
326
|
+
insecure: true // Skip SSL verification
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
This uses `undici` under the hood for HTTP requests with SSL bypass support.
|
|
331
|
+
|
|
332
|
+
## Testing
|
|
333
|
+
|
|
334
|
+
### Unit Tests
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
# Run all tests
|
|
338
|
+
bun test
|
|
339
|
+
|
|
340
|
+
# Watch mode
|
|
341
|
+
bun test --watch
|
|
342
|
+
|
|
343
|
+
# Specific test file
|
|
344
|
+
bun test src/__tests__/index.test.ts
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Integration Tests
|
|
348
|
+
|
|
349
|
+
Integration tests connect to a live SAP system and require credentials:
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
# Windows
|
|
353
|
+
./test.bat <SAP_PASSWORD>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Test Coverage
|
|
357
|
+
|
|
358
|
+
| Test File | Coverage |
|
|
359
|
+
|-----------|----------|
|
|
360
|
+
| `index.test.ts` | Client creation, result utilities, object config |
|
|
361
|
+
| `cds-workflow.test.ts` | CDS View + Access Control lifecycle |
|
|
362
|
+
| `abap-class-workflow.test.ts` | ABAP Class CRAUD operations |
|
|
363
|
+
| `abap-program-workflow.test.ts` | ABAP Program CRAUD operations |
|
|
364
|
+
| `table-workflow.test.ts` | Table operations + data preview |
|
|
365
|
+
| `discovery-workflow.test.ts` | Packages, tree browsing, transports |
|
|
366
|
+
| `search-workflow.test.ts` | Object search + where-used analysis |
|
|
367
|
+
| `data-preview-workflow.test.ts` | Table/view data preview |
|
|
368
|
+
| `upsert-workflow.test.ts` | Create vs update detection |
|
|
369
|
+
|
|
370
|
+
## Requirements
|
|
371
|
+
|
|
372
|
+
- **Node.js**: 20.0.0 or higher
|
|
373
|
+
- **Runtime**: Works on both Bun (development) and Node.js (library consumers)
|
|
374
|
+
|
|
375
|
+
The library uses only web standard APIs (`fetch`, `Request`, `Response`, `URL`) for cross-platform compatibility.
|
|
376
|
+
|
|
377
|
+
## Known Limitations
|
|
378
|
+
|
|
379
|
+
- **SAML authentication**: Stubbed out, not yet implemented
|
|
380
|
+
- **SSO (Kerberos) authentication**: Stubbed out, not yet implemented
|
|
381
|
+
- Basic authentication is fully functional
|
|
382
|
+
|
|
383
|
+
## Dependencies
|
|
384
|
+
|
|
385
|
+
| Package | Purpose |
|
|
386
|
+
|---------|---------|
|
|
387
|
+
| `hono` | HTTP server framework (server mode) |
|
|
388
|
+
| `zod` | Runtime schema validation |
|
|
389
|
+
| `undici` | HTTP client with SSL bypass support |
|
|
390
|
+
| `@xmldom/xmldom` | XML parsing for ADT responses |
|
|
391
|
+
| `diff` | Text diffing for git-diff feature |
|
|
392
|
+
|
|
393
|
+
## Project Structure
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
src/
|
|
397
|
+
├── index.ts # Library exports
|
|
398
|
+
├── server.ts # Hono HTTP server
|
|
399
|
+
├── core/ # Pure business logic
|
|
400
|
+
│ ├── client.ts # ADT client implementation
|
|
401
|
+
│ ├── config.ts # Configuration loading
|
|
402
|
+
│ ├── adt/ # ADT operations
|
|
403
|
+
│ ├── auth/ # Authentication strategies
|
|
404
|
+
│ ├── session/ # Session management
|
|
405
|
+
│ └── utils/ # Shared utilities
|
|
406
|
+
├── types/ # TypeScript type definitions
|
|
407
|
+
└── server/ # Server-specific code
|
|
408
|
+
├── routes/ # HTTP route handlers
|
|
409
|
+
└── middleware/ # Hono middleware
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## License
|
|
413
|
+
|
|
414
|
+
MIT
|
|
415
|
+
|
|
416
|
+
## Author
|
|
417
|
+
|
|
418
|
+
Egan Bosch
|