catalyst-relay 0.5.13 → 0.5.14
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 +30 -16
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +80 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -188,7 +188,9 @@ curl -X POST http://localhost:3000/login \
|
|
|
188
188
|
| `asdcls` | Access Control | DCLS/DL |
|
|
189
189
|
| `aclass` | ABAP Class | CLAS/OC |
|
|
190
190
|
| `asprog` | ABAP Program | PROG/P |
|
|
191
|
+
| `asinc` | ABAP Include | PROG/I |
|
|
191
192
|
| `astabldt` | Table | TABL/DT |
|
|
193
|
+
| `astablds` | Structure | STRU/D |
|
|
192
194
|
|
|
193
195
|
## Library Mode API Reference
|
|
194
196
|
|
|
@@ -199,21 +201,28 @@ curl -X POST http://localhost:3000/login \
|
|
|
199
201
|
| `login()` | Authenticate and create session |
|
|
200
202
|
| `logout()` | End session |
|
|
201
203
|
| `refreshSession()` | Manually refresh session (keepalive) |
|
|
204
|
+
| `exportSessionState()` | Serialize session for transfer to another process |
|
|
205
|
+
| `importSessionState(state)` | Restore a previously exported session |
|
|
202
206
|
| `read(objects)` | Batch read with content |
|
|
203
|
-
| `create(object, package, transport?)` | Create new object |
|
|
204
|
-
| `update(object, transport?)` | Update existing object |
|
|
205
|
-
| `upsert(objects, package, transport?)` | Create or update |
|
|
206
|
-
| `activate(objects)` |
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
207
|
+
| `create(object, package, transport?)` | Create a new object |
|
|
208
|
+
| `update(object, transport?)` | Update an existing object |
|
|
209
|
+
| `upsert(objects, package, transport?)` | Create or update a batch |
|
|
210
|
+
| `activate(objects)` | Run-based activation; mixed extensions allowed |
|
|
211
|
+
| `checkSyntax(objects)` | Syntax check (single extension per batch) |
|
|
212
|
+
| `delete(objects, transport?)` | Multi-delete with dependency ordering; returns `DeleteResult[]` |
|
|
213
|
+
| `getPackages(options?)` | List packages (filter, includeDescriptions) |
|
|
214
|
+
| `getPackageStats(nameOrNames)` | Package description and recursive object count |
|
|
210
215
|
| `getTree(query)` | Browse package tree (supports owner filter) |
|
|
211
216
|
| `getTransports(package)` | List transports |
|
|
212
217
|
| `createTransport(config)` | Create transport |
|
|
218
|
+
| `deleteTransport(id, removeObjects?)` | Delete transport (optionally clear contents first) |
|
|
219
|
+
| `removeFromTransport(id, objectName)` | Remove a single object from a transport |
|
|
220
|
+
| `viewTransportObjects(id)` | List tasks and objects on a transport |
|
|
221
|
+
| `getInactiveObjects()` | List objects/transports awaiting activation |
|
|
213
222
|
| `previewData(query)` | Query table/view |
|
|
214
|
-
| `getDistinctValues(
|
|
215
|
-
| `countRows(
|
|
216
|
-
| `search(query,
|
|
223
|
+
| `getDistinctValues(name, parameters, column, type?)` | Distinct values with counts |
|
|
224
|
+
| `countRows(name, type, parameters?)` | Row count |
|
|
225
|
+
| `search(query, options?)` | Search objects (`{ types?, includePackages? }`) |
|
|
217
226
|
| `whereUsed(object)` | Find dependencies |
|
|
218
227
|
| `gitDiff(objects)` | Compare with server |
|
|
219
228
|
| `getObjectConfig()` | Supported object types |
|
|
@@ -261,11 +270,11 @@ if (error) {
|
|
|
261
270
|
#### Searching Objects
|
|
262
271
|
|
|
263
272
|
```typescript
|
|
264
|
-
const [results, error] = await client.search('ZSNAP*', ['DDLS
|
|
273
|
+
const [results, error] = await client.search('ZSNAP*', { types: ['DDLS', 'CLAS'] });
|
|
265
274
|
|
|
266
275
|
if (!error) {
|
|
267
276
|
for (const result of results) {
|
|
268
|
-
console.log(`${result.name} (${result.
|
|
277
|
+
console.log(`${result.name} (${result.objectType})`);
|
|
269
278
|
}
|
|
270
279
|
}
|
|
271
280
|
```
|
|
@@ -294,12 +303,17 @@ const [data, error] = await client.previewData({
|
|
|
294
303
|
| GET | `/packages` | List available packages |
|
|
295
304
|
| GET | `/packages/:name/stats` | Get package metadata and count |
|
|
296
305
|
| POST | `/tree` | Browse package tree (supports owner filter) |
|
|
297
|
-
| GET | `/transports/:package` | List transports |
|
|
306
|
+
| GET | `/transports/:package` | List transports for a package |
|
|
298
307
|
| POST | `/transports` | Create transport |
|
|
308
|
+
| DELETE | `/transports/:transportId` | Delete a transport (`?removeObjects=true` to clear first) |
|
|
309
|
+
| GET | `/transports/:transportId/objects` | List tasks/objects on a transport |
|
|
310
|
+
| PUT | `/transports/:transportId/objects` | Remove a single object from a transport |
|
|
311
|
+
| GET | `/inactive-objects` | List objects/transports awaiting activation |
|
|
299
312
|
| POST | `/objects/read` | Batch read objects |
|
|
300
313
|
| POST | `/objects/upsert/:package/:transport?` | Create/update objects |
|
|
301
314
|
| POST | `/objects/activate` | Activate objects |
|
|
302
|
-
|
|
|
315
|
+
| POST | `/objects/check` | Syntax check objects |
|
|
316
|
+
| DELETE | `/objects/:transport?` | Multi-delete with dependency ordering |
|
|
303
317
|
| POST | `/preview/data` | Query table/view data |
|
|
304
318
|
| POST | `/preview/distinct` | Get distinct values |
|
|
305
319
|
| POST | `/preview/count` | Count rows |
|
|
@@ -346,7 +360,7 @@ curl -X POST http://localhost:3000/preview/data \
|
|
|
346
360
|
curl -X POST "http://localhost:3000/search/ZSNAP*" \
|
|
347
361
|
-H "Content-Type: application/json" \
|
|
348
362
|
-H "x-session-id: abc123" \
|
|
349
|
-
-d '
|
|
363
|
+
-d '["DDLS", "CLAS"]'
|
|
350
364
|
```
|
|
351
365
|
|
|
352
366
|
## Error Handling
|
|
@@ -483,4 +497,4 @@ Egan Bosch
|
|
|
483
497
|
|
|
484
498
|
---
|
|
485
499
|
|
|
486
|
-
*Last updated: v0.
|
|
500
|
+
*Last updated: v0.5.13*
|
package/dist/index.d.mts
CHANGED
|
@@ -597,6 +597,9 @@ interface TransportObject {
|
|
|
597
597
|
|
|
598
598
|
interface TaskContents {
|
|
599
599
|
taskId: string;
|
|
600
|
+
owner?: string;
|
|
601
|
+
description?: string;
|
|
602
|
+
status?: string;
|
|
600
603
|
objects: TransportObject[];
|
|
601
604
|
}
|
|
602
605
|
|
|
@@ -674,6 +677,7 @@ interface ADTClient {
|
|
|
674
677
|
previewData(query: PreviewSQL): AsyncResult<DataFrame>;
|
|
675
678
|
getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
|
|
676
679
|
countRows(objectName: string, objectType: 'table' | 'view', parameters?: Parameter[]): AsyncResult<number>;
|
|
680
|
+
freestyleQuery(sqlQuery: string, limit?: number, timeout?: number): AsyncResult<DataFrame>;
|
|
677
681
|
search(query: string, options?: SearchOptions): AsyncResult<SearchResult[]>;
|
|
678
682
|
whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;
|
|
679
683
|
createTransport(config: TransportConfig): AsyncResult<string>;
|
package/dist/index.d.ts
CHANGED
|
@@ -597,6 +597,9 @@ interface TransportObject {
|
|
|
597
597
|
|
|
598
598
|
interface TaskContents {
|
|
599
599
|
taskId: string;
|
|
600
|
+
owner?: string;
|
|
601
|
+
description?: string;
|
|
602
|
+
status?: string;
|
|
600
603
|
objects: TransportObject[];
|
|
601
604
|
}
|
|
602
605
|
|
|
@@ -674,6 +677,7 @@ interface ADTClient {
|
|
|
674
677
|
previewData(query: PreviewSQL): AsyncResult<DataFrame>;
|
|
675
678
|
getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
|
|
676
679
|
countRows(objectName: string, objectType: 'table' | 'view', parameters?: Parameter[]): AsyncResult<number>;
|
|
680
|
+
freestyleQuery(sqlQuery: string, limit?: number, timeout?: number): AsyncResult<DataFrame>;
|
|
677
681
|
search(query: string, options?: SearchOptions): AsyncResult<SearchResult[]>;
|
|
678
682
|
whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;
|
|
679
683
|
createTransport(config: TransportConfig): AsyncResult<string>;
|
package/dist/index.js
CHANGED
|
@@ -2381,16 +2381,64 @@ function parseDataPreview(xml, maxRows, isTable) {
|
|
|
2381
2381
|
const namespace = "http://www.sap.com/adt/dataPreview";
|
|
2382
2382
|
const metadataElements = doc.getElementsByTagNameNS(namespace, "metadata");
|
|
2383
2383
|
const columns = [];
|
|
2384
|
+
const SAP_TYPE_MAP = {
|
|
2385
|
+
"8": "integer",
|
|
2386
|
+
// Int8
|
|
2387
|
+
"I": "integer",
|
|
2388
|
+
// Integer
|
|
2389
|
+
"P": "decimal",
|
|
2390
|
+
// Packed decimal
|
|
2391
|
+
"F": "float",
|
|
2392
|
+
// Floating point
|
|
2393
|
+
"D": "date",
|
|
2394
|
+
// Date (YYYYMMDD)
|
|
2395
|
+
"T": "time",
|
|
2396
|
+
// Time (HHMMSS)
|
|
2397
|
+
"S": "timestamp",
|
|
2398
|
+
// Timestamp
|
|
2399
|
+
"C": "string",
|
|
2400
|
+
// Character
|
|
2401
|
+
"N": "string",
|
|
2402
|
+
// Numeric character string
|
|
2403
|
+
"V": "string",
|
|
2404
|
+
// Variable-length character
|
|
2405
|
+
"X": "binary"
|
|
2406
|
+
// Raw binary/hex
|
|
2407
|
+
};
|
|
2384
2408
|
for (let i = 0; i < metadataElements.length; i++) {
|
|
2385
2409
|
const meta = metadataElements[i];
|
|
2386
2410
|
if (!meta) continue;
|
|
2387
2411
|
const nameAttr = isTable ? "name" : "camelCaseName";
|
|
2388
2412
|
const name = meta.getAttributeNS(namespace, nameAttr) || meta.getAttribute("name");
|
|
2389
|
-
const
|
|
2413
|
+
const colType = meta.getAttributeNS(namespace, "colType") || meta.getAttribute("colType");
|
|
2414
|
+
const rawType = meta.getAttributeNS(namespace, "type") || meta.getAttribute("type");
|
|
2415
|
+
const isKeyFigure = meta.getAttributeNS(namespace, "isKeyFigure") === "true";
|
|
2416
|
+
let dataType;
|
|
2417
|
+
if (colType && colType.trim() !== "") {
|
|
2418
|
+
dataType = colType;
|
|
2419
|
+
} else if (isKeyFigure) {
|
|
2420
|
+
dataType = "decimal";
|
|
2421
|
+
} else if (rawType && SAP_TYPE_MAP[rawType]) {
|
|
2422
|
+
dataType = SAP_TYPE_MAP[rawType];
|
|
2423
|
+
} else {
|
|
2424
|
+
dataType = "string";
|
|
2425
|
+
}
|
|
2426
|
+
const allAttrs = {};
|
|
2427
|
+
for (let j = 0; j < meta.attributes.length; j++) {
|
|
2428
|
+
const attr = meta.attributes[j];
|
|
2429
|
+
if (!attr) {
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2432
|
+
allAttrs[attr.name] = attr.value;
|
|
2433
|
+
}
|
|
2390
2434
|
if (!name || !dataType) continue;
|
|
2391
2435
|
columns.push({ name, dataType });
|
|
2392
2436
|
}
|
|
2393
2437
|
const dataSetElements = doc.getElementsByTagNameNS(namespace, "dataSet");
|
|
2438
|
+
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2439
|
+
const dataSet = dataSetElements[i];
|
|
2440
|
+
if (!dataSet) continue;
|
|
2441
|
+
}
|
|
2394
2442
|
if (columns.length === 0 && dataSetElements.length > 0) {
|
|
2395
2443
|
for (let i = 0; i < dataSetElements.length; i++) {
|
|
2396
2444
|
const dataSet = dataSetElements[i];
|
|
@@ -2473,7 +2521,7 @@ async function previewData(client, query) {
|
|
|
2473
2521
|
|
|
2474
2522
|
// src/core/adt/data_extraction/freestyle.ts
|
|
2475
2523
|
var DEFAULT_ROW_LIMIT = 100;
|
|
2476
|
-
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
2524
|
+
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT, timeout) {
|
|
2477
2525
|
debug(`Freestyle query: ${sqlQuery}`);
|
|
2478
2526
|
const [response, requestErr] = await client.request({
|
|
2479
2527
|
method: "POST",
|
|
@@ -2483,16 +2531,21 @@ async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
|
2483
2531
|
},
|
|
2484
2532
|
headers: {
|
|
2485
2533
|
"Accept": "application/xml, application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
2486
|
-
"Content-Type": "text/plain"
|
|
2534
|
+
"Content-Type": "text/plain",
|
|
2535
|
+
// Override stateful base header: each preview request is independent; stateless
|
|
2536
|
+
// lets SAP route to any work process and recycle it after the request, preventing
|
|
2537
|
+
// GENERATE_SUBPOOL_DIR_FULL (36-pool limit per work process).
|
|
2538
|
+
"X-sap-adt-sessiontype": "stateless"
|
|
2487
2539
|
},
|
|
2488
|
-
body: sqlQuery
|
|
2540
|
+
body: sqlQuery,
|
|
2541
|
+
...timeout !== void 0 && { timeout }
|
|
2489
2542
|
});
|
|
2490
2543
|
if (requestErr) return err(requestErr);
|
|
2491
2544
|
if (!response.ok) {
|
|
2492
2545
|
const text2 = await response.text();
|
|
2493
2546
|
debug(`Freestyle query error response: ${text2.substring(0, 500)}`);
|
|
2494
2547
|
const errorMsg = extractError(text2);
|
|
2495
|
-
return err(new Error(`Freestyle query failed: ${errorMsg}
|
|
2548
|
+
return err(new Error(`Freestyle query failed: ${errorMsg}`, { cause: text2 }));
|
|
2496
2549
|
}
|
|
2497
2550
|
const text = await response.text();
|
|
2498
2551
|
const [dataFrame, parseErr] = parseDataPreview(text, limit, true);
|
|
@@ -2753,7 +2806,16 @@ function parseTransportTasks(doc) {
|
|
|
2753
2806
|
position: el.getAttribute("tm:position") || ""
|
|
2754
2807
|
});
|
|
2755
2808
|
}
|
|
2756
|
-
|
|
2809
|
+
const owner = taskEl.getAttribute("tm:owner");
|
|
2810
|
+
const description = taskEl.getAttribute("tm:desc");
|
|
2811
|
+
const status = taskEl.getAttribute("tm:status");
|
|
2812
|
+
tasks.push({
|
|
2813
|
+
taskId,
|
|
2814
|
+
...owner ? { owner } : {},
|
|
2815
|
+
...description ? { description } : {},
|
|
2816
|
+
...status ? { status } : {},
|
|
2817
|
+
objects
|
|
2818
|
+
});
|
|
2757
2819
|
}
|
|
2758
2820
|
return tasks;
|
|
2759
2821
|
}
|
|
@@ -3147,6 +3209,12 @@ async function countRows2(state, requestor, objectName, objectType, parameters =
|
|
|
3147
3209
|
return countRows(requestor, objectName, objectType, parameters);
|
|
3148
3210
|
}
|
|
3149
3211
|
|
|
3212
|
+
// src/client/methods/preview/freestyleQuery.ts
|
|
3213
|
+
async function freestyleQuery2(state, requestor, sqlQuery, limit, timeout) {
|
|
3214
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
3215
|
+
return freestyleQuery(requestor, sqlQuery, limit, timeout);
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3150
3218
|
// src/client/methods/search/search.ts
|
|
3151
3219
|
async function search(state, requestor, query, options) {
|
|
3152
3220
|
if (!state.session) return err(new Error("Not logged in"));
|
|
@@ -3330,7 +3398,7 @@ function buildUrl2(baseUrl, path, params) {
|
|
|
3330
3398
|
// src/client/methods/internal/request.ts
|
|
3331
3399
|
async function executeRequest(deps, options, selfRequest) {
|
|
3332
3400
|
const { state, ssoCerts, getCookieHeader, storeCookies: storeCookies2 } = deps;
|
|
3333
|
-
const { method, path, params, headers: customHeaders, body } = options;
|
|
3401
|
+
const { method, path, params, headers: customHeaders, body, timeout: requestTimeout } = options;
|
|
3334
3402
|
const { config } = state;
|
|
3335
3403
|
debug(`Request ${method} ${path} - CSRF token in state: ${state.csrfToken?.substring(0, 20) || "null"}...`);
|
|
3336
3404
|
const headers = buildRequestHeaders(
|
|
@@ -3357,7 +3425,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3357
3425
|
cert: ssoCerts?.cert,
|
|
3358
3426
|
key: ssoCerts?.key,
|
|
3359
3427
|
rejectUnauthorized: !config.insecure,
|
|
3360
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3428
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3361
3429
|
});
|
|
3362
3430
|
storeCookies2(response);
|
|
3363
3431
|
if (response.status === 403) {
|
|
@@ -3380,7 +3448,7 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
3380
3448
|
cert: ssoCerts?.cert,
|
|
3381
3449
|
key: ssoCerts?.key,
|
|
3382
3450
|
rejectUnauthorized: !config.insecure,
|
|
3383
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
3451
|
+
timeout: requestTimeout ?? config.timeout ?? DEFAULT_TIMEOUT
|
|
3384
3452
|
});
|
|
3385
3453
|
storeCookies2(retryResponse);
|
|
3386
3454
|
return ok(retryResponse);
|
|
@@ -3551,6 +3619,9 @@ var ADTClientImpl = class {
|
|
|
3551
3619
|
async countRows(objectName, objectType, parameters = []) {
|
|
3552
3620
|
return countRows2(this.state, this.requestor, objectName, objectType, parameters);
|
|
3553
3621
|
}
|
|
3622
|
+
async freestyleQuery(sqlQuery, limit, timeout) {
|
|
3623
|
+
return freestyleQuery2(this.state, this.requestor, sqlQuery, limit, timeout);
|
|
3624
|
+
}
|
|
3554
3625
|
// --- Search ---
|
|
3555
3626
|
async search(query, options) {
|
|
3556
3627
|
return search(this.state, this.requestor, query, options);
|