catalyst-relay 0.4.3 → 0.4.4
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.d.mts +35 -7
- package/dist/index.d.ts +35 -7
- package/dist/index.js +91 -92
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -92
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -64,6 +64,15 @@ interface SsoAuthConfig {
|
|
|
64
64
|
* Union of all auth configurations
|
|
65
65
|
*/
|
|
66
66
|
type AuthConfig = BasicAuthConfig | SamlAuthConfig | SsoAuthConfig;
|
|
67
|
+
/**
|
|
68
|
+
* Auto-refresh configuration for session keepalive
|
|
69
|
+
*/
|
|
70
|
+
interface AutoRefreshConfig {
|
|
71
|
+
/** Enable automatic session refresh (default: true) */
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
/** Refresh interval in milliseconds (default: 7200000 = 2 hours) */
|
|
74
|
+
intervalMs?: number;
|
|
75
|
+
}
|
|
67
76
|
/**
|
|
68
77
|
* Client configuration for connecting to SAP ADT
|
|
69
78
|
*/
|
|
@@ -78,6 +87,8 @@ interface ClientConfig {
|
|
|
78
87
|
timeout?: number;
|
|
79
88
|
/** Skip SSL verification (dev only) */
|
|
80
89
|
insecure?: boolean;
|
|
90
|
+
/** Auto-refresh configuration for session keepalive (default: enabled with 2-hour interval) */
|
|
91
|
+
autoRefresh?: AutoRefreshConfig;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
/**
|
|
@@ -187,6 +198,27 @@ interface Session {
|
|
|
187
198
|
expiresAt: number;
|
|
188
199
|
}
|
|
189
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Session Refresh via Reentrance Ticket
|
|
203
|
+
*
|
|
204
|
+
* Fetches a reentrance ticket from SAP ADT to keep the session alive.
|
|
205
|
+
* Eclipse ADT uses this mechanism to maintain sessions across extended periods.
|
|
206
|
+
*
|
|
207
|
+
* Endpoint: GET /sap/bc/adt/security/reentranceticket
|
|
208
|
+
* - Returns a base64-encoded SSO ticket
|
|
209
|
+
* - Refreshes server-side session cookies (MYSAPSSO2)
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Result of a session refresh operation
|
|
214
|
+
*/
|
|
215
|
+
interface RefreshResult {
|
|
216
|
+
/** Base64-encoded reentrance ticket */
|
|
217
|
+
ticket: string;
|
|
218
|
+
/** Updated session expiration timestamp (ms since epoch) */
|
|
219
|
+
expiresAt: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
190
222
|
interface ObjectConfig {
|
|
191
223
|
/** ADT endpoint path (e.g., 'ddic/ddl/sources') */
|
|
192
224
|
endpoint: string;
|
|
@@ -273,16 +305,11 @@ interface FolderNode {
|
|
|
273
305
|
displayName: string;
|
|
274
306
|
numContents: number;
|
|
275
307
|
}
|
|
276
|
-
interface ApiState {
|
|
277
|
-
useInCloudDevelopment: boolean;
|
|
278
|
-
useInCloudDvlpmntActive: boolean;
|
|
279
|
-
useInKeyUserApps: boolean;
|
|
280
|
-
}
|
|
281
308
|
interface ObjectNode {
|
|
282
309
|
name: string;
|
|
283
310
|
objectType: string;
|
|
284
311
|
extension: string;
|
|
285
|
-
|
|
312
|
+
description?: string;
|
|
286
313
|
}
|
|
287
314
|
|
|
288
315
|
/**
|
|
@@ -487,6 +514,7 @@ interface ADTClient {
|
|
|
487
514
|
readonly session: Session | null;
|
|
488
515
|
login(): AsyncResult<Session>;
|
|
489
516
|
logout(): AsyncResult<void>;
|
|
517
|
+
refreshSession(): AsyncResult<RefreshResult>;
|
|
490
518
|
read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]>;
|
|
491
519
|
create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void>;
|
|
492
520
|
update(object: ObjectContent, transport?: string): AsyncResult<void>;
|
|
@@ -509,4 +537,4 @@ interface ADTClient {
|
|
|
509
537
|
}
|
|
510
538
|
declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
|
|
511
539
|
|
|
512
|
-
export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type
|
|
540
|
+
export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type FolderNode, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeQuery, type TreeResponse, type UpsertResult, buildSQLQuery, createClient, err, ok };
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,15 @@ interface SsoAuthConfig {
|
|
|
64
64
|
* Union of all auth configurations
|
|
65
65
|
*/
|
|
66
66
|
type AuthConfig = BasicAuthConfig | SamlAuthConfig | SsoAuthConfig;
|
|
67
|
+
/**
|
|
68
|
+
* Auto-refresh configuration for session keepalive
|
|
69
|
+
*/
|
|
70
|
+
interface AutoRefreshConfig {
|
|
71
|
+
/** Enable automatic session refresh (default: true) */
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
/** Refresh interval in milliseconds (default: 7200000 = 2 hours) */
|
|
74
|
+
intervalMs?: number;
|
|
75
|
+
}
|
|
67
76
|
/**
|
|
68
77
|
* Client configuration for connecting to SAP ADT
|
|
69
78
|
*/
|
|
@@ -78,6 +87,8 @@ interface ClientConfig {
|
|
|
78
87
|
timeout?: number;
|
|
79
88
|
/** Skip SSL verification (dev only) */
|
|
80
89
|
insecure?: boolean;
|
|
90
|
+
/** Auto-refresh configuration for session keepalive (default: enabled with 2-hour interval) */
|
|
91
|
+
autoRefresh?: AutoRefreshConfig;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
/**
|
|
@@ -187,6 +198,27 @@ interface Session {
|
|
|
187
198
|
expiresAt: number;
|
|
188
199
|
}
|
|
189
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Session Refresh via Reentrance Ticket
|
|
203
|
+
*
|
|
204
|
+
* Fetches a reentrance ticket from SAP ADT to keep the session alive.
|
|
205
|
+
* Eclipse ADT uses this mechanism to maintain sessions across extended periods.
|
|
206
|
+
*
|
|
207
|
+
* Endpoint: GET /sap/bc/adt/security/reentranceticket
|
|
208
|
+
* - Returns a base64-encoded SSO ticket
|
|
209
|
+
* - Refreshes server-side session cookies (MYSAPSSO2)
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Result of a session refresh operation
|
|
214
|
+
*/
|
|
215
|
+
interface RefreshResult {
|
|
216
|
+
/** Base64-encoded reentrance ticket */
|
|
217
|
+
ticket: string;
|
|
218
|
+
/** Updated session expiration timestamp (ms since epoch) */
|
|
219
|
+
expiresAt: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
190
222
|
interface ObjectConfig {
|
|
191
223
|
/** ADT endpoint path (e.g., 'ddic/ddl/sources') */
|
|
192
224
|
endpoint: string;
|
|
@@ -273,16 +305,11 @@ interface FolderNode {
|
|
|
273
305
|
displayName: string;
|
|
274
306
|
numContents: number;
|
|
275
307
|
}
|
|
276
|
-
interface ApiState {
|
|
277
|
-
useInCloudDevelopment: boolean;
|
|
278
|
-
useInCloudDvlpmntActive: boolean;
|
|
279
|
-
useInKeyUserApps: boolean;
|
|
280
|
-
}
|
|
281
308
|
interface ObjectNode {
|
|
282
309
|
name: string;
|
|
283
310
|
objectType: string;
|
|
284
311
|
extension: string;
|
|
285
|
-
|
|
312
|
+
description?: string;
|
|
286
313
|
}
|
|
287
314
|
|
|
288
315
|
/**
|
|
@@ -487,6 +514,7 @@ interface ADTClient {
|
|
|
487
514
|
readonly session: Session | null;
|
|
488
515
|
login(): AsyncResult<Session>;
|
|
489
516
|
logout(): AsyncResult<void>;
|
|
517
|
+
refreshSession(): AsyncResult<RefreshResult>;
|
|
490
518
|
read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]>;
|
|
491
519
|
create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void>;
|
|
492
520
|
update(object: ObjectContent, transport?: string): AsyncResult<void>;
|
|
@@ -509,4 +537,4 @@ interface ADTClient {
|
|
|
509
537
|
}
|
|
510
538
|
declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
|
|
511
539
|
|
|
512
|
-
export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type
|
|
540
|
+
export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type FolderNode, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeQuery, type TreeResponse, type UpsertResult, buildSQLQuery, createClient, err, ok };
|
package/dist/index.js
CHANGED
|
@@ -237,7 +237,11 @@ var clientConfigSchema = import_zod.z.object({
|
|
|
237
237
|
})
|
|
238
238
|
]),
|
|
239
239
|
timeout: import_zod.z.number().positive().optional(),
|
|
240
|
-
insecure: import_zod.z.boolean().optional()
|
|
240
|
+
insecure: import_zod.z.boolean().optional(),
|
|
241
|
+
autoRefresh: import_zod.z.object({
|
|
242
|
+
enabled: import_zod.z.boolean(),
|
|
243
|
+
intervalMs: import_zod.z.number().positive().optional()
|
|
244
|
+
}).optional()
|
|
241
245
|
});
|
|
242
246
|
|
|
243
247
|
// src/core/session/types.ts
|
|
@@ -351,6 +355,33 @@ async function sessionReset(state, request3) {
|
|
|
351
355
|
return ok(void 0);
|
|
352
356
|
}
|
|
353
357
|
|
|
358
|
+
// src/core/session/refresh.ts
|
|
359
|
+
var REENTRANCE_TICKET_PATH = "/sap/bc/adt/security/reentranceticket";
|
|
360
|
+
async function refreshSession(state, request3) {
|
|
361
|
+
if (!state.session) {
|
|
362
|
+
return err(new Error("Not logged in"));
|
|
363
|
+
}
|
|
364
|
+
debug("Fetching reentrance ticket to refresh session...");
|
|
365
|
+
const [response, reqErr] = await request3({
|
|
366
|
+
method: "GET",
|
|
367
|
+
path: REENTRANCE_TICKET_PATH,
|
|
368
|
+
headers: { "Accept": "text/plain" }
|
|
369
|
+
});
|
|
370
|
+
if (reqErr) {
|
|
371
|
+
return err(new Error(`Session refresh failed: ${reqErr.message}`));
|
|
372
|
+
}
|
|
373
|
+
if (!response.ok) {
|
|
374
|
+
const text = await response.text();
|
|
375
|
+
return err(new Error(`Session refresh failed (${response.status}): ${text}`));
|
|
376
|
+
}
|
|
377
|
+
const ticket = await response.text();
|
|
378
|
+
debug(`Received reentrance ticket: ${ticket.substring(0, 20)}...`);
|
|
379
|
+
const timeout = getSessionTimeout(state.config.auth.type);
|
|
380
|
+
state.session.expiresAt = Date.now() + timeout;
|
|
381
|
+
debug(`Session refreshed, new expiration: ${new Date(state.session.expiresAt).toISOString()}`);
|
|
382
|
+
return ok({ ticket, expiresAt: state.session.expiresAt });
|
|
383
|
+
}
|
|
384
|
+
|
|
354
385
|
// src/core/adt/types.ts
|
|
355
386
|
var OBJECT_CONFIG_MAP = {
|
|
356
387
|
"asddls": {
|
|
@@ -745,14 +776,6 @@ async function getPackages(client, filter = "*") {
|
|
|
745
776
|
return ok(packages);
|
|
746
777
|
}
|
|
747
778
|
|
|
748
|
-
// src/core/adt/discovery/tree/types.ts
|
|
749
|
-
var API_FOLDERS = [
|
|
750
|
-
"NOT_RELEASED",
|
|
751
|
-
"USE_IN_CLOUD_DEVELOPMENT",
|
|
752
|
-
"USE_IN_CLOUD_DVLPMNT_ACTIVE",
|
|
753
|
-
"USE_IN_KEY_USER_APPS"
|
|
754
|
-
];
|
|
755
|
-
|
|
756
779
|
// src/core/adt/discovery/tree/parsers.ts
|
|
757
780
|
function buildQueryFromPath(packageName, path) {
|
|
758
781
|
const query = {
|
|
@@ -795,13 +818,14 @@ function constructTreeBody(query, searchPattern) {
|
|
|
795
818
|
const specifiedXml = Object.entries(specified).map(([facet, name]) => ` <vfs:preselection facet="${facet.toLowerCase()}">
|
|
796
819
|
<vfs:value>${name}</vfs:value>
|
|
797
820
|
</vfs:preselection>`).join("\n");
|
|
798
|
-
const
|
|
821
|
+
const atObjectLevel = query.PACKAGE && query.GROUP && query.TYPE;
|
|
822
|
+
const facetorderXml = atObjectLevel || facets.length === 0 ? " <vfs:facetorder/>" : ` <vfs:facetorder>
|
|
823
|
+
${facets.map((f) => ` <vfs:facet>${f.toLowerCase()}</vfs:facet>`).join("\n")}
|
|
824
|
+
</vfs:facetorder>`;
|
|
799
825
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
800
826
|
<vfs:virtualFoldersRequest xmlns:vfs="http://www.sap.com/adt/ris/virtualFolders" objectSearchPattern="${searchPattern}">
|
|
801
827
|
${specifiedXml}
|
|
802
|
-
|
|
803
|
-
${facetsXml}
|
|
804
|
-
</vfs:facetorder>
|
|
828
|
+
${facetorderXml}
|
|
805
829
|
</vfs:virtualFoldersRequest>`;
|
|
806
830
|
}
|
|
807
831
|
function parseTreeXml(xml) {
|
|
@@ -842,11 +866,14 @@ function parseTreeXml(xml) {
|
|
|
842
866
|
if (!name || !type) continue;
|
|
843
867
|
const config = getConfigByType(type);
|
|
844
868
|
if (!config) continue;
|
|
845
|
-
|
|
869
|
+
const text = obj.getAttribute("text");
|
|
870
|
+
const parsedObj = {
|
|
846
871
|
name,
|
|
847
872
|
objectType: config.label,
|
|
848
873
|
extension: config.extension
|
|
849
|
-
}
|
|
874
|
+
};
|
|
875
|
+
if (text) parsedObj.description = text;
|
|
876
|
+
objects.push(parsedObj);
|
|
850
877
|
}
|
|
851
878
|
return ok({ folders, objects });
|
|
852
879
|
}
|
|
@@ -870,11 +897,15 @@ function transformToTreeResponse(parsed, queryPackage) {
|
|
|
870
897
|
});
|
|
871
898
|
}
|
|
872
899
|
}
|
|
873
|
-
const objects = parsed.objects.map((obj) =>
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
900
|
+
const objects = parsed.objects.map((obj) => {
|
|
901
|
+
const node = {
|
|
902
|
+
name: obj.name,
|
|
903
|
+
objectType: obj.objectType,
|
|
904
|
+
extension: obj.extension
|
|
905
|
+
};
|
|
906
|
+
if (obj.description) node.description = obj.description;
|
|
907
|
+
return node;
|
|
908
|
+
});
|
|
878
909
|
return { packages, folders, objects };
|
|
879
910
|
}
|
|
880
911
|
|
|
@@ -938,58 +969,6 @@ async function fetchVirtualFolders(client, query) {
|
|
|
938
969
|
const text = await response.text();
|
|
939
970
|
return parseTreeXml(text);
|
|
940
971
|
}
|
|
941
|
-
async function fetchObjectsWithApiState(client, packageName, pathSegments, apiFolders) {
|
|
942
|
-
const group = pathSegments[0];
|
|
943
|
-
const type = pathSegments[1];
|
|
944
|
-
if (!group || !type) return ok([]);
|
|
945
|
-
const apiQueries = apiFolders.map((apiFolder) => ({
|
|
946
|
-
apiFolder,
|
|
947
|
-
query: {
|
|
948
|
-
PACKAGE: { name: `..${packageName}`, hasChildrenOfSameFacet: false },
|
|
949
|
-
GROUP: { name: group, hasChildrenOfSameFacet: false },
|
|
950
|
-
TYPE: { name: type, hasChildrenOfSameFacet: false },
|
|
951
|
-
API: { name: apiFolder, hasChildrenOfSameFacet: false }
|
|
952
|
-
}
|
|
953
|
-
}));
|
|
954
|
-
const results = await Promise.all(
|
|
955
|
-
apiQueries.map(async ({ apiFolder, query }) => {
|
|
956
|
-
const [parsed, parseErr] = await fetchVirtualFolders(client, query);
|
|
957
|
-
if (parseErr) return { apiFolder, objects: [], error: parseErr };
|
|
958
|
-
return { apiFolder, objects: parsed.objects, error: null };
|
|
959
|
-
})
|
|
960
|
-
);
|
|
961
|
-
const errors = results.filter((r) => r.error !== null);
|
|
962
|
-
if (errors.length === results.length) {
|
|
963
|
-
return err(errors[0].error);
|
|
964
|
-
}
|
|
965
|
-
const objectMap = /* @__PURE__ */ new Map();
|
|
966
|
-
for (const { apiFolder, objects } of results) {
|
|
967
|
-
for (const obj of objects) {
|
|
968
|
-
let node = objectMap.get(obj.name);
|
|
969
|
-
if (!node) {
|
|
970
|
-
node = {
|
|
971
|
-
name: obj.name,
|
|
972
|
-
objectType: obj.objectType,
|
|
973
|
-
extension: obj.extension,
|
|
974
|
-
apiState: {
|
|
975
|
-
useInCloudDevelopment: false,
|
|
976
|
-
useInCloudDvlpmntActive: false,
|
|
977
|
-
useInKeyUserApps: false
|
|
978
|
-
}
|
|
979
|
-
};
|
|
980
|
-
objectMap.set(obj.name, node);
|
|
981
|
-
}
|
|
982
|
-
if (apiFolder === "USE_IN_CLOUD_DEVELOPMENT") {
|
|
983
|
-
node.apiState.useInCloudDevelopment = true;
|
|
984
|
-
} else if (apiFolder === "USE_IN_CLOUD_DVLPMNT_ACTIVE") {
|
|
985
|
-
node.apiState.useInCloudDvlpmntActive = true;
|
|
986
|
-
} else if (apiFolder === "USE_IN_KEY_USER_APPS") {
|
|
987
|
-
node.apiState.useInKeyUserApps = true;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
return ok(Array.from(objectMap.values()));
|
|
992
|
-
}
|
|
993
972
|
|
|
994
973
|
// src/core/adt/discovery/tree/index.ts
|
|
995
974
|
async function getTree(client, query = {}) {
|
|
@@ -1019,22 +998,6 @@ async function getTree(client, query = {}) {
|
|
|
1019
998
|
const internalQuery = buildQueryFromPath(query.package, query.path);
|
|
1020
999
|
const [parsed, parseErr] = await fetchVirtualFolders(client, internalQuery);
|
|
1021
1000
|
if (parseErr) return err(parseErr);
|
|
1022
|
-
const pathSegments = query.path?.split("/").filter((s) => s.length > 0) ?? [];
|
|
1023
|
-
const hasApiFolders = parsed.folders.length > 0 && parsed.folders.every((f) => f.facet === "API");
|
|
1024
|
-
if (pathSegments.length >= 2 && hasApiFolders) {
|
|
1025
|
-
const [objects, objErr] = await fetchObjectsWithApiState(
|
|
1026
|
-
client,
|
|
1027
|
-
query.package,
|
|
1028
|
-
pathSegments,
|
|
1029
|
-
API_FOLDERS
|
|
1030
|
-
);
|
|
1031
|
-
if (objErr) return err(objErr);
|
|
1032
|
-
return ok({
|
|
1033
|
-
packages,
|
|
1034
|
-
folders: [],
|
|
1035
|
-
objects
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
1001
|
const result = transformToTreeResponse(parsed, query.package);
|
|
1039
1002
|
result.packages = packages;
|
|
1040
1003
|
return ok(result);
|
|
@@ -2321,6 +2284,7 @@ async function httpsRequest2(url, options) {
|
|
|
2321
2284
|
req.end();
|
|
2322
2285
|
});
|
|
2323
2286
|
}
|
|
2287
|
+
var DEFAULT_REFRESH_INTERVAL = 30 * 60 * 1e3;
|
|
2324
2288
|
function buildParams(baseParams, clientNum) {
|
|
2325
2289
|
const params = new URLSearchParams();
|
|
2326
2290
|
if (baseParams) {
|
|
@@ -2345,6 +2309,8 @@ var ADTClientImpl = class {
|
|
|
2345
2309
|
requestor;
|
|
2346
2310
|
// Store SSO certificates for mTLS authentication
|
|
2347
2311
|
ssoCerts;
|
|
2312
|
+
// Auto-refresh timer handle
|
|
2313
|
+
refreshTimer = null;
|
|
2348
2314
|
constructor(config) {
|
|
2349
2315
|
const authOptions = {
|
|
2350
2316
|
config: config.auth,
|
|
@@ -2382,6 +2348,22 @@ var ADTClientImpl = class {
|
|
|
2382
2348
|
if (this.state.cookies.size === 0) return null;
|
|
2383
2349
|
return Array.from(this.state.cookies.entries()).map(([name, value]) => `${name}=${value}`).join("; ");
|
|
2384
2350
|
}
|
|
2351
|
+
startAutoRefresh(intervalMs) {
|
|
2352
|
+
this.stopAutoRefresh();
|
|
2353
|
+
this.refreshTimer = setInterval(async () => {
|
|
2354
|
+
if (!this.state.session) return;
|
|
2355
|
+
const [, refreshErr] = await this.refreshSession();
|
|
2356
|
+
if (refreshErr) {
|
|
2357
|
+
debug(`Auto-refresh failed: ${refreshErr.message}`);
|
|
2358
|
+
}
|
|
2359
|
+
}, intervalMs);
|
|
2360
|
+
}
|
|
2361
|
+
stopAutoRefresh() {
|
|
2362
|
+
if (this.refreshTimer) {
|
|
2363
|
+
clearInterval(this.refreshTimer);
|
|
2364
|
+
this.refreshTimer = null;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2385
2367
|
// Core HTTP request function with CSRF token injection and automatic retry on 403 errors
|
|
2386
2368
|
async request(options) {
|
|
2387
2369
|
const { method, path, params, headers: customHeaders, body } = options;
|
|
@@ -2473,9 +2455,9 @@ var ADTClientImpl = class {
|
|
|
2473
2455
|
async login() {
|
|
2474
2456
|
const { authStrategy } = this.state;
|
|
2475
2457
|
if (authStrategy.performLogin) {
|
|
2476
|
-
const [,
|
|
2477
|
-
if (
|
|
2478
|
-
return err(
|
|
2458
|
+
const [, loginErr2] = await authStrategy.performLogin(fetch);
|
|
2459
|
+
if (loginErr2) {
|
|
2460
|
+
return err(loginErr2);
|
|
2479
2461
|
}
|
|
2480
2462
|
}
|
|
2481
2463
|
if (authStrategy.type === "saml" && authStrategy.getCookies) {
|
|
@@ -2495,11 +2477,28 @@ var ADTClientImpl = class {
|
|
|
2495
2477
|
debug("Stored mTLS certificates for SSO authentication");
|
|
2496
2478
|
}
|
|
2497
2479
|
}
|
|
2498
|
-
|
|
2480
|
+
const [session, loginErr] = await login(this.state, this.request.bind(this));
|
|
2481
|
+
if (loginErr) {
|
|
2482
|
+
return err(loginErr);
|
|
2483
|
+
}
|
|
2484
|
+
const autoRefresh = this.state.config.autoRefresh ?? { enabled: true };
|
|
2485
|
+
if (autoRefresh.enabled) {
|
|
2486
|
+
const interval = autoRefresh.intervalMs ?? DEFAULT_REFRESH_INTERVAL;
|
|
2487
|
+
this.startAutoRefresh(interval);
|
|
2488
|
+
debug(`Auto-refresh started with ${interval}ms interval`);
|
|
2489
|
+
}
|
|
2490
|
+
return ok(session);
|
|
2499
2491
|
}
|
|
2500
2492
|
async logout() {
|
|
2493
|
+
this.stopAutoRefresh();
|
|
2501
2494
|
return logout(this.state, this.request.bind(this));
|
|
2502
2495
|
}
|
|
2496
|
+
async refreshSession() {
|
|
2497
|
+
if (!this.state.session) {
|
|
2498
|
+
return err(new Error("Not logged in"));
|
|
2499
|
+
}
|
|
2500
|
+
return refreshSession(this.state, this.request.bind(this));
|
|
2501
|
+
}
|
|
2503
2502
|
// --- CRAUD Operations ---
|
|
2504
2503
|
async read(objects) {
|
|
2505
2504
|
if (!this.state.session) return err(new Error("Not logged in"));
|