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 ADDED
@@ -0,0 +1,418 @@
1
+ # Catalyst-Relay
2
+
3
+ [![npm version](https://img.shields.io/npm/v/catalyst-relay.svg)](https://www.npmjs.com/package/catalyst-relay)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen.svg)](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