From 686ac667fa0f12c4e0d61e54f7d9490929457d06 Mon Sep 17 00:00:00 2001 From: Salome DO Date: Thu, 4 Jan 2024 10:22:43 +0100 Subject: [PATCH] feat: improve ama-sdk plugins logging --- apps/showcase/src/app/app.module.ts | 9 ++-- packages/@ama-sdk/core/README.md | 24 +++++++++++ .../core/src/clients/api-angular-client.ts | 5 ++- .../core/src/clients/api-beacon-client.ts | 2 +- .../core/src/clients/api-fetch-client.ts | 7 ++-- .../core/src/fwk/core/base-api-constructor.ts | 3 ++ packages/@ama-sdk/core/src/fwk/index.ts | 1 + packages/@ama-sdk/core/src/fwk/logger.ts | 42 +++++++++++++++++++ .../bot-protection-fingerprint.request.ts | 24 +++++------ .../core/src/plugins/core/fetch-plugin.ts | 11 +++-- .../@ama-sdk/core/src/plugins/core/plugin.ts | 19 ++++++++- .../core/src/plugins/core/reply-plugin.ts | 13 +++--- .../core/src/plugins/core/request-plugin.ts | 14 +++++-- .../mock-intercept/mock-intercept.fetch.ts | 3 +- .../mock-intercept/mock-intercept.request.ts | 1 + .../pii-tokenizer/pii-tokenizer.request.ts | 17 ++++---- .../plugins/session-id/session-id.request.ts | 27 ++++++------ .../src/plugins/session-id/session-id.spec.ts | 12 ++++-- .../templates/base/package.json.template | 2 +- 19 files changed, 173 insertions(+), 63 deletions(-) create mode 100644 packages/@ama-sdk/core/src/fwk/logger.ts diff --git a/apps/showcase/src/app/app.module.ts b/apps/showcase/src/app/app.module.ts index 198152535a..e70234a627 100644 --- a/apps/showcase/src/app/app.module.ts +++ b/apps/showcase/src/app/app.module.ts @@ -21,6 +21,7 @@ import { translateLoaderProvider, TranslateMessageFormatLazyCompiler } from '@o3r/localization'; +import { ConsoleLogger, Logger, LOGGER_CLIENT_TOKEN, LoggerService } from '@o3r/logger'; import { RulesEngineRunnerModule } from '@o3r/rules-engine'; import { HIGHLIGHT_OPTIONS } from 'ngx-highlightjs'; import { ScrollBackTopPresComponent, SidenavPresComponent } from '../components/index'; @@ -43,12 +44,13 @@ const runtimeChecks: Partial = { registerLocaleData(localeEN, 'en-GB'); registerLocaleData(localeFR, 'fr-FR'); -function petApiFactory() { +function petApiFactory(logger: Logger) { const apiConfig: ApiClient = new ApiFetchClient( { basePath: 'https://petstore3.swagger.io/api/v3', requestPlugins: [], - fetchPlugins: [] + fetchPlugins: [], + logger } ); return new PetApi(apiConfig); @@ -122,7 +124,8 @@ export function registerCustomComponents(): Map { } } }, - {provide: PetApi, useFactory: petApiFactory} + {provide: LOGGER_CLIENT_TOKEN, useValue: new ConsoleLogger()}, + {provide: PetApi, useFactory: petApiFactory, deps: [LoggerService]} ], bootstrap: [AppComponent] }) diff --git a/packages/@ama-sdk/core/README.md b/packages/@ama-sdk/core/README.md index fd3c831676..0fc72f8aed 100644 --- a/packages/@ama-sdk/core/README.md +++ b/packages/@ama-sdk/core/README.md @@ -42,3 +42,27 @@ A list of API Clients are provided by this package: | ApiFetchClient | @ama-sdk/core | Default API Client based on the browser FetchApi | | ApiBeaconClient | @ama-sdk/core | API Client based on the browser BeaconApi, it is processing synchronous call | | ApiAngularClient | @ama-sdk/core/clients/api-angular-client | API Client using the HttpClient exposed by the `@angular/common` package | + +### Logs + +In order to ease the logging in the ama-sdk plugins, it is possible to connect to third-party logging services. +This can be achieved by adding a `Logger` [implementation](/packages/@ama-sdk/core/src/fwk/logger.ts) to the options of an API client. + +For example, in the Otter showcase application, we could add a `ConsoleLogger` (from `@o3r/core`) as a parameter to the ApiFetchClient: + +```typescript +const logger = new ConsoleLogger(); +function petApiFactory() { + const apiConfig: ApiClient = new ApiFetchClient( + { + basePath: 'https://petstore3.swagger.io/api/v3', + requestPlugins: [new SessionIdRequest()], + fetchPlugins: [], + logger + } + ); + return new PetApi(apiConfig); +} +``` + +> *Note*: Adding a third-party logging service is optional. If undefined, the fallback is the console logger. diff --git a/packages/@ama-sdk/core/src/clients/api-angular-client.ts b/packages/@ama-sdk/core/src/clients/api-angular-client.ts index 0978bce404..15047a4f42 100644 --- a/packages/@ama-sdk/core/src/clients/api-angular-client.ts +++ b/packages/@ama-sdk/core/src/clients/api-angular-client.ts @@ -63,7 +63,7 @@ export class ApiAngularClient implements ApiClient { let opts = options; if (this.options.requestPlugins) { for (const plugin of this.options.requestPlugins) { - opts = await plugin.load().transform(opts); + opts = await plugin.load({logger: this.options.logger}).transform(opts); } } @@ -142,7 +142,8 @@ export class ApiAngularClient implements ApiClient { exception, operationId, url, - origin + origin, + logger: this.options.logger })) : []; let parsedData = root; diff --git a/packages/@ama-sdk/core/src/clients/api-beacon-client.ts b/packages/@ama-sdk/core/src/clients/api-beacon-client.ts index f5cd099d3f..61223358bc 100644 --- a/packages/@ama-sdk/core/src/clients/api-beacon-client.ts +++ b/packages/@ama-sdk/core/src/clients/api-beacon-client.ts @@ -78,7 +78,7 @@ export class ApiBeaconClient implements ApiClient { let opts = options; if (this.options.requestPlugins) { for (const plugin of this.options.requestPlugins) { - const changedOpt = plugin.load().transform(opts); + const changedOpt = plugin.load({logger: this.options.logger}).transform(opts); if (isPromise(changedOpt)) { throw new Error(`Request plugin ${plugin.constructor.name} has async transform method. Only sync methods are supported with the Beacon client.`); } else { diff --git a/packages/@ama-sdk/core/src/clients/api-fetch-client.ts b/packages/@ama-sdk/core/src/clients/api-fetch-client.ts index 6a5009f8aa..0a3e5b5b8a 100644 --- a/packages/@ama-sdk/core/src/clients/api-fetch-client.ts +++ b/packages/@ama-sdk/core/src/clients/api-fetch-client.ts @@ -79,7 +79,7 @@ export class ApiFetchClient implements ApiClient { let opts = options; if (this.options.requestPlugins) { for (const plugin of this.options.requestPlugins) { - opts = await plugin.load().transform(opts); + opts = await plugin.load({logger: this.options.logger}).transform(opts); } } @@ -120,7 +120,7 @@ export class ApiFetchClient implements ApiClient { } const loadedPlugins: (PluginAsyncRunner & PluginAsyncStarter)[] = []; if (this.options.fetchPlugins) { - loadedPlugins.push(...this.options.fetchPlugins.map((plugin) => plugin.load({url, options, fetchPlugins: loadedPlugins, controller, apiClient: this}))); + loadedPlugins.push(...this.options.fetchPlugins.map((plugin) => plugin.load({url, options, fetchPlugins: loadedPlugins, controller, apiClient: this, logger: this.options.logger}))); } const canStart = await Promise.all(loadedPlugins.map((plugin) => !plugin.canStart || plugin.canStart())); @@ -164,7 +164,8 @@ export class ApiFetchClient implements ApiClient { exception, operationId, url, - origin + origin, + logger: this.options.logger })) : []; let parsedData = root; diff --git a/packages/@ama-sdk/core/src/fwk/core/base-api-constructor.ts b/packages/@ama-sdk/core/src/fwk/core/base-api-constructor.ts index a3377e33f2..08851e55b1 100644 --- a/packages/@ama-sdk/core/src/fwk/core/base-api-constructor.ts +++ b/packages/@ama-sdk/core/src/fwk/core/base-api-constructor.ts @@ -1,3 +1,4 @@ +import type { Logger } from '../logger'; import { ReplyPlugin, RequestPlugin } from '../../plugins'; /** Interface of the constructor configuration object */ @@ -15,6 +16,8 @@ export interface BaseApiClientOptions { enableTokenization?: boolean; /** Disable the fallback on the first success code reviver if the response returned by the API does not match the list of expected success codes */ disableFallback?: boolean; + /** Logger (optional, fallback to console logger if undefined) */ + logger?: Logger; } /** Interface of the constructor configuration object */ diff --git a/packages/@ama-sdk/core/src/fwk/index.ts b/packages/@ama-sdk/core/src/fwk/index.ts index 3fe905dfd5..28e88631d0 100644 --- a/packages/@ama-sdk/core/src/fwk/index.ts +++ b/packages/@ama-sdk/core/src/fwk/index.ts @@ -5,5 +5,6 @@ export * from './core/index'; export * from './date'; export * from './errors'; export * from './ignore-enum.type'; +export * from './logger'; export * from './mocks/index'; export * from './Reviver'; diff --git a/packages/@ama-sdk/core/src/fwk/logger.ts b/packages/@ama-sdk/core/src/fwk/logger.ts new file mode 100644 index 0000000000..ed234ecf60 --- /dev/null +++ b/packages/@ama-sdk/core/src/fwk/logger.ts @@ -0,0 +1,42 @@ +/** + * Logger Client interface. + * + * Duplicate from [@o3r/core]{@link https://github.com/AmadeusITGroup/otter/blob/main/packages/%40o3r/core/src/log/logger.ts} + * All modifications should be made in both interfaces + */ +export interface Logger { + /** + * Log an error. + * @param message Message to log + * @param optionalParams Optional parameters to log + */ + error(message?: any, ...optionalParams: any[]): void; + + /** + * Log a warning. + * @param message Message to log + * @param optionalParams Optional parameters to log + */ + warn(message?: any, ...optionalParams: any[]): void; + + /** + * Log a message. + * @param message Message to log + * @param optionalParams Optional parameters to log + */ + info?(message?: any, ...optionalParams: any[]): void; + + /** + * Log a message. + * @param message Message to log + * @param optionalParams Optional parameters to log + */ + log(message?: any, ...optionalParams: any[]): void; + + /** + * Log a debug message. + * @param message Message to log + * @param optionalParams Optional parameters to log + */ + debug?(message?: any, ...optionalParams: any[]): void; +} diff --git a/packages/@ama-sdk/core/src/plugins/bot-protection-fingerprint/bot-protection-fingerprint.request.ts b/packages/@ama-sdk/core/src/plugins/bot-protection-fingerprint/bot-protection-fingerprint.request.ts index 1cbec682e8..235bb1c36f 100644 --- a/packages/@ama-sdk/core/src/plugins/bot-protection-fingerprint/bot-protection-fingerprint.request.ts +++ b/packages/@ama-sdk/core/src/plugins/bot-protection-fingerprint/bot-protection-fingerprint.request.ts @@ -1,9 +1,10 @@ -import {PluginRunner, RequestOptions, RequestPlugin} from '../core'; +import {PluginRunner, RequestOptions, RequestPlugin, RequestPluginContext} from '../core'; +import type {Logger} from '../../fwk/logger'; /** * Function that returns the value of the fingerprint if available. */ -export type BotProtectionFingerprintRetriever = () => string | undefined | Promise; +export type BotProtectionFingerprintRetriever = (logger?: Logger) => string | undefined | Promise; /** * Represents the object exposed by Imperva for the integration of their Advanced Bot Protection script with Singe Page Apps. @@ -52,13 +53,12 @@ If the application runs on a domain that is not protected by Imperva, this plugi }); }; - return async () => { + return async (logger?: Logger) => { if (!protection) { try { protection = await getProtection(); } catch (e) { - // eslint-disable-next-line no-console - console.error(e); + (logger || console).error(e); return; } } @@ -66,8 +66,7 @@ If the application runs on a domain that is not protected by Imperva, this plugi try { return await protection.token(tokenTimeout); } catch (e) { - // eslint-disable-next-line no-console - console.error('[SDK][Plug-in][BotProtectionFingerprintRequest] Timeout: no Token was received in time.'); + (logger || console).error('[SDK][Plug-in][BotProtectionFingerprintRequest] Timeout: no Token was received in time.'); return; } }; @@ -232,15 +231,15 @@ export class BotProtectionFingerprintRequest implements RequestPlugin { * * If pollOnlyOnce is set to true, the poller won't be executed again after it has been fully executed once. */ - private async waitForFingerprint() { + private async waitForFingerprint(logger?: Logger) { const pollerOptions = this.options.pollerOptions; if (pollerOptions === undefined || this.options.pollOnlyOnce !== false && this.hasPolled) { - return this.options.fingerprintRetriever(); + return this.options.fingerprintRetriever(logger); } for (let i = pollerOptions.maximumTries - 1; i >= 0; i--) { - const fingerprint = await this.options.fingerprintRetriever(); + const fingerprint = await this.options.fingerprintRetriever(logger); if (fingerprint) { this.hasPolled = true; return fingerprint; @@ -252,10 +251,11 @@ export class BotProtectionFingerprintRequest implements RequestPlugin { this.hasPolled = true; } - public load(): PluginRunner { + /** @inheritdoc */ + public load(context?: RequestPluginContext): PluginRunner { return { transform: async (requestOptions: RequestOptions) => { - const fingerprint = await this.waitForFingerprint(); + const fingerprint = await this.waitForFingerprint(context?.logger); if (fingerprint) { requestOptions.headers.set(this.options.destinationHeaderName, fingerprint); } diff --git a/packages/@ama-sdk/core/src/plugins/core/fetch-plugin.ts b/packages/@ama-sdk/core/src/plugins/core/fetch-plugin.ts index 1774f73801..8e154a5f5b 100644 --- a/packages/@ama-sdk/core/src/plugins/core/fetch-plugin.ts +++ b/packages/@ama-sdk/core/src/plugins/core/fetch-plugin.ts @@ -1,6 +1,6 @@ import type { ApiClient } from '../../fwk/core/api-client'; -import { Plugin, PluginAsyncRunner } from './plugin'; -import { RequestOptions } from './request-plugin'; +import type { Plugin, PluginAsyncRunner, PluginContext } from './plugin'; +import type { RequestOptions } from './request-plugin'; export type FetchCall = Promise; @@ -8,7 +8,7 @@ export type FetchCall = Promise; * Interface of an SDK reply plugin. * The plugin will be run on the reply of a call */ -export interface FetchPluginContext { +export interface FetchPluginContext extends PluginContext { /** URL targeted */ url: string; @@ -39,6 +39,9 @@ export interface PluginAsyncStarter { * The plugin will be run around the Fetch call */ export interface FetchPlugin extends Plugin { - /** Load the plugin with the context */ + /** + * Load the plugin with the context + * @param context Context of fetch plugin + */ load(context: FetchPluginContext): PluginAsyncRunner & PluginAsyncStarter; } diff --git a/packages/@ama-sdk/core/src/plugins/core/plugin.ts b/packages/@ama-sdk/core/src/plugins/core/plugin.ts index 8894eb4bd8..2235dc8a3b 100644 --- a/packages/@ama-sdk/core/src/plugins/core/plugin.ts +++ b/packages/@ama-sdk/core/src/plugins/core/plugin.ts @@ -1,3 +1,5 @@ +import type { Logger } from '../../fwk/logger'; + /** * Interface of a runnable plugin */ @@ -22,12 +24,25 @@ export interface PluginSyncRunner { transform(data: V): T; } +/** + * Interface of a plugin context + */ +export interface PluginContext { + /** Plugin context properties */ + [key: string]: any; + /** Logger (optional, fallback to console logger if undefined) */ + logger?: Logger; +} + /** * Interface of an SDK plugin */ export interface Plugin { - /** Load the plugin with the context */ - load(context?: Record): PluginRunner; + /** + * Load the plugin with the context + * @param context Context of plugin + */ + load(context?: PluginContext): PluginRunner; } /** diff --git a/packages/@ama-sdk/core/src/plugins/core/reply-plugin.ts b/packages/@ama-sdk/core/src/plugins/core/reply-plugin.ts index bb00eb6c81..60eee3e43a 100644 --- a/packages/@ama-sdk/core/src/plugins/core/reply-plugin.ts +++ b/packages/@ama-sdk/core/src/plugins/core/reply-plugin.ts @@ -1,12 +1,12 @@ -import { ApiTypes } from '../../fwk/api'; -import { ReviverType } from '../../fwk/Reviver'; -import { Plugin, PluginRunner } from './plugin'; +import type { ApiTypes } from '../../fwk/api'; +import type { ReviverType } from '../../fwk/Reviver'; +import type { Plugin, PluginContext, PluginRunner } from './plugin'; /** * Interface of an SDK reply plugin. * The plugin will be run on the reply of a call */ -export interface ReplyPluginContext { +export interface ReplyPluginContext extends PluginContext { /** Reply reviver function */ reviver?: ReviverType; @@ -40,6 +40,9 @@ export interface ReplyPluginContext { * The plugin will be run on the reply of a call */ export interface ReplyPlugin extends Plugin { - /** Load the plugin with the context */ + /** + * Load the plugin with the context + * @param context Context of reply plugin + */ load(context: ReplyPluginContext): PluginRunner; } diff --git a/packages/@ama-sdk/core/src/plugins/core/request-plugin.ts b/packages/@ama-sdk/core/src/plugins/core/request-plugin.ts index 4b3feba36c..0657fc68c8 100644 --- a/packages/@ama-sdk/core/src/plugins/core/request-plugin.ts +++ b/packages/@ama-sdk/core/src/plugins/core/request-plugin.ts @@ -1,4 +1,4 @@ -import { Plugin, PluginRunner } from './plugin'; +import type { Plugin, PluginContext, PluginRunner } from './plugin'; export type RequestBody = string | FormData; @@ -52,11 +52,19 @@ export interface RequestOptions extends RequestInit { method: NonNullable; } +/** + * Interface of an SDK request plugin context. + */ +export interface RequestPluginContext extends PluginContext {} + /** * Interface of an SDK request plugin. * The plugin will be run on the request of a call */ export interface RequestPlugin extends Plugin { - /** Load the plugin with the context */ - load(): PluginRunner; + /** + * Load the plugin with the context + * @param context Context of request plugin + */ + load(context?: RequestPluginContext): PluginRunner; } diff --git a/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.fetch.ts b/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.fetch.ts index b4fbb4de2b..84e50c20fa 100644 --- a/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.fetch.ts +++ b/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.fetch.ts @@ -47,8 +47,7 @@ export class MockInterceptFetch implements FetchPlugin { return responsePromise.then(() => response); } catch { - // eslint-disable-next-line no-console - console.error(`Failed to retrieve the latest mock for Operation ID ${operationId}, fallback to default mock`); + (context.logger || console).error(`Failed to retrieve the latest mock for Operation ID ${operationId}, fallback to default mock`); return responsePromise; } } diff --git a/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.request.ts b/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.request.ts index 63c05e4f36..17f35f1fab 100644 --- a/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.request.ts +++ b/packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.request.ts @@ -20,6 +20,7 @@ export class MockInterceptRequest implements RequestPlugin { }; } + /** @inheritdoc */ public load(): PluginRunner { return { transform: async (data: RequestOptions) => { diff --git a/packages/@ama-sdk/core/src/plugins/pii-tokenizer/pii-tokenizer.request.ts b/packages/@ama-sdk/core/src/plugins/pii-tokenizer/pii-tokenizer.request.ts index dbe294b786..0827fd3a03 100644 --- a/packages/@ama-sdk/core/src/plugins/pii-tokenizer/pii-tokenizer.request.ts +++ b/packages/@ama-sdk/core/src/plugins/pii-tokenizer/pii-tokenizer.request.ts @@ -1,5 +1,6 @@ import { createJweEncoder, createJwtEncoder } from '../../utils/json-token'; -import { PluginRunner, RequestOptions, RequestPlugin } from '../core'; +import { PluginRunner, RequestOptions, RequestPlugin, RequestPluginContext } from '../core'; +import type { Logger } from '../../fwk/logger'; /** * Creates a JWT encoding function which transforms the provided token-value associations as a unsecured JWT format https://tools.ietf.org/html/rfc7519#section-6 @@ -196,21 +197,22 @@ export class PiiTokenizerRequest implements RequestPlugin { /** * Append the generated token based on the request options to the tokens header * @param requestOptions Request options to generate the token + * @param logger Logger (optional, fallback to console logger if undefined) */ - private async appendEncodedToken(requestOptions: RequestOptions) { + private async appendEncodedToken(requestOptions: RequestOptions, logger?: Logger) { try { return await this.tokenEncoder(requestOptions.tokenizedOptions!.values); } catch (e) { if (this.silent) { - // eslint-disable-next-line no-console - console.error('Couldn\'t encode the token'); + (logger || console).error('Couldn\'t encode the token'); } else { throw new Error('Couldn\'t encode the token'); } } } - public load(): PluginRunner { + /** @inheritdoc */ + public load(context?: RequestPluginContext): PluginRunner { return { transform: async (data: RequestOptions) => { if (data.metadata?.deepLinkOptions) { @@ -221,13 +223,12 @@ export class PiiTokenizerRequest implements RequestPlugin { } } else if (!data.tokenizedOptions) { - // eslint-disable-next-line no-console - console.error('No tokenized options found. Please make sure tokenization is enabled on your ApiClient'); + (context?.logger || console).error('No tokenized options found. Please make sure tokenization is enabled on your ApiClient'); } else if (Object.keys(data.tokenizedOptions.values).length > 0) { data.basePath = data.tokenizedOptions.url; data.queryParams = {...data.queryParams, ...data.tokenizedOptions.queryParams}; - const token = await this.appendEncodedToken(data); + const token = await this.appendEncodedToken(data, context?.logger); if (token) { data.headers.append(this.tokensHeader, token); } diff --git a/packages/@ama-sdk/core/src/plugins/session-id/session-id.request.ts b/packages/@ama-sdk/core/src/plugins/session-id/session-id.request.ts index 9bd618ca40..88027a8bbc 100644 --- a/packages/@ama-sdk/core/src/plugins/session-id/session-id.request.ts +++ b/packages/@ama-sdk/core/src/plugins/session-id/session-id.request.ts @@ -1,5 +1,6 @@ import { v4 } from 'uuid'; -import { PluginRunner, RequestOptions, RequestPlugin } from '../core'; +import { PluginRunner, RequestOptions, RequestPlugin, RequestPluginContext } from '../core'; +import type { Logger } from '../../fwk/logger'; /** * Plugin to add a header with an ID that can be used to track all the calls done by one or several APIs of the SDK. @@ -32,7 +33,7 @@ export class SessionIdRequest implements RequestPlugin { /** * The session ID used to track API calls */ - public sessionId: string; + public sessionId?: string; /** * Constructor. @@ -40,22 +41,22 @@ export class SessionIdRequest implements RequestPlugin { * @param activateRequestId Indicates if the request ID part should be added to the ID. */ constructor(sessionIdHeader = 'Ama-Client-Ref', activateRequestId = true) { + // Declaration done first since generateSessionId uses the logger this.sessionIdHeader = sessionIdHeader; this.requestIdActivated = activateRequestId; - this.sessionId = this.generateSessionId(); } - private logSessionId(sessionId: string, date: string) { - // eslint-disable-next-line no-console, no-restricted-syntax - console.info(`Your debug ID associated to the header "${this.sessionIdHeader}" is: ${sessionId}.`); - // eslint-disable-next-line no-console, no-restricted-syntax - console.info(`Generated at: ${date}`); + private logSessionId(sessionId: string, date: string, logger?: Logger) { + (logger?.info || logger?.log || console.info).bind(logger || console)(`Your debug ID associated to the header "${this.sessionIdHeader}" is: ${sessionId}.`); + (logger?.info || logger?.log || console.info).bind(logger || console)(`Generated at: ${date}`); } - public load(): PluginRunner { + /** @inheritdoc */ + public load(context?: RequestPluginContext): PluginRunner { + const sessionId = this.sessionId ||= this.generateSessionId(context?.logger); return { transform: (data: RequestOptions) => { - data.headers.append(this.sessionIdHeader, this.requestIdActivated ? `${this.sessionId}:${this.generateRequestId()}` : this.sessionId); + data.headers.append(this.sessionIdHeader, this.requestIdActivated ? `${sessionId}:${this.generateRequestId()}` : sessionId); return data; } }; @@ -64,7 +65,7 @@ export class SessionIdRequest implements RequestPlugin { /** * Generates a session ID and stores it in session / backup storage. */ - public generateSessionId() { + public generateSessionId(logger?: Logger) { // Check if we already have a session ID in the shared memory if (SessionIdRequest.sharedMemory[this.sessionIdHeader]) { return SessionIdRequest.sharedMemory[this.sessionIdHeader] as string; @@ -79,7 +80,7 @@ export class SessionIdRequest implements RequestPlugin { const parsedSessionIdObject = JSON.parse(sessionIdObjectFromStorage); // update the shared memory and log the ID to the user SessionIdRequest.sharedMemory[this.sessionIdHeader] = parsedSessionIdObject.id; - this.logSessionId(parsedSessionIdObject.id, parsedSessionIdObject.generatedTime); + this.logSessionId(parsedSessionIdObject.id, parsedSessionIdObject.generatedTime, logger); return parsedSessionIdObject.id; } catch { /* if the content of the session storage was corrupted somehow we'll just generate a new one */ } } @@ -89,7 +90,7 @@ export class SessionIdRequest implements RequestPlugin { const sessionId = v4(); const generatedTime = new Date().toJSON(); // log it - this.logSessionId(sessionId, generatedTime); + this.logSessionId(sessionId, generatedTime, logger); // and store it SessionIdRequest.sharedMemory[this.sessionIdHeader] = sessionId; if (typeof sessionStorage !== 'undefined') { diff --git a/packages/@ama-sdk/core/src/plugins/session-id/session-id.spec.ts b/packages/@ama-sdk/core/src/plugins/session-id/session-id.spec.ts index 15040f89cf..97ba542e86 100644 --- a/packages/@ama-sdk/core/src/plugins/session-id/session-id.spec.ts +++ b/packages/@ama-sdk/core/src/plugins/session-id/session-id.spec.ts @@ -13,8 +13,8 @@ describe('Session ID Request Plugin', () => { it('should have the default id to Ama-Client-Ref', async () => { const plugin = new SessionIdRequest(); - const sessionId = plugin.sessionId; const runner = plugin.load(); + const sessionId = plugin.sessionId; await runner.transform(options); @@ -23,8 +23,8 @@ describe('Session ID Request Plugin', () => { it('should add the session ID to the headers', async () => { const plugin = new SessionIdRequest(TEST_KEY); - const sessionId = plugin.sessionId; const runner = plugin.load(); + const sessionId = plugin.sessionId; await runner.transform(options); @@ -34,6 +34,8 @@ describe('Session ID Request Plugin', () => { it('second plugin with same header should use the ID that\'s already in memory', () => { const plugin = new SessionIdRequest(TEST_KEY); const plugin2 = new SessionIdRequest(TEST_KEY); + plugin.load(); + plugin2.load(); expect(plugin.sessionId).toBe(plugin2.sessionId); }); @@ -41,14 +43,16 @@ describe('Session ID Request Plugin', () => { it('second plugin with different header should generate a new session ID', () => { const plugin = new SessionIdRequest(TEST_KEY); const plugin2 = new SessionIdRequest(TEST_KEY2); + plugin.load(); + plugin2.load(); expect(plugin.sessionId).not.toBe(plugin2.sessionId); }); it('should generate a correctly formatted ID', async () => { const plugin = new SessionIdRequest(); - const sessionId: string = plugin.sessionId; const runner = plugin.load(); + const sessionId: string = plugin.sessionId; await runner.transform(options); @@ -58,8 +62,8 @@ describe('Session ID Request Plugin', () => { it('should be possible to deactivate the request ID part', async () => { const plugin = new SessionIdRequest(TEST_KEY, false); - const sessionId = plugin.sessionId; const runner = plugin.load(); + const sessionId = plugin.sessionId; await runner.transform(options); diff --git a/packages/@ama-sdk/schematics/schematics/typescript/shell/templates/base/package.json.template b/packages/@ama-sdk/schematics/schematics/typescript/shell/templates/base/package.json.template index 923fb0b1e1..2a7eb3ea6e 100644 --- a/packages/@ama-sdk/schematics/schematics/typescript/shell/templates/base/package.json.template +++ b/packages/@ama-sdk/schematics/schematics/typescript/shell/templates/base/package.json.template @@ -76,9 +76,9 @@ "@commitlint/config-conventional": "^17.0.0", "@ama-sdk/schematics": "~<%= sdkCoreVersion %>", "@ama-sdk/core": "~<%= sdkCoreVersion %>", - "@o3r/schematics": "^<%= sdkCoreVersion %>", "@o3r/eslint-config-otter": "^<%= sdkCoreVersion %>", "@o3r/eslint-plugin": "^<%= sdkCoreVersion %>", + "@o3r/schematics": "^<%= sdkCoreVersion %>", "@o3r/workspace": "^<%= sdkCoreVersion %>", "@openapitools/openapi-generator-cli": "<%= versions['@openapitools/openapi-generator-cli'] %>", "@swc/cli": "^0.1.57",