From 81852dcd22c5439b9aed1747184bbb3523b65843 Mon Sep 17 00:00:00 2001 From: "M. Emin Cihangeri" Date: Wed, 12 Nov 2025 16:10:27 +0100 Subject: [PATCH 1/6] feat: Add jks to supported formats --- packages/connectivity/package.json | 1 + .../connectivity/src/http-agent/http-agent.ts | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/connectivity/package.json b/packages/connectivity/package.json index 43ffd2bcbf..37dfb35b4a 100644 --- a/packages/connectivity/package.json +++ b/packages/connectivity/package.json @@ -42,6 +42,7 @@ "@sap/xssec": "^4.11.0", "async-retry": "^1.3.3", "axios": "^1.12.2", + "jks-js": "^1.1.4", "jsonwebtoken": "^9.0.2" }, "devDependencies": { diff --git a/packages/connectivity/src/http-agent/http-agent.ts b/packages/connectivity/src/http-agent/http-agent.ts index 7e2a7e93c6..08f5e554e1 100644 --- a/packages/connectivity/src/http-agent/http-agent.ts +++ b/packages/connectivity/src/http-agent/http-agent.ts @@ -1,6 +1,7 @@ import { readFile } from 'fs/promises'; import http from 'http'; import https from 'https'; +import * as jks from 'jks-js'; import { createLogger, last } from '@sap-cloud-sdk/util'; /* Careful the proxy imports cause circular dependencies if imported from scp directly */ // eslint-disable-next-line import/no-internal-modules @@ -132,6 +133,25 @@ function getKeyStoreOptions(destination: Destination): const certBuffer = Buffer.from(certificate.content, 'base64'); + if (getFormat(certificate) === 'jks') { + if (!destination.keyStorePassword) { + throw Error('Keystore password is required for JKS format'); + } + const pemKeystore = jks.toPem(certBuffer, destination.keyStorePassword); + const aliases = Object.keys(pemKeystore); + if (aliases.length === 0) { + throw Error('No entries found in JKS keystore'); + } + const alias = aliases[0]; // Use first alias + const entry = pemKeystore[alias]; + if (!entry.cert || !entry.key) { + throw Error('Invalid JKS entry: missing cert or key'); + } + return { + cert: Buffer.from(entry.cert, 'utf8'), + key: Buffer.from(entry.key, 'utf8') + }; + } // if the format is pem, the key and certificate needs to be passed separately // it could be required to separate the string into two parts, but this seems to work as well if (getFormat(certificate) === 'pem') { @@ -207,7 +227,7 @@ function mtlsIsEnabled(destination: Destination) { /* The node client supports only these store formats https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions. */ -const supportedCertificateFormats = ['p12', 'pfx', 'pem']; +const supportedCertificateFormats = ['p12', 'pfx', 'pem', 'jks']; function isSupportedFormat(format: string | undefined): boolean { return !!format && supportedCertificateFormats.includes(format); From 7426a5884401cd56c60aead966956f3d44141929 Mon Sep 17 00:00:00 2001 From: "M. Emin Cihangeri" Date: Fri, 21 Nov 2025 09:33:53 +0100 Subject: [PATCH 2/6] chore: Test jks format --- .../src/http-agent/http-agent.spec.ts | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/connectivity/src/http-agent/http-agent.spec.ts b/packages/connectivity/src/http-agent/http-agent.spec.ts index fb3c08b1e1..624e75082c 100644 --- a/packages/connectivity/src/http-agent/http-agent.spec.ts +++ b/packages/connectivity/src/http-agent/http-agent.spec.ts @@ -172,7 +172,7 @@ describe('createAgent', () => { ).toMatchObject(expectedOptions); }); - it('throws an error if the format is not supported', async () => { + it('does not throw an error for supported JKS format', async () => { const destination: HttpDestination = { url: 'https://destination.example.com', authentication: 'ClientCertificateAuthentication', @@ -187,8 +187,35 @@ describe('createAgent', () => { ] }; + // Mock the jks.toPem to avoid actual JKS parsing + const mockPem = { + alias: { + cert: 'mock-cert', + key: 'mock-key' + } + }; + jest.spyOn(require('jks-js'), 'toPem').mockReturnValue(mockPem); + + await expect(getAgentConfig(destination)).resolves.toBeDefined(); + }); + + it('throws an error if the format is not supported', async () => { + const destination: HttpDestination = { + url: 'https://destination.example.com', + authentication: 'ClientCertificateAuthentication', + keyStoreName: 'cert.unknown', + keyStorePassword: 'password', + certificates: [ + { + name: 'cert.unknown', + content: 'base64string', + type: 'CERTIFICATE' + } + ] + }; + expect(async () => getAgentConfig(destination)).rejects.toThrow( - "The format of the provided certificate 'cert.jks' is not supported. Supported formats are: p12, pfx, pem. You can convert Java Keystores (.jks, .keystore) into PKCS#12 keystores using the JVM's keytool CLI: keytool -importkeystore -srckeystore your-keystore.jks -destkeystore your-keystore.p12 -deststoretype pkcs12" + "The format of the provided certificate 'cert.unknown' is not supported. Supported formats are: p12, pfx, pem, jks." ); }); From 9eafa68de8286c1d28201276e196fb9d3f30a779 Mon Sep 17 00:00:00 2001 From: "M. Emin Cihangeri" Date: Fri, 21 Nov 2025 09:49:29 +0100 Subject: [PATCH 3/6] chore: Update changeset --- .changeset/legal-pandas-yell.md | 5 +++ .../src/http-agent/http-agent.spec.ts | 3 +- .../connectivity/src/http-agent/http-agent.ts | 3 ++ .../destination/destination-from-service.ts | 32 ++++++++++-------- .../destination/destination-from-vcap.ts | 4 +-- .../destination-service-cache.spec.ts | 5 +-- .../destination/http-proxy-util.spec.ts | 5 +-- packages/http-client/src/http-client.spec.ts | 2 +- packages/http-client/src/http-client.ts | 5 +-- packages/odata-common/src/entity-api.ts | 8 +++-- packages/odata-common/src/expandable.ts | 13 ++++---- packages/odata-common/src/filter/filter.ts | 4 +-- packages/odata-common/src/order/order.ts | 5 +-- .../odata-common/src/selectable/selectable.ts | 33 +++++++++---------- .../odata-v2/src/selectable/oderable.spec.ts | 5 +-- .../operation-request-builder.spec.ts | 7 ++-- packages/util/src/error-with-cause.ts | 11 ++++--- .../TestEntityLvl2SingleLinkApi.d.ts | 3 +- .../TestEntityLvl2SingleLinkApi.ts | 3 +- .../TestEntityOtherMultiLinkApi.d.ts | 3 +- .../TestEntityOtherMultiLinkApi.ts | 3 +- .../TestEntityLvl2SingleLinkApi.d.ts | 3 +- .../TestEntityLvl2SingleLinkApi.ts | 3 +- .../TestEntityOtherMultiLinkApi.d.ts | 3 +- .../TestEntityOtherMultiLinkApi.ts | 3 +- .../type-tests/test/v2/batch.test-d.ts | 2 +- .../type-tests/test/v4/batch.test-d.ts | 2 +- 27 files changed, 101 insertions(+), 77 deletions(-) create mode 100644 .changeset/legal-pandas-yell.md diff --git a/.changeset/legal-pandas-yell.md b/.changeset/legal-pandas-yell.md new file mode 100644 index 0000000000..f524ece664 --- /dev/null +++ b/.changeset/legal-pandas-yell.md @@ -0,0 +1,5 @@ +--- +'@sap-cloud-sdk/connectivity': minor +--- + +[New Functionality] Support certificates in JKS format for `ClientCertificateAuthentication`. diff --git a/packages/connectivity/src/http-agent/http-agent.spec.ts b/packages/connectivity/src/http-agent/http-agent.spec.ts index 624e75082c..4d8194fb82 100644 --- a/packages/connectivity/src/http-agent/http-agent.spec.ts +++ b/packages/connectivity/src/http-agent/http-agent.spec.ts @@ -1,5 +1,6 @@ import { X509Certificate } from 'node:crypto'; import mock from 'mock-fs'; +import * as jks from 'jks-js'; import { createLogger } from '@sap-cloud-sdk/util'; import { registerDestinationCache } from '../scp-cf/destination/register-destination-cache'; import { certAsString } from '../../../../test-resources/test/test-util/test-certificate'; @@ -194,7 +195,7 @@ describe('createAgent', () => { key: 'mock-key' } }; - jest.spyOn(require('jks-js'), 'toPem').mockReturnValue(mockPem); + jest.spyOn(jks, 'toPem').mockReturnValue(mockPem); await expect(getAgentConfig(destination)).resolves.toBeDefined(); }); diff --git a/packages/connectivity/src/http-agent/http-agent.ts b/packages/connectivity/src/http-agent/http-agent.ts index 08f5e554e1..2ffc8d322b 100644 --- a/packages/connectivity/src/http-agent/http-agent.ts +++ b/packages/connectivity/src/http-agent/http-agent.ts @@ -142,6 +142,9 @@ function getKeyStoreOptions(destination: Destination): if (aliases.length === 0) { throw Error('No entries found in JKS keystore'); } + if (aliases.length > 1) { + throw Error('Multiple entries found in JKS keystore; only a single entry is supported'); + } const alias = aliases[0]; // Use first alias const entry = pemKeystore[alias]; if (!entry.cert || !entry.key) { diff --git a/packages/connectivity/src/scp-cf/destination/destination-from-service.ts b/packages/connectivity/src/scp-cf/destination/destination-from-service.ts index 25281e9e7d..7bd1d1ea4b 100644 --- a/packages/connectivity/src/scp-cf/destination/destination-from-service.ts +++ b/packages/connectivity/src/scp-cf/destination/destination-from-service.ts @@ -127,8 +127,9 @@ export class DestinationFromServiceRetriever { (destination.authentication === 'OAuth2SAMLBearerAssertion' && !da.usesSystemUser(destination)) ) { - destination = - await da.fetchDestinationWithUserExchangeFlows(destinationResult); + destination = await da.fetchDestinationWithUserExchangeFlows( + destinationResult + ); } if (destination.authentication === 'PrincipalPropagation') { @@ -143,13 +144,15 @@ export class DestinationFromServiceRetriever { destination.authentication === 'OAuth2ClientCredentials' || da.usesSystemUser(destination) ) { - destination = - await da.fetchDestinationWithNonUserExchangeFlows(destinationResult); + destination = await da.fetchDestinationWithNonUserExchangeFlows( + destinationResult + ); } if (destination.authentication === 'OAuth2RefreshToken') { - destination = - await da.fetchDestinationWithRefreshTokenFlow(destinationResult); + destination = await da.fetchDestinationWithRefreshTokenFlow( + destinationResult + ); } } @@ -367,8 +370,9 @@ Possible alternatives for such technical user authentication are BasicAuthentica private async fetchDestinationWithNonUserExchangeFlows( destinationResult: DestinationSearchResult ): Promise { - const token = - await this.getAuthTokenForOAuth2ClientCredentials(destinationResult); + const token = await this.getAuthTokenForOAuth2ClientCredentials( + destinationResult + ); return fetchDestinationWithTokenRetrieval( getDestinationServiceCredentials().uri, @@ -380,10 +384,9 @@ Possible alternatives for such technical user authentication are BasicAuthentica private async fetchDestinationWithUserExchangeFlows( destinationResult: DestinationSearchResult ): Promise { - const token = - await this.getAuthTokenForOAuth2UserBasedTokenExchanges( - destinationResult - ); + const token = await this.getAuthTokenForOAuth2UserBasedTokenExchanges( + destinationResult + ); return fetchDestinationWithTokenRetrieval( getDestinationServiceCredentials().uri, @@ -395,8 +398,9 @@ Possible alternatives for such technical user authentication are BasicAuthentica private async fetchDestinationWithRefreshTokenFlow( destinationResult: DestinationSearchResult ): Promise { - const token = - await this.getAuthTokenForOAuth2RefreshToken(destinationResult); + const token = await this.getAuthTokenForOAuth2RefreshToken( + destinationResult + ); return fetchDestinationWithTokenRetrieval( getDestinationServiceCredentials().uri, diff --git a/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts b/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts index 6549608b59..bc9ee02c57 100644 --- a/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts +++ b/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts @@ -36,8 +36,8 @@ export async function getDestinationFromServiceBinding( const decodedJwt = options.iss ? { iss: options.iss } : options.jwt - ? decodeJwt(options.jwt) - : undefined; + ? decodeJwt(options.jwt) + : undefined; const retrievalOptions = { ...options, jwt: decodedJwt }; const destination = await retrieveDestination(retrievalOptions); diff --git a/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts b/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts index 5a55f2ee3b..48dd565e2f 100644 --- a/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts +++ b/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts @@ -68,8 +68,9 @@ describe('DestinationServiceCache', () => { ); expect(directCallSubscriber.length).toEqual(2); - const directCallProvider = - await populateCacheDestinations(providerServiceToken); + const directCallProvider = await populateCacheDestinations( + providerServiceToken + ); const cacheSubscriber = getDestinationsFromCache(subscriberServiceToken); expect(cacheSubscriber).toEqual(directCallSubscriber); diff --git a/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts b/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts index 125f0d51c8..cf27a1840e 100644 --- a/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts +++ b/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts @@ -65,8 +65,9 @@ describe('proxy-util', () => { } }); - process.env['no_proxy'] = - `http://some.otherURL.com,${httpsDestination.url}`; + process.env[ + 'no_proxy' + ] = `http://some.otherURL.com,${httpsDestination.url}`; expect(proxyStrategy(httpsDestination)).toBe('no-proxy'); }); diff --git a/packages/http-client/src/http-client.spec.ts b/packages/http-client/src/http-client.spec.ts index 2dbb4aa825..6da89092d7 100644 --- a/packages/http-client/src/http-client.spec.ts +++ b/packages/http-client/src/http-client.spec.ts @@ -294,7 +294,7 @@ describe('generic http client', () => { it('passes the context properties to the middleware', async () => { const showContextMiddleware: HttpMiddleware = (opt: HttpMiddlewareOptions) => () => - ({ data: opt.context }) as any; + ({ data: opt.context } as any); mockServiceBindings(); // Inside connectivity package we can use jest to mock jwtVerify and tokenAccessor diff --git a/packages/http-client/src/http-client.ts b/packages/http-client/src/http-client.ts index 46fb1abe6f..9c375302e4 100644 --- a/packages/http-client/src/http-client.ts +++ b/packages/http-client/src/http-client.ts @@ -87,8 +87,9 @@ export function execute(executeFn: ExecuteHttpRequestFn) { const resolvedDestination = await resolveDestination(destination); assertHttpDestination(resolvedDestination); - const destinationRequestConfig = - await buildHttpRequest(resolvedDestination); + const destinationRequestConfig = await buildHttpRequest( + resolvedDestination + ); logCustomHeadersWarning(requestConfig.headers); const request = await buildRequestWithMergedHeadersAndQueryParameters( diff --git a/packages/odata-common/src/entity-api.ts b/packages/odata-common/src/entity-api.ts index fd0cb1d219..84a9f42008 100644 --- a/packages/odata-common/src/entity-api.ts +++ b/packages/odata-common/src/entity-api.ts @@ -43,5 +43,9 @@ export interface EntityApi< /** * Helper type to extract the type of an entity from an API so EntityType> is `Dog`. */ -export type EntityType = - forExtraction extends EntityApi ? EntityT : never; +export type EntityType = forExtraction extends EntityApi< + infer EntityT, + any +> + ? EntityT + : never; diff --git a/packages/odata-common/src/expandable.ts b/packages/odata-common/src/expandable.ts index 847eb69fa5..8f0f305d19 100644 --- a/packages/odata-common/src/expandable.ts +++ b/packages/odata-common/src/expandable.ts @@ -14,10 +14,9 @@ export type Expandable< EntityBase, DeSerializersT > -> = - ODataVersionOf extends 'v2' - ? never - : - | OneToManyLink - | OneToOneLink - | AllFields; +> = ODataVersionOf extends 'v2' + ? never + : + | OneToManyLink + | OneToOneLink + | AllFields; diff --git a/packages/odata-common/src/filter/filter.ts b/packages/odata-common/src/filter/filter.ts index 17b99899f1..1ff8ab2f40 100644 --- a/packages/odata-common/src/filter/filter.ts +++ b/packages/odata-common/src/filter/filter.ts @@ -37,8 +37,8 @@ export type FilterOperator = export type FilterOperatorByType = FieldT extends string ? FilterOperatorString : FieldT extends number - ? FilterOperatorNumber - : FilterOperatorBoolean; + ? FilterOperatorNumber + : FilterOperatorBoolean; /** * Represents a filter expression to narrow the data on a {@link GetAllRequestBuilderBase | GetAllRequestBuilder} request for multiple entities that match the specified criteria. diff --git a/packages/odata-common/src/order/order.ts b/packages/odata-common/src/order/order.ts index 8cdaab4903..3eab903f8e 100644 --- a/packages/odata-common/src/order/order.ts +++ b/packages/odata-common/src/order/order.ts @@ -25,8 +25,5 @@ export class Order * @param _fieldName - Field to order by. * @param orderType - Type of ordering, can be 'asc' for ascending or 'desc' for descending. */ - constructor( - public _fieldName: string, - public orderType: OrderType = 'asc' - ) {} + constructor(public _fieldName: string, public orderType: OrderType = 'asc') {} } diff --git a/packages/odata-common/src/selectable/selectable.ts b/packages/odata-common/src/selectable/selectable.ts index e0c244477c..e01f93cedd 100644 --- a/packages/odata-common/src/selectable/selectable.ts +++ b/packages/odata-common/src/selectable/selectable.ts @@ -14,20 +14,19 @@ import type { SimpleTypeFields } from './simple-type-fields'; export type Selectable< EntityT extends EntityBase, DeSerializersT extends DeSerializers -> = - ODataVersionOf extends 'v2' - ? - | SimpleTypeFields - | Link> - | ComplexTypeField - | CustomField - | CollectionField - | AllFields - : ODataVersionOf extends 'v4' - ? - | SimpleTypeFields - | ComplexTypeField - | CustomField - | CollectionField - | AllFields - : never; +> = ODataVersionOf extends 'v2' + ? + | SimpleTypeFields + | Link> + | ComplexTypeField + | CustomField + | CollectionField + | AllFields + : ODataVersionOf extends 'v4' + ? + | SimpleTypeFields + | ComplexTypeField + | CustomField + | CollectionField + | AllFields + : never; diff --git a/packages/odata-v2/src/selectable/oderable.spec.ts b/packages/odata-v2/src/selectable/oderable.spec.ts index c1da7e161b..e2e7e27b79 100644 --- a/packages/odata-v2/src/selectable/oderable.spec.ts +++ b/packages/odata-v2/src/selectable/oderable.spec.ts @@ -8,8 +8,9 @@ describe('orderable', () => { const datetimeoffsetFieldName = 'DateTimeOffSetProperty'; it('should create filter for type DateTimeOffset by passing moment() ', () => { - const filter = - testEntityApi.schema.DATE_TIME_OFF_SET_PROPERTY.equals(moment()); + const filter = testEntityApi.schema.DATE_TIME_OFF_SET_PROPERTY.equals( + moment() + ); expect(moment.isMoment(filter.value)).toBe(true); }); diff --git a/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts b/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts index f544caf4b5..75f9940dce 100644 --- a/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts +++ b/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts @@ -94,10 +94,9 @@ describe('operation request builder', () => { ) .reply(200, httpResponse); - const result = - await testActionImportMultipleParameterComplexReturnType(tsBody).execute( - destination - ); + const result = await testActionImportMultipleParameterComplexReturnType( + tsBody + ).execute(destination); expect(result).toEqual(tsResponse); }); diff --git a/packages/util/src/error-with-cause.ts b/packages/util/src/error-with-cause.ts index 62d90d68e7..74b8d4b43a 100644 --- a/packages/util/src/error-with-cause.ts +++ b/packages/util/src/error-with-cause.ts @@ -16,10 +16,7 @@ export class ErrorWithCause extends Error { * @param message - Error message. * @param cause - Original error, causing this error. */ - constructor( - message: string, - public readonly cause: Error - ) { + constructor(message: string, public readonly cause: Error) { // There is an issue with the prototype chain when extending from Error: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget super(message); // 'Error' breaks prototype chain here Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain @@ -38,7 +35,11 @@ export class ErrorWithCause extends Error { let response = ''; if (cause.response?.data) { try { - response = `${unixEOL}${JSON.stringify(cause.response?.data, null, 2)}`; + response = `${unixEOL}${JSON.stringify( + cause.response?.data, + null, + 2 + )}`; } catch (error) { logger.warn(`Failed to stringify response data: ${error.message}`); response = `${unixEOL}${cause.response?.data}`; diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts index 9c845d0c59..a6730fac32 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts @@ -17,7 +17,8 @@ import { } from '@sap-cloud-sdk/odata-v2'; export declare class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts index 9cde49f1f5..53104b157e 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts @@ -19,7 +19,8 @@ import { } from '@sap-cloud-sdk/odata-v2'; export class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts index f51b203e37..3b87bd98a0 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts @@ -17,7 +17,8 @@ import { } from '@sap-cloud-sdk/odata-v2'; export declare class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts index fb99ec6b24..c436f55e5d 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts @@ -19,7 +19,8 @@ import { } from '@sap-cloud-sdk/odata-v2'; export class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts index 6d0af07b69..be9eb79ad4 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts @@ -17,7 +17,8 @@ import { } from '@sap-cloud-sdk/odata-v4'; export declare class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts index dbf4e53263..34243546b7 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts @@ -19,7 +19,8 @@ import { } from '@sap-cloud-sdk/odata-v4'; export class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts index 44c1eb4fdc..0d193f5ec7 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts @@ -17,7 +17,8 @@ import { } from '@sap-cloud-sdk/odata-v4'; export declare class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts index edae1b83aa..87f1cf234a 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts @@ -19,7 +19,8 @@ import { } from '@sap-cloud-sdk/odata-v4'; export class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements EntityApi, DeSerializersT> +> implements + EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/type-tests/test/v2/batch.test-d.ts b/test-packages/type-tests/test/v2/batch.test-d.ts index 9cb0ab1b8d..c1b94f1649 100644 --- a/test-packages/type-tests/test/v2/batch.test-d.ts +++ b/test-packages/type-tests/test/v2/batch.test-d.ts @@ -68,7 +68,7 @@ expectType>( ); expectType<() => ReadResponse>( - (): ReadResponse => ({}) as any + (): ReadResponse => ({} as any) ); async () => { diff --git a/test-packages/type-tests/test/v4/batch.test-d.ts b/test-packages/type-tests/test/v4/batch.test-d.ts index 924cefe244..1a4b7a74a1 100644 --- a/test-packages/type-tests/test/v4/batch.test-d.ts +++ b/test-packages/type-tests/test/v4/batch.test-d.ts @@ -18,7 +18,7 @@ import type { const { testEntityApi } = testService(); expectType<() => ReadResponse>( - (): ReadResponse => ({}) as any + (): ReadResponse => ({} as any) ); async () => { From 091ebc5c39de848cf7af75a822645f894207fd22 Mon Sep 17 00:00:00 2001 From: cloud-sdk-js Date: Fri, 21 Nov 2025 08:55:03 +0000 Subject: [PATCH 4/6] Changes from lint:fix --- .../connectivity/src/http-agent/http-agent.ts | 4 ++- .../destination/destination-from-service.ts | 32 ++++++++---------- .../destination/destination-from-vcap.ts | 4 +-- .../destination-service-cache.spec.ts | 5 ++- .../destination/http-proxy-util.spec.ts | 5 ++- packages/http-client/src/http-client.spec.ts | 2 +- packages/http-client/src/http-client.ts | 5 ++- packages/odata-common/src/entity-api.ts | 8 ++--- packages/odata-common/src/expandable.ts | 13 ++++---- packages/odata-common/src/filter/filter.ts | 4 +-- packages/odata-common/src/order/order.ts | 5 ++- .../odata-common/src/selectable/selectable.ts | 33 ++++++++++--------- .../odata-v2/src/selectable/oderable.spec.ts | 5 ++- .../operation-request-builder.spec.ts | 7 ++-- packages/util/src/error-with-cause.ts | 5 ++- .../TestEntityLvl2SingleLinkApi.d.ts | 3 +- .../TestEntityLvl2SingleLinkApi.ts | 3 +- .../TestEntityOtherMultiLinkApi.d.ts | 3 +- .../TestEntityOtherMultiLinkApi.ts | 3 +- .../TestEntityLvl2SingleLinkApi.d.ts | 3 +- .../TestEntityLvl2SingleLinkApi.ts | 3 +- .../TestEntityOtherMultiLinkApi.d.ts | 3 +- .../TestEntityOtherMultiLinkApi.ts | 3 +- .../type-tests/test/v2/batch.test-d.ts | 2 +- .../type-tests/test/v4/batch.test-d.ts | 2 +- 25 files changed, 78 insertions(+), 87 deletions(-) diff --git a/packages/connectivity/src/http-agent/http-agent.ts b/packages/connectivity/src/http-agent/http-agent.ts index 2ffc8d322b..8f3a74866a 100644 --- a/packages/connectivity/src/http-agent/http-agent.ts +++ b/packages/connectivity/src/http-agent/http-agent.ts @@ -143,7 +143,9 @@ function getKeyStoreOptions(destination: Destination): throw Error('No entries found in JKS keystore'); } if (aliases.length > 1) { - throw Error('Multiple entries found in JKS keystore; only a single entry is supported'); + throw Error( + 'Multiple entries found in JKS keystore; only a single entry is supported' + ); } const alias = aliases[0]; // Use first alias const entry = pemKeystore[alias]; diff --git a/packages/connectivity/src/scp-cf/destination/destination-from-service.ts b/packages/connectivity/src/scp-cf/destination/destination-from-service.ts index 7bd1d1ea4b..25281e9e7d 100644 --- a/packages/connectivity/src/scp-cf/destination/destination-from-service.ts +++ b/packages/connectivity/src/scp-cf/destination/destination-from-service.ts @@ -127,9 +127,8 @@ export class DestinationFromServiceRetriever { (destination.authentication === 'OAuth2SAMLBearerAssertion' && !da.usesSystemUser(destination)) ) { - destination = await da.fetchDestinationWithUserExchangeFlows( - destinationResult - ); + destination = + await da.fetchDestinationWithUserExchangeFlows(destinationResult); } if (destination.authentication === 'PrincipalPropagation') { @@ -144,15 +143,13 @@ export class DestinationFromServiceRetriever { destination.authentication === 'OAuth2ClientCredentials' || da.usesSystemUser(destination) ) { - destination = await da.fetchDestinationWithNonUserExchangeFlows( - destinationResult - ); + destination = + await da.fetchDestinationWithNonUserExchangeFlows(destinationResult); } if (destination.authentication === 'OAuth2RefreshToken') { - destination = await da.fetchDestinationWithRefreshTokenFlow( - destinationResult - ); + destination = + await da.fetchDestinationWithRefreshTokenFlow(destinationResult); } } @@ -370,9 +367,8 @@ Possible alternatives for such technical user authentication are BasicAuthentica private async fetchDestinationWithNonUserExchangeFlows( destinationResult: DestinationSearchResult ): Promise { - const token = await this.getAuthTokenForOAuth2ClientCredentials( - destinationResult - ); + const token = + await this.getAuthTokenForOAuth2ClientCredentials(destinationResult); return fetchDestinationWithTokenRetrieval( getDestinationServiceCredentials().uri, @@ -384,9 +380,10 @@ Possible alternatives for such technical user authentication are BasicAuthentica private async fetchDestinationWithUserExchangeFlows( destinationResult: DestinationSearchResult ): Promise { - const token = await this.getAuthTokenForOAuth2UserBasedTokenExchanges( - destinationResult - ); + const token = + await this.getAuthTokenForOAuth2UserBasedTokenExchanges( + destinationResult + ); return fetchDestinationWithTokenRetrieval( getDestinationServiceCredentials().uri, @@ -398,9 +395,8 @@ Possible alternatives for such technical user authentication are BasicAuthentica private async fetchDestinationWithRefreshTokenFlow( destinationResult: DestinationSearchResult ): Promise { - const token = await this.getAuthTokenForOAuth2RefreshToken( - destinationResult - ); + const token = + await this.getAuthTokenForOAuth2RefreshToken(destinationResult); return fetchDestinationWithTokenRetrieval( getDestinationServiceCredentials().uri, diff --git a/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts b/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts index bc9ee02c57..6549608b59 100644 --- a/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts +++ b/packages/connectivity/src/scp-cf/destination/destination-from-vcap.ts @@ -36,8 +36,8 @@ export async function getDestinationFromServiceBinding( const decodedJwt = options.iss ? { iss: options.iss } : options.jwt - ? decodeJwt(options.jwt) - : undefined; + ? decodeJwt(options.jwt) + : undefined; const retrievalOptions = { ...options, jwt: decodedJwt }; const destination = await retrieveDestination(retrievalOptions); diff --git a/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts b/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts index 48dd565e2f..5a55f2ee3b 100644 --- a/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts +++ b/packages/connectivity/src/scp-cf/destination/destination-service-cache.spec.ts @@ -68,9 +68,8 @@ describe('DestinationServiceCache', () => { ); expect(directCallSubscriber.length).toEqual(2); - const directCallProvider = await populateCacheDestinations( - providerServiceToken - ); + const directCallProvider = + await populateCacheDestinations(providerServiceToken); const cacheSubscriber = getDestinationsFromCache(subscriberServiceToken); expect(cacheSubscriber).toEqual(directCallSubscriber); diff --git a/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts b/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts index cf27a1840e..125f0d51c8 100644 --- a/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts +++ b/packages/connectivity/src/scp-cf/destination/http-proxy-util.spec.ts @@ -65,9 +65,8 @@ describe('proxy-util', () => { } }); - process.env[ - 'no_proxy' - ] = `http://some.otherURL.com,${httpsDestination.url}`; + process.env['no_proxy'] = + `http://some.otherURL.com,${httpsDestination.url}`; expect(proxyStrategy(httpsDestination)).toBe('no-proxy'); }); diff --git a/packages/http-client/src/http-client.spec.ts b/packages/http-client/src/http-client.spec.ts index 6da89092d7..2dbb4aa825 100644 --- a/packages/http-client/src/http-client.spec.ts +++ b/packages/http-client/src/http-client.spec.ts @@ -294,7 +294,7 @@ describe('generic http client', () => { it('passes the context properties to the middleware', async () => { const showContextMiddleware: HttpMiddleware = (opt: HttpMiddlewareOptions) => () => - ({ data: opt.context } as any); + ({ data: opt.context }) as any; mockServiceBindings(); // Inside connectivity package we can use jest to mock jwtVerify and tokenAccessor diff --git a/packages/http-client/src/http-client.ts b/packages/http-client/src/http-client.ts index 9c375302e4..46fb1abe6f 100644 --- a/packages/http-client/src/http-client.ts +++ b/packages/http-client/src/http-client.ts @@ -87,9 +87,8 @@ export function execute(executeFn: ExecuteHttpRequestFn) { const resolvedDestination = await resolveDestination(destination); assertHttpDestination(resolvedDestination); - const destinationRequestConfig = await buildHttpRequest( - resolvedDestination - ); + const destinationRequestConfig = + await buildHttpRequest(resolvedDestination); logCustomHeadersWarning(requestConfig.headers); const request = await buildRequestWithMergedHeadersAndQueryParameters( diff --git a/packages/odata-common/src/entity-api.ts b/packages/odata-common/src/entity-api.ts index 84a9f42008..fd0cb1d219 100644 --- a/packages/odata-common/src/entity-api.ts +++ b/packages/odata-common/src/entity-api.ts @@ -43,9 +43,5 @@ export interface EntityApi< /** * Helper type to extract the type of an entity from an API so EntityType> is `Dog`. */ -export type EntityType = forExtraction extends EntityApi< - infer EntityT, - any -> - ? EntityT - : never; +export type EntityType = + forExtraction extends EntityApi ? EntityT : never; diff --git a/packages/odata-common/src/expandable.ts b/packages/odata-common/src/expandable.ts index 8f0f305d19..847eb69fa5 100644 --- a/packages/odata-common/src/expandable.ts +++ b/packages/odata-common/src/expandable.ts @@ -14,9 +14,10 @@ export type Expandable< EntityBase, DeSerializersT > -> = ODataVersionOf extends 'v2' - ? never - : - | OneToManyLink - | OneToOneLink - | AllFields; +> = + ODataVersionOf extends 'v2' + ? never + : + | OneToManyLink + | OneToOneLink + | AllFields; diff --git a/packages/odata-common/src/filter/filter.ts b/packages/odata-common/src/filter/filter.ts index 1ff8ab2f40..17b99899f1 100644 --- a/packages/odata-common/src/filter/filter.ts +++ b/packages/odata-common/src/filter/filter.ts @@ -37,8 +37,8 @@ export type FilterOperator = export type FilterOperatorByType = FieldT extends string ? FilterOperatorString : FieldT extends number - ? FilterOperatorNumber - : FilterOperatorBoolean; + ? FilterOperatorNumber + : FilterOperatorBoolean; /** * Represents a filter expression to narrow the data on a {@link GetAllRequestBuilderBase | GetAllRequestBuilder} request for multiple entities that match the specified criteria. diff --git a/packages/odata-common/src/order/order.ts b/packages/odata-common/src/order/order.ts index 3eab903f8e..8cdaab4903 100644 --- a/packages/odata-common/src/order/order.ts +++ b/packages/odata-common/src/order/order.ts @@ -25,5 +25,8 @@ export class Order * @param _fieldName - Field to order by. * @param orderType - Type of ordering, can be 'asc' for ascending or 'desc' for descending. */ - constructor(public _fieldName: string, public orderType: OrderType = 'asc') {} + constructor( + public _fieldName: string, + public orderType: OrderType = 'asc' + ) {} } diff --git a/packages/odata-common/src/selectable/selectable.ts b/packages/odata-common/src/selectable/selectable.ts index e01f93cedd..e0c244477c 100644 --- a/packages/odata-common/src/selectable/selectable.ts +++ b/packages/odata-common/src/selectable/selectable.ts @@ -14,19 +14,20 @@ import type { SimpleTypeFields } from './simple-type-fields'; export type Selectable< EntityT extends EntityBase, DeSerializersT extends DeSerializers -> = ODataVersionOf extends 'v2' - ? - | SimpleTypeFields - | Link> - | ComplexTypeField - | CustomField - | CollectionField - | AllFields - : ODataVersionOf extends 'v4' - ? - | SimpleTypeFields - | ComplexTypeField - | CustomField - | CollectionField - | AllFields - : never; +> = + ODataVersionOf extends 'v2' + ? + | SimpleTypeFields + | Link> + | ComplexTypeField + | CustomField + | CollectionField + | AllFields + : ODataVersionOf extends 'v4' + ? + | SimpleTypeFields + | ComplexTypeField + | CustomField + | CollectionField + | AllFields + : never; diff --git a/packages/odata-v2/src/selectable/oderable.spec.ts b/packages/odata-v2/src/selectable/oderable.spec.ts index e2e7e27b79..c1da7e161b 100644 --- a/packages/odata-v2/src/selectable/oderable.spec.ts +++ b/packages/odata-v2/src/selectable/oderable.spec.ts @@ -8,9 +8,8 @@ describe('orderable', () => { const datetimeoffsetFieldName = 'DateTimeOffSetProperty'; it('should create filter for type DateTimeOffset by passing moment() ', () => { - const filter = testEntityApi.schema.DATE_TIME_OFF_SET_PROPERTY.equals( - moment() - ); + const filter = + testEntityApi.schema.DATE_TIME_OFF_SET_PROPERTY.equals(moment()); expect(moment.isMoment(filter.value)).toBe(true); }); diff --git a/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts b/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts index 75f9940dce..f544caf4b5 100644 --- a/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts +++ b/packages/odata-v4/src/request-builder/operation-request-builder.spec.ts @@ -94,9 +94,10 @@ describe('operation request builder', () => { ) .reply(200, httpResponse); - const result = await testActionImportMultipleParameterComplexReturnType( - tsBody - ).execute(destination); + const result = + await testActionImportMultipleParameterComplexReturnType(tsBody).execute( + destination + ); expect(result).toEqual(tsResponse); }); diff --git a/packages/util/src/error-with-cause.ts b/packages/util/src/error-with-cause.ts index 74b8d4b43a..7c5e13c959 100644 --- a/packages/util/src/error-with-cause.ts +++ b/packages/util/src/error-with-cause.ts @@ -16,7 +16,10 @@ export class ErrorWithCause extends Error { * @param message - Error message. * @param cause - Original error, causing this error. */ - constructor(message: string, public readonly cause: Error) { + constructor( + message: string, + public readonly cause: Error + ) { // There is an issue with the prototype chain when extending from Error: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget super(message); // 'Error' breaks prototype chain here Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts index a6730fac32..9c845d0c59 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.d.ts @@ -17,8 +17,7 @@ import { } from '@sap-cloud-sdk/odata-v2'; export declare class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts index 53104b157e..9cde49f1f5 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityLvl2SingleLinkApi.ts @@ -19,8 +19,7 @@ import { } from '@sap-cloud-sdk/odata-v2'; export class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts index 3b87bd98a0..f51b203e37 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.d.ts @@ -17,8 +17,7 @@ import { } from '@sap-cloud-sdk/odata-v2'; export declare class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts index c436f55e5d..fb99ec6b24 100644 --- a/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts +++ b/test-packages/test-services-odata-v2/test-service/TestEntityOtherMultiLinkApi.ts @@ -19,8 +19,7 @@ import { } from '@sap-cloud-sdk/odata-v2'; export class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts index be9eb79ad4..6d0af07b69 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.d.ts @@ -17,8 +17,7 @@ import { } from '@sap-cloud-sdk/odata-v4'; export declare class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts index 34243546b7..dbf4e53263 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityLvl2SingleLinkApi.ts @@ -19,8 +19,7 @@ import { } from '@sap-cloud-sdk/odata-v4'; export class TestEntityLvl2SingleLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts index 0d193f5ec7..44c1eb4fdc 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.d.ts @@ -17,8 +17,7 @@ import { } from '@sap-cloud-sdk/odata-v4'; export declare class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { deSerializers: DeSerializersT; private constructor(); diff --git a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts index 87f1cf234a..edae1b83aa 100644 --- a/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts +++ b/test-packages/test-services-odata-v4/test-service/TestEntityOtherMultiLinkApi.ts @@ -19,8 +19,7 @@ import { } from '@sap-cloud-sdk/odata-v4'; export class TestEntityOtherMultiLinkApi< DeSerializersT extends DeSerializers = DefaultDeSerializers -> implements - EntityApi, DeSerializersT> +> implements EntityApi, DeSerializersT> { public deSerializers: DeSerializersT; diff --git a/test-packages/type-tests/test/v2/batch.test-d.ts b/test-packages/type-tests/test/v2/batch.test-d.ts index c1b94f1649..9cb0ab1b8d 100644 --- a/test-packages/type-tests/test/v2/batch.test-d.ts +++ b/test-packages/type-tests/test/v2/batch.test-d.ts @@ -68,7 +68,7 @@ expectType>( ); expectType<() => ReadResponse>( - (): ReadResponse => ({} as any) + (): ReadResponse => ({}) as any ); async () => { diff --git a/test-packages/type-tests/test/v4/batch.test-d.ts b/test-packages/type-tests/test/v4/batch.test-d.ts index 1a4b7a74a1..924cefe244 100644 --- a/test-packages/type-tests/test/v4/batch.test-d.ts +++ b/test-packages/type-tests/test/v4/batch.test-d.ts @@ -18,7 +18,7 @@ import type { const { testEntityApi } = testService(); expectType<() => ReadResponse>( - (): ReadResponse => ({} as any) + (): ReadResponse => ({}) as any ); async () => { From e90a58d9dec626249342be74456e6e84c6f0bd22 Mon Sep 17 00:00:00 2001 From: "M. Emin Cihangeri" Date: Fri, 21 Nov 2025 15:41:31 +0100 Subject: [PATCH 5/6] chore: Create mock data for test --- .../src/http-agent/http-agent.spec.ts | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/connectivity/src/http-agent/http-agent.spec.ts b/packages/connectivity/src/http-agent/http-agent.spec.ts index 4d8194fb82..be55982c6a 100644 --- a/packages/connectivity/src/http-agent/http-agent.spec.ts +++ b/packages/connectivity/src/http-agent/http-agent.spec.ts @@ -1,7 +1,12 @@ import { X509Certificate } from 'node:crypto'; import mock from 'mock-fs'; -import * as jks from 'jks-js'; import { createLogger } from '@sap-cloud-sdk/util'; + +// Mock jks-js module +jest.mock('jks-js', () => ({ + toPem: jest.fn() +})); +import * as jks from 'jks-js'; import { registerDestinationCache } from '../scp-cf/destination/register-destination-cache'; import { certAsString } from '../../../../test-resources/test/test-util/test-certificate'; import { getAgentConfig } from './http-agent'; @@ -174,6 +179,15 @@ describe('createAgent', () => { }); it('does not throw an error for supported JKS format', async () => { + // Mock jks.toPem to return valid PEM data + const mockPemKeystore = { + 'alias1': { + cert: '-----BEGIN CERTIFICATE-----\nMII...\n-----END CERTIFICATE-----', + key: '-----BEGIN PRIVATE KEY-----\nMII...\n-----END PRIVATE KEY-----' + } + }; + (jks.toPem as jest.MockedFunction).mockReturnValue(mockPemKeystore); + const destination: HttpDestination = { url: 'https://destination.example.com', authentication: 'ClientCertificateAuthentication', @@ -182,22 +196,21 @@ describe('createAgent', () => { certificates: [ { name: 'cert.jks', - content: 'base64string', + content: 'base64string', // Can remain dummy since we're mocking type: 'CERTIFICATE' } ] }; - // Mock the jks.toPem to avoid actual JKS parsing - const mockPem = { - alias: { - cert: 'mock-cert', - key: 'mock-key' - } + const expectedOptions = { + rejectUnauthorized: true, + cert: Buffer.from(mockPemKeystore['alias1'].cert, 'utf8'), + key: Buffer.from(mockPemKeystore['alias1'].key, 'utf8') }; - jest.spyOn(jks, 'toPem').mockReturnValue(mockPem); - await expect(getAgentConfig(destination)).resolves.toBeDefined(); + expect( + (await getAgentConfig(destination))['httpsAgent']['options'] + ).toMatchObject(expectedOptions); }); it('throws an error if the format is not supported', async () => { From d14c340bab438ca82d890043b8740ae626f3a113 Mon Sep 17 00:00:00 2001 From: cloud-sdk-js Date: Fri, 21 Nov 2025 14:44:28 +0000 Subject: [PATCH 6/6] Changes from lint:fix --- packages/connectivity/src/http-agent/http-agent.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/connectivity/src/http-agent/http-agent.spec.ts b/packages/connectivity/src/http-agent/http-agent.spec.ts index be55982c6a..546ded0e09 100644 --- a/packages/connectivity/src/http-agent/http-agent.spec.ts +++ b/packages/connectivity/src/http-agent/http-agent.spec.ts @@ -181,12 +181,14 @@ describe('createAgent', () => { it('does not throw an error for supported JKS format', async () => { // Mock jks.toPem to return valid PEM data const mockPemKeystore = { - 'alias1': { + alias1: { cert: '-----BEGIN CERTIFICATE-----\nMII...\n-----END CERTIFICATE-----', key: '-----BEGIN PRIVATE KEY-----\nMII...\n-----END PRIVATE KEY-----' } }; - (jks.toPem as jest.MockedFunction).mockReturnValue(mockPemKeystore); + (jks.toPem as jest.MockedFunction).mockReturnValue( + mockPemKeystore + ); const destination: HttpDestination = { url: 'https://destination.example.com',