catalyst-relay 0.4.5 → 0.4.6
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/dist/index.js +69 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +69 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -255,7 +255,7 @@ var DEFAULT_SESSION_CONFIG = {
|
|
|
255
255
|
};
|
|
256
256
|
|
|
257
257
|
// src/core/session/login.ts
|
|
258
|
-
async function fetchCsrfToken(state,
|
|
258
|
+
async function fetchCsrfToken(state, request4) {
|
|
259
259
|
const endpoint = state.config.auth.type === "saml" ? "/sap/bc/adt/core/http/sessions" : "/sap/bc/adt/compatibility/graph";
|
|
260
260
|
const contentType = state.config.auth.type === "saml" ? "application/vnd.sap.adt.core.http.session.v3+xml" : "application/xml";
|
|
261
261
|
const headers = {
|
|
@@ -263,7 +263,7 @@ async function fetchCsrfToken(state, request3) {
|
|
|
263
263
|
"Content-Type": contentType,
|
|
264
264
|
"Accept": contentType
|
|
265
265
|
};
|
|
266
|
-
const [response, requestErr] = await
|
|
266
|
+
const [response, requestErr] = await request4({
|
|
267
267
|
method: "GET",
|
|
268
268
|
path: endpoint,
|
|
269
269
|
headers
|
|
@@ -313,8 +313,8 @@ function extractUsername(auth) {
|
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
|
-
async function login(state,
|
|
317
|
-
const [token, tokenErr] = await fetchCsrfToken(state,
|
|
316
|
+
async function login(state, request4) {
|
|
317
|
+
const [token, tokenErr] = await fetchCsrfToken(state, request4);
|
|
318
318
|
if (tokenErr) {
|
|
319
319
|
return err(new Error(`Login failed: ${tokenErr.message}`));
|
|
320
320
|
}
|
|
@@ -328,8 +328,8 @@ async function login(state, request3) {
|
|
|
328
328
|
state.session = session;
|
|
329
329
|
return ok(session);
|
|
330
330
|
}
|
|
331
|
-
async function logout(state,
|
|
332
|
-
const [response, requestErr] = await
|
|
331
|
+
async function logout(state, request4) {
|
|
332
|
+
const [response, requestErr] = await request4({
|
|
333
333
|
method: "POST",
|
|
334
334
|
path: "/sap/public/bc/icf/logoff"
|
|
335
335
|
});
|
|
@@ -344,11 +344,11 @@ async function logout(state, request3) {
|
|
|
344
344
|
state.session = null;
|
|
345
345
|
return ok(void 0);
|
|
346
346
|
}
|
|
347
|
-
async function sessionReset(state,
|
|
348
|
-
await logout(state,
|
|
347
|
+
async function sessionReset(state, request4) {
|
|
348
|
+
await logout(state, request4);
|
|
349
349
|
state.csrfToken = null;
|
|
350
350
|
state.session = null;
|
|
351
|
-
const [, loginErr] = await login(state,
|
|
351
|
+
const [, loginErr] = await login(state, request4);
|
|
352
352
|
if (loginErr) {
|
|
353
353
|
return err(loginErr);
|
|
354
354
|
}
|
|
@@ -357,12 +357,12 @@ async function sessionReset(state, request3) {
|
|
|
357
357
|
|
|
358
358
|
// src/core/session/refresh.ts
|
|
359
359
|
var REENTRANCE_TICKET_PATH = "/sap/bc/adt/security/reentranceticket";
|
|
360
|
-
async function refreshSession(state,
|
|
360
|
+
async function refreshSession(state, request4) {
|
|
361
361
|
if (!state.session) {
|
|
362
362
|
return err(new Error("Not logged in"));
|
|
363
363
|
}
|
|
364
364
|
debug("Fetching reentrance ticket to refresh session...");
|
|
365
|
-
const [response, reqErr] = await
|
|
365
|
+
const [response, reqErr] = await request4({
|
|
366
366
|
method: "GET",
|
|
367
367
|
path: REENTRANCE_TICKET_PATH,
|
|
368
368
|
headers: { "Accept": "text/plain" }
|
|
@@ -1242,6 +1242,35 @@ async function previewData(client, query) {
|
|
|
1242
1242
|
return ok(dataFrame);
|
|
1243
1243
|
}
|
|
1244
1244
|
|
|
1245
|
+
// src/core/adt/data_extraction/freestyle.ts
|
|
1246
|
+
var DEFAULT_ROW_LIMIT = 100;
|
|
1247
|
+
async function freestyleQuery(client, sqlQuery, limit = DEFAULT_ROW_LIMIT) {
|
|
1248
|
+
debug(`Freestyle query: ${sqlQuery}`);
|
|
1249
|
+
const [response, requestErr] = await client.request({
|
|
1250
|
+
method: "POST",
|
|
1251
|
+
path: "/sap/bc/adt/datapreview/freestyle",
|
|
1252
|
+
params: {
|
|
1253
|
+
"rowNumber": limit
|
|
1254
|
+
},
|
|
1255
|
+
headers: {
|
|
1256
|
+
"Accept": "application/xml, application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
1257
|
+
"Content-Type": "text/plain"
|
|
1258
|
+
},
|
|
1259
|
+
body: sqlQuery
|
|
1260
|
+
});
|
|
1261
|
+
if (requestErr) return err(requestErr);
|
|
1262
|
+
if (!response.ok) {
|
|
1263
|
+
const text2 = await response.text();
|
|
1264
|
+
debug(`Freestyle query error response: ${text2.substring(0, 500)}`);
|
|
1265
|
+
const errorMsg = extractError(text2);
|
|
1266
|
+
return err(new Error(`Freestyle query failed: ${errorMsg}`));
|
|
1267
|
+
}
|
|
1268
|
+
const text = await response.text();
|
|
1269
|
+
const [dataFrame, parseErr] = parseDataPreview(text, limit, true);
|
|
1270
|
+
if (parseErr) return err(parseErr);
|
|
1271
|
+
return ok(dataFrame);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1245
1274
|
// src/core/adt/data_extraction/queryBuilder.ts
|
|
1246
1275
|
function quoteString(value) {
|
|
1247
1276
|
return typeof value == "string" ? "'" + value + "'" : "" + value;
|
|
@@ -1316,15 +1345,10 @@ from ${query.objectName}${parametersToSQLParams(parameters)} as main
|
|
|
1316
1345
|
|
|
1317
1346
|
// src/core/adt/data_extraction/distinct.ts
|
|
1318
1347
|
var MAX_ROW_COUNT = 5e4;
|
|
1319
|
-
async function getDistinctValues(client, objectName, parameters, column,
|
|
1348
|
+
async function getDistinctValues(client, objectName, parameters, column, _objectType = "view") {
|
|
1320
1349
|
const columnName = column.toUpperCase();
|
|
1321
|
-
const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS
|
|
1322
|
-
const [dataFrame, error] = await
|
|
1323
|
-
objectName,
|
|
1324
|
-
objectType,
|
|
1325
|
-
sqlQuery,
|
|
1326
|
-
limit: MAX_ROW_COUNT
|
|
1327
|
-
});
|
|
1350
|
+
const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS value_count FROM ${objectName}${parametersToSQLParams(parameters)} GROUP BY ${columnName} ORDER BY value_count DESCENDING`;
|
|
1351
|
+
const [dataFrame, error] = await freestyleQuery(client, sqlQuery, MAX_ROW_COUNT);
|
|
1328
1352
|
if (error) {
|
|
1329
1353
|
return err(new Error(`Distinct values query failed: ${error.message}`));
|
|
1330
1354
|
}
|
|
@@ -1336,14 +1360,9 @@ async function getDistinctValues(client, objectName, parameters, column, objectT
|
|
|
1336
1360
|
}
|
|
1337
1361
|
|
|
1338
1362
|
// src/core/adt/data_extraction/count.ts
|
|
1339
|
-
async function countRows(client, objectName,
|
|
1340
|
-
const sqlQuery = `SELECT COUNT(*) AS
|
|
1341
|
-
const [dataFrame, error] = await
|
|
1342
|
-
objectName,
|
|
1343
|
-
objectType,
|
|
1344
|
-
sqlQuery,
|
|
1345
|
-
limit: 1
|
|
1346
|
-
});
|
|
1363
|
+
async function countRows(client, objectName, _objectType) {
|
|
1364
|
+
const sqlQuery = `SELECT COUNT(*) AS row_count FROM ${objectName}`;
|
|
1365
|
+
const [dataFrame, error] = await freestyleQuery(client, sqlQuery, 1);
|
|
1347
1366
|
if (error) {
|
|
1348
1367
|
return err(new Error(`Row count query failed: ${error.message}`));
|
|
1349
1368
|
}
|
|
@@ -2246,13 +2265,22 @@ function createAuthStrategy(options) {
|
|
|
2246
2265
|
}
|
|
2247
2266
|
|
|
2248
2267
|
// src/core/client.ts
|
|
2268
|
+
var http = __toESM(require("http"));
|
|
2249
2269
|
var https2 = __toESM(require("https"));
|
|
2250
|
-
|
|
2270
|
+
var MAX_REDIRECTS = 5;
|
|
2271
|
+
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
2272
|
+
async function httpRequest(url, options, redirectCount = 0) {
|
|
2273
|
+
if (redirectCount > MAX_REDIRECTS) {
|
|
2274
|
+
throw new Error(`Too many redirects (max ${MAX_REDIRECTS})`);
|
|
2275
|
+
}
|
|
2251
2276
|
const urlObj = new URL(url);
|
|
2277
|
+
const isHttps = urlObj.protocol === "https:";
|
|
2278
|
+
const requestFn = isHttps ? https2.request : http.request;
|
|
2279
|
+
const defaultPort = isHttps ? 443 : 80;
|
|
2252
2280
|
return new Promise((resolve, reject) => {
|
|
2253
|
-
const req =
|
|
2281
|
+
const req = requestFn({
|
|
2254
2282
|
hostname: urlObj.hostname,
|
|
2255
|
-
port: urlObj.port ||
|
|
2283
|
+
port: urlObj.port || defaultPort,
|
|
2256
2284
|
path: urlObj.pathname + urlObj.search,
|
|
2257
2285
|
method: options.method,
|
|
2258
2286
|
headers: options.headers,
|
|
@@ -2261,6 +2289,14 @@ async function httpsRequest2(url, options) {
|
|
|
2261
2289
|
rejectUnauthorized: options.rejectUnauthorized ?? true,
|
|
2262
2290
|
timeout: options.timeout
|
|
2263
2291
|
}, (res) => {
|
|
2292
|
+
const statusCode = res.statusCode || 0;
|
|
2293
|
+
if (REDIRECT_STATUSES.has(statusCode) && res.headers.location) {
|
|
2294
|
+
const redirectUrl = new URL(res.headers.location, url).toString();
|
|
2295
|
+
const redirectMethod = statusCode === 303 ? "GET" : options.method;
|
|
2296
|
+
const redirectBody = statusCode === 303 ? void 0 : options.body;
|
|
2297
|
+
httpRequest(redirectUrl, { ...options, method: redirectMethod, body: redirectBody }, redirectCount + 1).then(resolve).catch(reject);
|
|
2298
|
+
return;
|
|
2299
|
+
}
|
|
2264
2300
|
const chunks = [];
|
|
2265
2301
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
2266
2302
|
res.on("end", () => {
|
|
@@ -2276,7 +2312,7 @@ async function httpsRequest2(url, options) {
|
|
|
2276
2312
|
}
|
|
2277
2313
|
}
|
|
2278
2314
|
resolve(new Response(body, {
|
|
2279
|
-
status:
|
|
2315
|
+
status: statusCode,
|
|
2280
2316
|
statusText: res.statusMessage || "",
|
|
2281
2317
|
headers
|
|
2282
2318
|
}));
|
|
@@ -2395,7 +2431,7 @@ var ADTClientImpl = class {
|
|
|
2395
2431
|
try {
|
|
2396
2432
|
debug(`Fetching URL: ${url}`);
|
|
2397
2433
|
debug(`mTLS: ${!!this.ssoCerts}, insecure: ${config.insecure}`);
|
|
2398
|
-
const response = await
|
|
2434
|
+
const response = await httpRequest(url, {
|
|
2399
2435
|
method,
|
|
2400
2436
|
headers,
|
|
2401
2437
|
body,
|
|
@@ -2418,7 +2454,7 @@ var ADTClientImpl = class {
|
|
|
2418
2454
|
headers["Cookie"] = retryCookieHeader;
|
|
2419
2455
|
}
|
|
2420
2456
|
debug(`Retrying with new CSRF token: ${newToken.substring(0, 20)}...`);
|
|
2421
|
-
const retryResponse = await
|
|
2457
|
+
const retryResponse = await httpRequest(url, {
|
|
2422
2458
|
method,
|
|
2423
2459
|
headers,
|
|
2424
2460
|
body,
|