]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: code-quality cleanup — utils usage, logic consolidation, export hygiene...
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sun, 19 Jul 2026 16:17:58 +0000 (18:17 +0200)
committerGitHub <noreply@github.com>
Sun, 19 Jul 2026 16:17:58 +0000 (18:17 +0200)
* refactor(ui-server): use isEmpty for outstanding-hashid checks

* refactor(ui-server): extract releaseRequest for broadcast request release

* refactor(ocpp): lift requestHandler into base template method

* refactor(utils): add isOCPP20x helper and route version predicates

* refactor(charging-station): single-source the request-statistics gate

* refactor(utils): use isNotEmptyString/isNotEmptyArray predicates

* refactor: drop dead exports and redundant re-export

* refactor(auth): rename AuthorizationStatus enum to AuthResultStatus

* refactor(ocpp): drop now-redundant logRequestHandlerError module-name param

* docs(charging-station): document recordRequestStatistic public method

* refactor(ocpp): route VariableMetadata mutability/persistence checks through predicates

* refactor(ocpp): unexport in-file-only parseJsonSchemaFile

57 files changed:
src/charging-station/ChargingStation.ts
src/charging-station/ConfigurationKeyUtils.ts
src/charging-station/TemplateSchema.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/broadcast-channel/UIServiceWorkerBroadcastChannel.ts
src/charging-station/index.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/2.0/OCPP20VariableManager.ts
src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPServiceOperations.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/charging-station/ocpp/auth/adapters/OCPP16AuthAdapter.ts
src/charging-station/ocpp/auth/adapters/OCPP20AuthAdapter.ts
src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts
src/charging-station/ocpp/auth/index.ts
src/charging-station/ocpp/auth/interfaces/OCPPAuthService.ts
src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts
src/charging-station/ocpp/auth/strategies/CertificateAuthStrategy.ts
src/charging-station/ocpp/auth/strategies/LocalAuthStrategy.ts
src/charging-station/ocpp/auth/types/AuthTypes.ts
src/charging-station/ocpp/auth/utils/AuthHelpers.ts
src/charging-station/ui-server/UIMCPServer.ts
src/charging-station/ui-server/UIServerAccessPolicy.ts
src/charging-station/ui-server/ui-services/AbstractUIService.ts
src/utils/Configuration.ts
src/utils/ConfigurationSchema.ts
src/utils/Utils.ts
src/utils/index.ts
src/worker/WorkerTypes.ts
src/worker/index.ts
tests/charging-station/ChargingStation-RequestStatistic.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/1.6/OCPP16RequestService-CallChain.test.ts
tests/charging-station/ocpp/1.6/OCPP16ServiceUtils.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-RequestStartTransaction.test.ts
tests/charging-station/ocpp/2.0/OCPP20ResponseService-CacheUpdate.test.ts
tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-AuthCache.test.ts
tests/charging-station/ocpp/2.0/OCPP20VariableRegistry.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/OCPPServiceOperations.test.ts
tests/charging-station/ocpp/auth/OCPPAuthIntegration.test.ts
tests/charging-station/ocpp/auth/adapters/OCPP16AuthAdapter.test.ts
tests/charging-station/ocpp/auth/adapters/OCPP20AuthAdapter.test.ts
tests/charging-station/ocpp/auth/cache/InMemoryAuthCache.test.ts
tests/charging-station/ocpp/auth/helpers/MockFactories.ts
tests/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.test.ts
tests/charging-station/ocpp/auth/strategies/CertificateAuthStrategy.test.ts
tests/charging-station/ocpp/auth/strategies/LocalAuthStrategy-DisablePostAuthorize.test.ts
tests/charging-station/ocpp/auth/strategies/LocalAuthStrategy.test.ts
tests/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.test.ts
tests/charging-station/ocpp/auth/types/AuthTypes.test.ts
tests/charging-station/ocpp/auth/utils/AuthConfigValidator.test.ts
tests/charging-station/ocpp/auth/utils/AuthHelpers.test.ts
tests/utils/Utils.test.ts
ui/common/src/client/WebSocketClient.ts
ui/common/tests/WebSocketClient.test.ts

index 36343f823195f76d84cde2f03f361371f6accaa2..41fa2cf5981c60d5daa2c99e9f437e505fb9561f 100644 (file)
@@ -100,6 +100,7 @@ import {
   isEmpty,
   isNotEmptyArray,
   isNotEmptyString,
+  isOCPP20x,
   JSONStringify,
   logger,
   logPrefix,
@@ -1047,6 +1048,21 @@ export class ChargingStation extends EventEmitter {
     this.wsConnection.on('pong', this.onPong.bind(this))
   }
 
+  /**
+   * Records a request statistic for the given command, but only when statistics
+   * collection is enabled on the station (`stationInfo.enableStatistics`).
+   * @param command - OCPP command the statistic is recorded against.
+   * @param messageType - Message type of the recorded exchange.
+   */
+  public recordRequestStatistic (
+    command: IncomingRequestCommand | RequestCommand,
+    messageType: MessageType
+  ): void {
+    if (this.stationInfo?.enableStatistics === true) {
+      this.performanceStatistics?.addRequestStatistic(command, messageType)
+    }
+  }
+
   /**
    * Removes a reservation and restores the connector to its previous status.
    * @param reservation - The reservation to remove
@@ -1653,10 +1669,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   private getReconnectDelay (): number {
-    if (
-      this.stationInfo?.ocppVersion === OCPPVersion.VERSION_20 ||
-      this.stationInfo?.ocppVersion === OCPPVersion.VERSION_201
-    ) {
+    if (isOCPP20x(this.stationInfo?.ocppVersion)) {
       return OCPP20ServiceUtils.computeReconnectDelay(this, this.wsConnectionRetryCount)
     }
     return this.stationInfo?.reconnectExponentialDelay === true
@@ -1863,9 +1876,7 @@ export class ChargingStation extends EventEmitter {
         commandPayload
       )
     }
-    if (this.stationInfo?.enableStatistics === true) {
-      this.performanceStatistics?.addRequestStatistic(commandName, messageType)
-    }
+    this.recordRequestStatistic(commandName, messageType)
     logger.debug(
       `${this.logPrefix()} ${moduleName}.handleIncomingMessage: << Command '${commandName}' received request payload: ${JSON.stringify(
         request
index 1807c796b42b85524c51c34d3bb3c799db8c4322..000561c6abd5523d2f911948c9c423310269ba71 100644 (file)
@@ -4,11 +4,10 @@ import {
   type ConfigurationKey,
   type ConfigurationKeyType,
   OCPP20ComponentName,
-  OCPPVersion,
   StandardParametersKey,
   VendorParametersKey,
 } from '../types/index.js'
-import { logger } from '../utils/index.js'
+import { isOCPP20x, logger } from '../utils/index.js'
 
 export const buildConfigKey = (component: string, variable: string, instance?: string): string => {
   const base = `${component}.${variable}`
@@ -122,7 +121,7 @@ const resolveKey = (
   key: ConfigurationKeyType
 ): ConfigurationKeyType => {
   const version = chargingStation.stationInfo?.ocppVersion
-  if (version === OCPPVersion.VERSION_20 || version === OCPPVersion.VERSION_201) {
+  if (isOCPP20x(version)) {
     return OCPP2_PARAMETER_KEY_MAP.get(key) ?? key
   }
   return key
@@ -130,7 +129,7 @@ const resolveKey = (
 
 export const warnOnOCPP16TemplateKeys = (chargingStation: ChargingStation): void => {
   const version = chargingStation.stationInfo?.ocppVersion
-  if (version !== OCPPVersion.VERSION_20 && version !== OCPPVersion.VERSION_201) {
+  if (!isOCPP20x(version)) {
     return
   }
   const keys = chargingStation.ocppConfiguration?.configurationKey
index 1c1b9399c0134c3ff448ce885bea3ccfba9d2946..5f22dd66fc7b170e2d1620ea7d4ffe05f53bada0 100644 (file)
@@ -305,11 +305,6 @@ export const TemplateSchema = BaseTemplateSchema.superRefine((template, ctx) =>
   }
 })
 
-/**
- * StrictTemplateSchema — rejects unknown keys. For CI strict mode.
- */
-export const StrictTemplateSchema = BaseTemplateSchema.strict()
-
 // ---------------------------------------------------------------
 // Exported sub-schemas for reuse
 // ---------------------------------------------------------------
index 2e5035ed29b777187f826ea8765d439c7a9c3d0e..45f8977acb1e4121abfd4c6539e7d11d68e238bc 100644 (file)
@@ -46,6 +46,7 @@ import {
   getErrorMessage,
   isAsyncFunction,
   isEmpty,
+  isOCPP20x,
   logger,
 } from '../../utils/index.js'
 import { getConfigurationKey } from '../ConfigurationKeyUtils.js'
@@ -414,9 +415,7 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
       )
     }
     const transactionId = this.chargingStation.getConnectorStatus(connectorId)?.transactionId
-    const isOcpp2 =
-      this.chargingStation.stationInfo?.ocppVersion === OCPPVersion.VERSION_20 ||
-      this.chargingStation.stationInfo?.ocppVersion === OCPPVersion.VERSION_201
+    const isOcpp2 = isOCPP20x(this.chargingStation.stationInfo?.ocppVersion)
     const interval = isOcpp2
       ? OCPP20ServiceUtils.getAlignedDataInterval(this.chargingStation)
       : (() => {
index f0d26d1bfec76c6709d6b47fbd4977b50cdc971c..a5aa33eb96631bab954294157d56bf7f52547471 100644 (file)
@@ -40,12 +40,7 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
       // Already completed and released by the normal response path.
       return
     }
-    try {
-      this.uiService.sendResponse(uuid, this.buildTimeoutResponsePayload(uuid))
-    } finally {
-      this.responses.delete(uuid)
-      this.uiService.deleteBroadcastChannelRequest(uuid)
-    }
+    this.releaseRequest(uuid, this.buildTimeoutResponsePayload(uuid))
   }
 
   /**
@@ -115,13 +110,7 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
   }
 
   private completeRequest (uuid: UUIDv4): void {
-    // Always release aggregation state, even if downstream sendResponse throws.
-    try {
-      this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid))
-    } finally {
-      this.responses.delete(uuid)
-      this.uiService.deleteBroadcastChannelRequest(uuid)
-    }
+    this.releaseRequest(uuid, this.buildResponsePayload(uuid))
   }
 
   private messageErrorHandler (messageEvent: MessageEvent): void {
@@ -131,6 +120,22 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
     )
   }
 
+  /**
+   * Sends the given response payload for a broadcast request and always
+   * releases its aggregation state afterwards, even if the downstream
+   * sendResponse throws.
+   * @param uuid - Request identifier.
+   * @param responsePayload - Aggregated response payload to send.
+   */
+  private releaseRequest (uuid: UUIDv4, responsePayload: ResponsePayload): void {
+    try {
+      this.uiService.sendResponse(uuid, responsePayload)
+    } finally {
+      this.responses.delete(uuid)
+      this.uiService.deleteBroadcastChannelRequest(uuid)
+    }
+  }
+
   private responseHandler (messageEvent: MessageEvent): void {
     const validatedMessageEvent = this.validateMessageEvent(messageEvent)
     if (validatedMessageEvent === false) {
index 0c7fc720c6ff7c1b959288b345f01563fd206b65..d1e1bf5437152da93beedbccef05138380b2479b 100644 (file)
@@ -45,5 +45,5 @@ export { IdTagsCache } from './IdTagsCache.js'
 export type { CoherentSession } from './meter-values/index.js'
 export { SharedLRUCache } from './SharedLRUCache.js'
 export { applyMigration, coerceVersion, CURRENT_SCHEMA_VERSION } from './TemplateMigrations.js'
-export { StrictTemplateSchema, TemplateSchema } from './TemplateSchema.js'
+export { TemplateSchema } from './TemplateSchema.js'
 export { TemplateValidationError, validateTemplate } from './TemplateValidation.js'
index d03c7678ca626ab3b0e2772f27ababa0d74a1b14..9da1a59d3052ce2c2fa17e966eb63fa45a9d298f 100644 (file)
@@ -14,12 +14,11 @@ import {
   type OCPP16StartTransactionRequest,
   type OCPP16StatusNotificationRequest,
   OCPPVersion,
-  type RequestParams,
 } from '../../../types/index.js'
-import { assertIsJsonObject, generateUUID, logger } from '../../../utils/index.js'
+import { assertIsJsonObject, logger } from '../../../utils/index.js'
 import { sendAndSetConnectorStatus } from '../OCPPConnectorStatusOperations.js'
 import { OCPPRequestService } from '../OCPPRequestService.js'
-import { createPayloadValidatorMap, isRequestCommandSupported } from '../OCPPServiceUtils.js'
+import { createPayloadValidatorMap } from '../OCPPServiceUtils.js'
 import { OCPP16Constants } from './OCPP16Constants.js'
 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js'
 
@@ -55,88 +54,12 @@ export class OCPP16RequestService extends OCPPRequestService {
    * @param ocppResponseService - The response service instance for handling responses
    */
   public constructor (ocppResponseService: OCPPResponseService) {
-    super(OCPPVersion.VERSION_16, ocppResponseService)
+    super(OCPPVersion.VERSION_16, ocppResponseService, moduleName)
     this.payloadValidatorFunctions = createPayloadValidatorMap(
       OCPP16ServiceUtils.createRequestPayloadConfigs(),
       OCPP16ServiceUtils.createPayloadOptions(moduleName, 'constructor'),
       this.ajv
     )
-    this.buildRequestPayload = this.buildRequestPayload.bind(this)
-  }
-
-  /**
-   * Handles OCPP 1.6 request processing with full validation and error handling
-   *
-   * This method serves as the main entry point for all outgoing OCPP 1.6 requests.
-   * It performs the following operations:
-   * - Validates that the requested command is supported by the charging station
-   * - Builds and validates the request payload according to OCPP 1.6 schemas
-   * - Sends the request to the Central System with proper error handling
-   * - Processes responses with comprehensive logging and error recovery
-   *
-   * The method ensures type safety through generic type parameters while maintaining
-   * backward compatibility with the OCPP 1.6 specification.
-   * @template RequestType - The expected type of the request parameters
-   * @template ResponseType - The expected type of the response from the Central System
-   * @param chargingStation - The charging station instance making the request
-   * @param commandName - The OCPP 1.6 command to execute (e.g., 'StartTransaction', 'StopTransaction')
-   * @param commandParams - Optional parameters specific to the command being executed
-   * @param params - Optional request parameters for controlling request behavior
-   * @returns Promise resolving to the typed response from the Central System
-   * @throws {OCPPError} When the command is not supported or validation fails
-   */
-  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
-  public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
-    chargingStation: ChargingStation,
-    commandName: OCPP16RequestCommand,
-    commandParams?: RequestType,
-    params?: RequestParams
-  ): Promise<ResponseType> {
-    logger.debug(
-      `${chargingStation.logPrefix()} ${moduleName}.requestHandler: Processing '${commandName}' request`
-    )
-    if (isRequestCommandSupported(chargingStation, commandName)) {
-      try {
-        logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.requestHandler: Building request payload for '${commandName}'`
-        )
-        const requestPayload =
-          params?.rawPayload === true
-            ? (commandParams as RequestType)
-            : this.buildRequestPayload(chargingStation, commandName, commandParams)
-        const messageId = generateUUID()
-        logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
-        )
-        // Pre request actions hook
-        switch (commandName) {
-          case OCPP16RequestCommand.START_TRANSACTION:
-            await sendAndSetConnectorStatus(chargingStation, {
-              connectorId: (commandParams as OCPP16StartTransactionRequest).connectorId,
-              status: OCPP16ChargePointStatus.Preparing,
-            })
-            break
-        }
-        const response = (await this.sendMessage(
-          chargingStation,
-          messageId,
-          requestPayload,
-          commandName,
-          params
-        )) as ResponseType
-        logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.requestHandler: '${commandName}' request completed successfully`
-        )
-        return response
-      } catch (error) {
-        this.logRequestHandlerError(chargingStation, moduleName, commandName, error)
-        throw error
-      }
-    }
-    // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
-    const errorMsg = `Unsupported OCPP command ${commandName}`
-    logger.error(`${chargingStation.logPrefix()} ${moduleName}.requestHandler: ${errorMsg}`)
-    throw new OCPPError(ErrorType.NOT_SUPPORTED, errorMsg, commandName, commandParams)
   }
 
   /**
@@ -158,7 +81,7 @@ export class OCPP16RequestService extends OCPPRequestService {
    * @param commandParams - Optional parameters provided by the caller for payload construction
    * @returns The fully constructed and validated request payload ready for transmission
    */
-  private buildRequestPayload (
+  protected buildRequestPayload (
     chargingStation: ChargingStation,
     commandName: OCPP16RequestCommand,
     commandParams?: JsonType
@@ -283,4 +206,26 @@ export class OCPP16RequestService extends OCPPRequestService {
       }
     }
   }
+
+  /**
+   * Runs the OCPP 1.6 pre-request actions hook: for StartTransaction it sends
+   * and sets the connector status to Preparing before the request is sent.
+   * @param chargingStation - The charging station instance making the request
+   * @param commandName - The OCPP 1.6 command being sent
+   * @param commandParams - Optional parameters provided by the caller
+   */
+  protected override async preRequestHook (
+    chargingStation: ChargingStation,
+    commandName: OCPP16RequestCommand,
+    commandParams?: JsonType
+  ): Promise<void> {
+    switch (commandName) {
+      case OCPP16RequestCommand.START_TRANSACTION:
+        await sendAndSetConnectorStatus(chargingStation, {
+          connectorId: (commandParams as OCPP16StartTransactionRequest).connectorId,
+          status: OCPP16ChargePointStatus.Preparing,
+        })
+        break
+    }
+  }
 }
index 286e700717f13b8d9f4f37b7b10185497ee449c2..a363d40787ef8cec07ea8ea95c565d069d5228e7 100644 (file)
@@ -162,7 +162,7 @@ import {
 } from '../../index.js'
 import {
   AuthContext,
-  AuthorizationStatus,
+  AuthResultStatus,
   type DifferentialAuthEntry,
   type LocalAuthEntry,
   mapOCPP20TokenType,
@@ -1158,13 +1158,13 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService<OCP
       timestamp: new Date(),
     })
 
-    if (authResult.status !== AuthorizationStatus.ACCEPTED) {
+    if (authResult.status !== AuthResultStatus.ACCEPTED) {
       logger.warn(
         `${chargingStation.logPrefix()} ${moduleName}.authorizeToken: ${tokenLabel} '${truncateId(tokenValue)}' is not authorized`
       )
     }
 
-    return authResult.status === AuthorizationStatus.ACCEPTED
+    return authResult.status === AuthResultStatus.ACCEPTED
   }
 
   private buildReportData (
index 01ef06b62781a52b63498f527359cdd57c3bde4c..78e67100501f5fa898e075515a7236fdcd05d9e1 100644 (file)
@@ -16,12 +16,11 @@ import {
   type OCPP20SignCertificateRequest,
   type OCPP20TransactionEventOptions,
   OCPPVersion,
-  type RequestParams,
   type StatusNotificationOptions,
 } from '../../../types/index.js'
-import { generateUUID, getErrorMessage, logger } from '../../../utils/index.js'
+import { getErrorMessage, logger } from '../../../utils/index.js'
 import { OCPPRequestService } from '../OCPPRequestService.js'
-import { createPayloadValidatorMap, isRequestCommandSupported } from '../OCPPServiceUtils.js'
+import { createPayloadValidatorMap } from '../OCPPServiceUtils.js'
 import { generatePkcs10Csr } from './Asn1DerUtils.js'
 import { OCPP20Constants } from './OCPP20Constants.js'
 import { buildTransactionEvent, OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
@@ -66,84 +65,15 @@ export class OCPP20RequestService extends OCPPRequestService {
    * @param ocppResponseService - The response service instance for handling OCPP 2.0.1 responses
    */
   public constructor (ocppResponseService: OCPPResponseService) {
-    super(OCPPVersion.VERSION_201, ocppResponseService)
+    super(OCPPVersion.VERSION_201, ocppResponseService, moduleName)
     this.payloadValidatorFunctions = createPayloadValidatorMap(
       OCPP20ServiceUtils.createRequestPayloadConfigs(),
       OCPP20ServiceUtils.createPayloadOptions(moduleName, 'constructor'),
       this.ajv
     )
-    this.buildRequestPayload = this.buildRequestPayload.bind(this)
   }
 
-  /**
-   * Handles OCPP 2.0.1 request processing with enhanced validation and comprehensive error handling
-   *
-   * This method serves as the main entry point for all outgoing OCPP 2.0.1 requests to the CSMS.
-   * It performs advanced operations including:
-   * - Validates that the requested command is supported by the charging station configuration
-   * - Builds and validates request payloads according to strict OCPP 2.0.1 schemas
-   * - Handles OCPP 2.0.1-specific features like component/variable management and enhanced security
-   * - Sends requests with comprehensive error handling and detailed logging
-   * - Processes responses with full support for OCPP 2.0.1's enhanced status reporting
-   * - Manages advanced OCPP 2.0.1 concepts like EVSE management and transaction UUIDs
-   *
-   * The method ensures full compliance with OCPP 2.0.1 specification while providing
-   * enhanced type safety and detailed error reporting for debugging and monitoring.
-   * @template RequestType - The expected type of the request parameters
-   * @template ResponseType - The expected type of the response from the CSMS
-   * @param chargingStation - The charging station instance making the request
-   * @param commandName - The OCPP 2.0.1 command to execute (e.g., 'Authorize', 'TransactionEvent')
-   * @param commandParams - Optional parameters specific to the command being executed
-   * @param params - Optional request parameters for controlling request behavior
-   * @returns Promise resolving to the typed response from the CSMS
-   * @throws {OCPPError} When the command is not supported, validation fails, or CSMS returns an error
-   */
-  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
-  public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
-    chargingStation: ChargingStation,
-    commandName: OCPP20RequestCommand,
-    commandParams?: RequestType,
-    params?: RequestParams
-  ): Promise<ResponseType> {
-    logger.debug(
-      `${chargingStation.logPrefix()} ${moduleName}.requestHandler: Processing '${commandName}' request`
-    )
-    if (isRequestCommandSupported(chargingStation, commandName)) {
-      try {
-        logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.requestHandler: Building request payload for '${commandName}'`
-        )
-        const requestPayload =
-          params?.rawPayload === true
-            ? (commandParams as RequestType)
-            : this.buildRequestPayload(chargingStation, commandName, commandParams)
-        const messageId = generateUUID()
-        logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
-        )
-        const response = (await this.sendMessage(
-          chargingStation,
-          messageId,
-          requestPayload,
-          commandName,
-          params
-        )) as ResponseType
-        logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.requestHandler: '${commandName}' request completed successfully`
-        )
-        return response
-      } catch (error) {
-        this.logRequestHandlerError(chargingStation, moduleName, commandName, error)
-        throw error
-      }
-    }
-    // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
-    const errorMsg = `Unsupported OCPP command ${commandName}`
-    logger.error(`${chargingStation.logPrefix()} ${moduleName}.requestHandler: ${errorMsg}`)
-    throw new OCPPError(ErrorType.NOT_SUPPORTED, errorMsg, commandName, commandParams)
-  }
-
-  private buildRequestPayload (
+  protected buildRequestPayload (
     chargingStation: ChargingStation,
     commandName: OCPP20RequestCommand,
     commandParams?: JsonType
index 0ebc90705d1b754da15776ba8c6fc995fbd49843..ccfb695f3604bd2241af8c8d1425f02bd2bb14fc 100644 (file)
@@ -6,7 +6,6 @@ import {
   type ComponentType,
   DataEnumType,
   GetVariableStatusEnumType,
-  MutabilityEnumType,
   OCPP20ComponentName,
   type OCPP20GetVariableDataType,
   type OCPP20GetVariableResultType,
@@ -14,7 +13,6 @@ import {
   OCPP20RequiredVariableName,
   type OCPP20SetVariableDataType,
   type OCPP20SetVariableResultType,
-  PersistenceEnumType,
   ReasonCodeEnumType,
   SetVariableStatusEnumType,
   type VariableType,
@@ -33,6 +31,10 @@ import {
   buildCaseInsensitiveCompositeKey,
   enforceReportingValueSize,
   getVariableMetadata,
+  isPersistent,
+  isReadOnly,
+  isVolatile,
+  isWriteOnly,
   resolveValue,
   validateValue,
   VARIABLE_REGISTRY,
@@ -251,10 +253,10 @@ export class OCPP20VariableManager {
     for (const metaKey of Object.keys(VARIABLE_REGISTRY)) {
       const variableMetadata = VARIABLE_REGISTRY[metaKey]
       // Enforce persistent non-write-only variables across components
-      if (variableMetadata.persistence !== PersistenceEnumType.Persistent) {
+      if (!isPersistent(variableMetadata)) {
         continue
       }
-      if (variableMetadata.mutability === MutabilityEnumType.WriteOnly) {
+      if (isWriteOnly(variableMetadata)) {
         continue
       }
       // Instance-scoped persistent variables are also auto-created when defaultValue is defined
@@ -387,7 +389,8 @@ export class OCPP20VariableManager {
       variable.instance ?? component.instance
     )
     if (
-      variableMetadata?.mutability === MutabilityEnumType.WriteOnly &&
+      variableMetadata != null &&
+      isWriteOnly(variableMetadata) &&
       resolvedAttributeType === AttributeEnumType.Actual
     ) {
       return this.rejectGet(
@@ -626,10 +629,7 @@ export class OCPP20VariableManager {
 
     let value = resolveValue(chargingStation, variableMetadata)
 
-    if (
-      variableMetadata.persistence === PersistenceEnumType.Persistent &&
-      variableMetadata.mutability !== MutabilityEnumType.WriteOnly
-    ) {
+    if (isPersistent(variableMetadata) && !isWriteOnly(variableMetadata)) {
       const configurationKeyName = computeConfigurationKeyName(variableMetadata)
       let cfg = getConfigurationKey(chargingStation, configurationKeyName)
 
@@ -651,10 +651,7 @@ export class OCPP20VariableManager {
       }
     }
 
-    if (
-      variableMetadata.persistence === PersistenceEnumType.Volatile &&
-      variableMetadata.mutability !== MutabilityEnumType.ReadOnly
-    ) {
+    if (isVolatile(variableMetadata) && !isReadOnly(variableMetadata)) {
       const stationId = this.getStationId(chargingStation)
       const override = this.getRuntimeOverrides(stationId).get(compositeKey)
       if (override != null) {
@@ -737,7 +734,7 @@ export class OCPP20VariableManager {
       variable.name
     )
     if (invalidVariables.has(variableKey) && resolvedAttributeType === AttributeEnumType.Actual) {
-      if (variableMetadata.mutability !== MutabilityEnumType.WriteOnly) {
+      if (!isWriteOnly(variableMetadata)) {
         return this.rejectSet(
           variable,
           component,
@@ -857,7 +854,7 @@ export class OCPP20VariableManager {
       }
     }
 
-    if (variableMetadata.mutability === MutabilityEnumType.ReadOnly) {
+    if (isReadOnly(variableMetadata)) {
       return this.rejectSet(
         variable,
         component,
@@ -1001,10 +998,7 @@ export class OCPP20VariableManager {
     const configurationKeyName = computeConfigurationKeyName(variableMetadata)
     const previousValue = getConfigurationKey(chargingStation, configurationKeyName)?.value
 
-    if (
-      variableMetadata.persistence === PersistenceEnumType.Persistent &&
-      variableMetadata.mutability !== MutabilityEnumType.WriteOnly
-    ) {
+    if (isPersistent(variableMetadata) && !isWriteOnly(variableMetadata)) {
       const configKey = getConfigurationKey(chargingStation, configurationKeyName)
       if (configKey == null) {
         addConfigurationKey(chargingStation, configurationKeyName, attributeValue, undefined, {
@@ -1034,7 +1028,7 @@ export class OCPP20VariableManager {
       chargingStation.restartWebSocketPing()
     }
     // Apply volatile runtime override generically (single location)
-    if (variableMetadata.persistence === PersistenceEnumType.Volatile) {
+    if (isVolatile(variableMetadata)) {
       this.getRuntimeOverrides(stationId).set(variableKey, attributeValue)
     }
 
index 76369304570330fedc7a29b6044b73d008f5e522..6694394c3006dd5a6cd2b806ff707a8e5af7dc45 100644 (file)
@@ -2609,6 +2609,15 @@ export function isReadOnly (variableMetadata: VariableMetadata): boolean {
   return variableMetadata.mutability === MutabilityEnumType.ReadOnly
 }
 
+/**
+ * Check if variable metadata is volatile.
+ * @param variableMetadata - Variable metadata entry.
+ * @returns `true` when persistence is Volatile.
+ */
+export function isVolatile (variableMetadata: VariableMetadata): boolean {
+  return variableMetadata.persistence === PersistenceEnumType.Volatile
+}
+
 /**
  * Check if variable metadata is write-only.
  * @param variableMetadata - Variable metadata entry.
index 79329988aa9a096748c5bc8a74880748c8ece10a..a93057d4b4fb7ca27e94960fc17f6c6426adaaf0 100644 (file)
@@ -24,13 +24,19 @@ import {
 import {
   ensureError,
   formatDurationMilliSeconds,
+  generateUUID,
   getErrorMessage,
   getMessageTypeString,
   handleSendMessageError,
   logger,
 } from '../../utils/index.js'
 import { OCPPConstants } from './OCPPConstants.js'
-import { type Ajv, createAjv, validatePayload } from './OCPPServiceUtils.js'
+import {
+  type Ajv,
+  createAjv,
+  isRequestCommandSupported,
+  validatePayload,
+} from './OCPPServiceUtils.js'
 
 const defaultRequestParams: RequestParams = {
   skipBufferingOnError: false,
@@ -47,15 +53,22 @@ export abstract class OCPPRequestService {
   >()
 
   protected readonly ajv: Ajv
+  protected readonly moduleName: string
   protected abstract payloadValidatorFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
   private readonly ocppResponseService: OCPPResponseService
   private readonly version: OCPPVersion
 
-  protected constructor (version: OCPPVersion, ocppResponseService: OCPPResponseService) {
+  protected constructor (
+    version: OCPPVersion,
+    ocppResponseService: OCPPResponseService,
+    moduleName: string
+  ) {
     this.version = version
+    this.moduleName = moduleName
     this.ajv = createAjv()
     this.ocppResponseService = ocppResponseService
     this.requestHandler = this.requestHandler.bind(this)
+    this.buildRequestPayload = this.buildRequestPayload.bind(this)
     this.sendMessage = this.sendMessage.bind(this)
     this.sendResponse = this.sendResponse.bind(this)
     this.sendError = this.sendError.bind(this)
@@ -85,12 +98,50 @@ export abstract class OCPPRequestService {
    * @returns Response payload from the Central System.
    */
   // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
-  public abstract requestHandler<ReqType extends JsonType, ResType extends JsonType>(
+  public async requestHandler<ReqType extends JsonType, ResType extends JsonType>(
     chargingStation: ChargingStation,
     commandName: RequestCommand,
     commandParams?: ReqType,
     params?: RequestParams
-  ): Promise<ResType>
+  ): Promise<ResType> {
+    logger.debug(
+      `${chargingStation.logPrefix()} ${this.moduleName}.requestHandler: Processing '${commandName}' request`
+    )
+    if (isRequestCommandSupported(chargingStation, commandName)) {
+      try {
+        logger.debug(
+          `${chargingStation.logPrefix()} ${this.moduleName}.requestHandler: Building request payload for '${commandName}'`
+        )
+        const requestPayload =
+          params?.rawPayload === true
+            ? (commandParams as ReqType)
+            : this.buildRequestPayload(chargingStation, commandName, commandParams)
+        const messageId = generateUUID()
+        logger.debug(
+          `${chargingStation.logPrefix()} ${this.moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
+        )
+        await this.preRequestHook(chargingStation, commandName, commandParams)
+        const response = (await this.sendMessage(
+          chargingStation,
+          messageId,
+          requestPayload,
+          commandName,
+          params
+        )) as ResType
+        logger.debug(
+          `${chargingStation.logPrefix()} ${this.moduleName}.requestHandler: '${commandName}' request completed successfully`
+        )
+        return response
+      } catch (error) {
+        this.logRequestHandlerError(chargingStation, commandName, error)
+        throw error
+      }
+    }
+    // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
+    const errorMsg = `Unsupported OCPP command ${commandName}`
+    logger.error(`${chargingStation.logPrefix()} ${this.moduleName}.requestHandler: ${errorMsg}`)
+    throw new OCPPError(ErrorType.NOT_SUPPORTED, errorMsg, commandName, commandParams)
+  }
 
   public async sendError (
     chargingStation: ChargingStation,
@@ -145,18 +196,39 @@ export abstract class OCPPRequestService {
     }
   }
 
+  protected abstract buildRequestPayload (
+    chargingStation: ChargingStation,
+    commandName: RequestCommand,
+    commandParams?: JsonType
+  ): JsonType
+
   protected logRequestHandlerError (
     chargingStation: ChargingStation,
-    subclassModuleName: string,
     commandName: RequestCommand,
     error: unknown
   ): void {
     logger.error(
-      `${chargingStation.logPrefix()} ${subclassModuleName}.requestHandler: Error processing '${commandName}' request:`,
+      `${chargingStation.logPrefix()} ${this.moduleName}.requestHandler: Error processing '${commandName}' request:`,
       error
     )
   }
 
+  /**
+   * Pre-request actions hook run after message id generation and before the
+   * request is sent. Base implementation is a no-op; overridden per OCPP
+   * version that needs a version-specific step (e.g. OCPP 1.6 StartTransaction).
+   * @param _chargingStation - Target charging station.
+   * @param _commandName - OCPP request command name.
+   * @param _commandParams - Optional request payload.
+   */
+  protected preRequestHook (
+    _chargingStation: ChargingStation,
+    _commandName: RequestCommand,
+    _commandParams?: JsonType
+  ): Promise<void> | void {
+    /* No-op by default */
+  }
+
   protected async sendMessage (
     chargingStation: ChargingStation,
     messageId: string,
@@ -319,12 +391,7 @@ export abstract class OCPPRequestService {
          * @param requestPayload - The original request payload
          */
         const responseCallback = (payload: JsonType, requestPayload: JsonType): void => {
-          if (chargingStation.stationInfo?.enableStatistics === true) {
-            chargingStation.performanceStatistics?.addRequestStatistic(
-              commandName,
-              MessageType.CALL_RESULT_MESSAGE
-            )
-          }
+          chargingStation.recordRequestStatistic(commandName, MessageType.CALL_RESULT_MESSAGE)
           self.ocppResponseService
             .responseHandler(
               chargingStation,
@@ -349,11 +416,8 @@ export abstract class OCPPRequestService {
          * @param requestStatistic - Whether to record request statistics
          */
         const errorCallback = (ocppError: OCPPError, requestStatistic = true): void => {
-          if (requestStatistic && chargingStation.stationInfo?.enableStatistics === true) {
-            chargingStation.performanceStatistics?.addRequestStatistic(
-              commandName,
-              MessageType.CALL_ERROR_MESSAGE
-            )
+          if (requestStatistic) {
+            chargingStation.recordRequestStatistic(commandName, MessageType.CALL_ERROR_MESSAGE)
           }
           logger.error(
             `${chargingStation.logPrefix()} Error occurred at ${getMessageTypeString(
@@ -390,9 +454,7 @@ export abstract class OCPPRequestService {
           reject(ocppError)
         }
 
-        if (chargingStation.stationInfo?.enableStatistics === true) {
-          chargingStation.performanceStatistics?.addRequestStatistic(commandName, messageType)
-        }
+        chargingStation.recordRequestStatistic(commandName, messageType)
         const messageToSend = this.buildMessageToSend(
           chargingStation,
           messageId,
index 44ffb05040e4c4fb0c32e071421966414fb86c22..4312f1df88a8ef0eaa01ccc6a8a2f7b40c58262b 100644 (file)
@@ -17,7 +17,7 @@ import { OCPP20ServiceUtils } from './2.0/OCPP20ServiceUtils.js'
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus as AuthStatus,
+  AuthResultStatus as AuthStatus,
   IdentifierType,
   OCPPAuthServiceFactory,
 } from './auth/index.js'
index 65acfb2b6df5bd43d811bbc29d3cc7be918cf0ee..b0b9447c79feaa25a5f1b7e5cc72eacf03ad88e2 100644 (file)
@@ -1962,7 +1962,7 @@ export const PayloadValidatorOptions = (
  * @returns Parsed JSON schema object
  * @throws {NodeJS.ErrnoException} If the schema file cannot be read or parsed
  */
-export function parseJsonSchemaFile<T extends JsonType> (
+function parseJsonSchemaFile<T extends JsonType> (
   relativePath: string,
   ocppVersion: OCPPVersion,
   moduleName?: string,
index c611a5766935ae5997ec42a05b7543d6211a4a8b..d0c9ad770c211aa2fea6be5b316756acb4b1b4ed 100644 (file)
@@ -28,7 +28,7 @@ import {
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
   mapOCPP16Status,
   mapToOCPP16Status,
@@ -118,7 +118,7 @@ export class OCPP16AuthAdapter implements OCPPAuthAdapter<string> {
         },
         isOffline: false,
         method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-        status: AuthorizationStatus.INVALID,
+        status: AuthResultStatus.INVALID,
         timestamp: new Date(),
       }
     }
index 51c796bc591f2be6011e705babd876910324b782..7e6318a4c1de257d23257d1550c005ee403a3ea1 100644 (file)
@@ -27,7 +27,7 @@ import { getErrorMessage, isEmpty, logger, truncateId } from '../../../../utils/
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
   mapOCPP20AuthorizationStatus,
   mapOCPP20TokenType,
@@ -77,7 +77,7 @@ export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
           },
           isOffline: false,
           method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-          status: AuthorizationStatus.INVALID,
+          status: AuthResultStatus.INVALID,
           timestamp: new Date(),
         }
       }
@@ -94,7 +94,7 @@ export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
           },
           isOffline: false,
           method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-          status: AuthorizationStatus.INVALID,
+          status: AuthResultStatus.INVALID,
           timestamp: new Date(),
         }
       }
@@ -147,7 +147,7 @@ export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
         },
         isOffline: false,
         method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-        status: AuthorizationStatus.INVALID,
+        status: AuthResultStatus.INVALID,
         timestamp: new Date(),
       }
     }
index 29c1f5d70ca4d48470c523f1fd92153b33702b69..b0de8b99ef344857687486e354999d470a8b6b88 100644 (file)
@@ -4,7 +4,7 @@ import type { AuthCache, CacheStats } from '../interfaces/OCPPAuthService.js'
 import type { AuthorizationResult } from '../types/AuthTypes.js'
 
 import { Constants, isEmpty, logger, roundTo, truncateId } from '../../../../utils/index.js'
-import { AuthorizationStatus } from '../types/AuthTypes.js'
+import { AuthResultStatus } from '../types/AuthTypes.js'
 
 const moduleName = 'InMemoryAuthCache'
 
@@ -192,7 +192,7 @@ export class InMemoryAuthCache implements AuthCache {
     if (now >= authCacheEntry.expiresAt) {
       this.stats.expired++
       // Transition to EXPIRED status instead of deleting (C10.FR.08)
-      authCacheEntry.result = { ...authCacheEntry.result, status: AuthorizationStatus.EXPIRED }
+      authCacheEntry.result = { ...authCacheEntry.result, status: AuthResultStatus.EXPIRED }
       // Apply absolute lifetime cap to expired-transition TTL refresh (default-TTL entries only)
       if (!authCacheEntry.hasExplicitTtl) {
         const absoluteDeadline = authCacheEntry.createdAt + this.maxAbsoluteLifetimeMs
@@ -293,13 +293,13 @@ export class InMemoryAuthCache implements AuthCache {
     const now = Date.now()
     for (const [key, entry] of this.cache.entries()) {
       if (now >= entry.expiresAt) {
-        if (entry.result.status === AuthorizationStatus.EXPIRED) {
+        if (entry.result.status === AuthResultStatus.EXPIRED) {
           // Already transitioned by get() — delete on second expiration cycle
           this.cache.delete(key)
           this.lruOrder.delete(key)
         } else {
           // First expiration — transition to EXPIRED status (consistent with get() C10.FR.08 semantics)
-          entry.result = { ...entry.result, status: AuthorizationStatus.EXPIRED }
+          entry.result = { ...entry.result, status: AuthResultStatus.EXPIRED }
           if (!entry.hasExplicitTtl) {
             const absoluteDeadline = entry.createdAt + this.maxAbsoluteLifetimeMs
             if (absoluteDeadline > now) {
@@ -439,7 +439,7 @@ export class InMemoryAuthCache implements AuthCache {
     for (const [identifier, accessTime] of this.lruOrder.entries()) {
       const authCacheEntry = this.cache.get(identifier)
       if (
-        authCacheEntry?.result.status !== AuthorizationStatus.ACCEPTED &&
+        authCacheEntry?.result.status !== AuthResultStatus.ACCEPTED &&
         accessTime < candidateTime
       ) {
         candidateTime = accessTime
index fd9cc06042b655e7fa440f4e65aeae1e3d664697..6a7e0056fb5c2082fe938e4ec7222eab4883453c 100644 (file)
@@ -27,8 +27,8 @@ export {
   AuthenticationMethod,
   AuthErrorCode,
   type AuthorizationResult,
-  AuthorizationStatus,
   type AuthRequest,
+  AuthResultStatus,
   type CertificateHashData,
   type Identifier,
   IdentifierType,
index 3d80b236d6b7da271bcae59e56b2c6cd2fa7d7cd..783a37cf33c018556f5d27e5b996c4d2861f096f 100644 (file)
@@ -2,8 +2,8 @@ import type { JsonObject, OCPPVersion } from '../../../../types/index.js'
 import type {
   AuthConfiguration,
   AuthorizationResult,
-  AuthorizationStatus,
   AuthRequest,
+  AuthResultStatus,
   Identifier,
   IdentifierType,
 } from '../types/AuthTypes.js'
@@ -483,7 +483,7 @@ export interface OCPPAuthService {
    */
   updateCacheEntry(
     identifier: string,
-    status: AuthorizationStatus,
+    status: AuthResultStatus,
     expiryDate?: Date | string,
     identifierType?: IdentifierType
   ): void
index aec52fdaccfb0ce4dac6073233b6a76bcab23a21..c45ec094136c9e47798d4ebed93522a83ecbcd24 100644 (file)
@@ -28,8 +28,8 @@ import {
   AuthContext,
   AuthenticationMethod,
   type AuthorizationResult,
-  AuthorizationStatus,
   type AuthRequest,
+  AuthResultStatus,
   type Identifier,
   IdentifierType,
 } from '../types/AuthTypes.js'
@@ -192,7 +192,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
       },
       isOffline: false,
       method: AuthenticationMethod.NONE,
-      status: AuthorizationStatus.INVALID,
+      status: AuthResultStatus.INVALID,
       timestamp: new Date(),
     }
   }
@@ -470,7 +470,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
 
   public updateCacheEntry (
     identifier: string,
-    status: AuthorizationStatus,
+    status: AuthResultStatus,
     expiryDate?: Date | string,
     identifierType?: IdentifierType
   ): void {
@@ -600,7 +600,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
       ocppVersion: this.chargingStation.stationInfo?.ocppVersion,
       offlineAuthorizationEnabled: true,
       remoteAuthorization: true,
-      unknownIdAuthorization: AuthorizationStatus.INVALID,
+      unknownIdAuthorization: AuthResultStatus.INVALID,
     }
   }
 
@@ -680,7 +680,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
   ): void {
     this.metrics.totalResponseTime += duration
 
-    if (result.status === AuthorizationStatus.ACCEPTED) {
+    if (result.status === AuthResultStatus.ACCEPTED) {
       this.metrics.successfulAuth++
     } else {
       this.metrics.failedAuth++
index 5cfc278e4b5ae20a440c517e2e1c8d1f3df4d3ef..2ad6c10890b6b7cf6218024d3f5e0eff31538415 100644 (file)
@@ -10,7 +10,7 @@ import type {
 
 import { OCPPVersion } from '../../../../types/index.js'
 import { isNotEmptyString, logger, sleep } from '../../../../utils/index.js'
-import { AuthenticationMethod, AuthorizationStatus, IdentifierType } from '../types/AuthTypes.js'
+import { AuthenticationMethod, AuthResultStatus, IdentifierType } from '../types/AuthTypes.js'
 
 const moduleName = 'CertificateAuthStrategy'
 
@@ -67,7 +67,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
           `${moduleName}: Certificate validation failed: ${String(certValidation.reason)}`
         )
         return this.createFailureResult(
-          AuthorizationStatus.INVALID,
+          AuthResultStatus.INVALID,
           certValidation.reason ?? 'Certificate validation failed',
           request.identifier,
           startTime
@@ -86,7 +86,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
       // Unreachable when the `canHandle` contract holds; defensive fallback
       // for unsupported OCPP versions.
       return this.createFailureResult(
-        AuthorizationStatus.INVALID,
+        AuthResultStatus.INVALID,
         `Certificate authentication not supported for OCPP ${this.adapter.ocppVersion}`,
         request.identifier,
         startTime
@@ -94,7 +94,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
     } catch (error) {
       logger.error(`${moduleName}: Certificate authorization error:`, error)
       return this.createFailureResult(
-        AuthorizationStatus.INVALID,
+        AuthResultStatus.INVALID,
         'Certificate authorization failed',
         request.identifier,
         startTime
@@ -181,7 +181,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
    * @returns Authorization result with failure status and diagnostic information
    */
   private createFailureResult (
-    status: AuthorizationStatus,
+    status: AuthResultStatus,
     reason: string,
     identifier: Identifier,
     startTime: number
@@ -275,7 +275,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
    * @param startTime - Request start timestamp for response time calculation
    */
   private updateStatistics (result: AuthorizationResult, startTime: number): void {
-    if (result.status === AuthorizationStatus.ACCEPTED) {
+    if (result.status === AuthResultStatus.ACCEPTED) {
       this.stats.successfulAuths++
     } else {
       this.stats.failedAuths++
@@ -375,7 +375,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
           expiryDate: this.calculateCertificateExpiry(request.identifier),
           isOffline: false,
           method: AuthenticationMethod.CERTIFICATE_BASED,
-          status: AuthorizationStatus.ACCEPTED,
+          status: AuthResultStatus.ACCEPTED,
           timestamp: new Date(),
         }
 
@@ -386,7 +386,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
         return successResult
       } else {
         return this.createFailureResult(
-          AuthorizationStatus.BLOCKED,
+          AuthResultStatus.BLOCKED,
           'Certificate validation failed',
           request.identifier,
           startTime
@@ -395,7 +395,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
     } catch (error) {
       logger.error(`${moduleName}: OCPP 2.0.1 certificate validation error:`, error)
       return this.createFailureResult(
-        AuthorizationStatus.INVALID,
+        AuthResultStatus.INVALID,
         'Certificate validation error',
         request.identifier,
         startTime
index 95766b7c355dddcce75dcd680a8d6bb266e82961..ad136b3cc22fa75278af801185175494bf6aee40 100644 (file)
@@ -12,7 +12,7 @@ import {
   AuthenticationError,
   AuthenticationMethod,
   AuthErrorCode,
-  AuthorizationStatus,
+  AuthResultStatus,
   enhanceAuthResult,
 } from '../types/AuthTypes.js'
 
@@ -395,7 +395,7 @@ export class LocalAuthStrategy implements AuthStrategy {
           expiryDate: entry.expiryDate,
           isOffline: false,
           method: AuthenticationMethod.LOCAL_LIST,
-          status: AuthorizationStatus.EXPIRED,
+          status: AuthResultStatus.EXPIRED,
           timestamp: new Date(),
         }
       }
@@ -446,14 +446,14 @@ export class LocalAuthStrategy implements AuthStrategy {
         additionalInfo: { reason: 'Transaction stop - offline mode' },
         isOffline: true,
         method: AuthenticationMethod.OFFLINE_FALLBACK,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date(),
       }
     }
 
     // For unknown IDs, check configuration
     if (config.allowOfflineTxForUnknownId) {
-      const status = config.unknownIdAuthorization ?? AuthorizationStatus.ACCEPTED
+      const status = config.unknownIdAuthorization ?? AuthResultStatus.ACCEPTED
 
       return {
         additionalInfo: { reason: 'Unknown ID allowed in offline mode' },
@@ -469,7 +469,7 @@ export class LocalAuthStrategy implements AuthStrategy {
       additionalInfo: { reason: 'Unknown ID not allowed in offline mode' },
       isOffline: true,
       method: AuthenticationMethod.OFFLINE_FALLBACK,
-      status: AuthorizationStatus.INVALID,
+      status: AuthResultStatus.INVALID,
       timestamp: new Date(),
     }
   }
@@ -479,26 +479,26 @@ export class LocalAuthStrategy implements AuthStrategy {
    * @param status - Status string from local auth list entry
    * @returns Authorization status corresponding to the entry status
    */
-  private mapEntryStatus (status: string): AuthorizationStatus {
+  private mapEntryStatus (status: string): AuthResultStatus {
     switch (status.toLowerCase()) {
       case 'accepted':
       case 'authorized':
       case 'valid':
-        return AuthorizationStatus.ACCEPTED
+        return AuthResultStatus.ACCEPTED
       case 'blocked':
       case 'disabled':
-        return AuthorizationStatus.BLOCKED
+        return AuthResultStatus.BLOCKED
       case 'concurrent':
       case 'concurrent_tx':
-        return AuthorizationStatus.CONCURRENT_TX
+        return AuthResultStatus.CONCURRENT_TX
       case 'expired':
-        return AuthorizationStatus.EXPIRED
+        return AuthResultStatus.EXPIRED
       case 'invalid':
       case 'unauthorized':
-        return AuthorizationStatus.INVALID
+        return AuthResultStatus.INVALID
       default:
         logger.warn(`${moduleName}: Unknown entry status: ${status}, defaulting to INVALID`)
-        return AuthorizationStatus.INVALID
+        return AuthResultStatus.INVALID
     }
   }
 
@@ -516,6 +516,6 @@ export class LocalAuthStrategy implements AuthStrategy {
     result: AuthorizationResult,
     config: AuthConfiguration
   ): boolean {
-    return result.status !== AuthorizationStatus.ACCEPTED && config.disablePostAuthorize !== true
+    return result.status !== AuthResultStatus.ACCEPTED && config.disablePostAuthorize !== true
   }
 }
index db59df06dcbcf5007ac419900f83db99f7b6929c..a95d8fa7fd09cf358e7c13c26dbb71a3bea33b54 100644 (file)
@@ -54,7 +54,7 @@ export enum AuthErrorCode {
 /**
  * Authorization status combining OCPP 1.6 and 2.0 statuses
  */
-export enum AuthorizationStatus {
+export enum AuthResultStatus {
   // Common statuses across versions
   ACCEPTED = 'Accepted',
   BLOCKED = 'Blocked',
@@ -154,7 +154,7 @@ export interface AuthConfiguration extends JsonObject {
   remoteAuthorization?: boolean
 
   /** Default authorization status for unknown IDs */
-  unknownIdAuthorization?: AuthorizationStatus
+  unknownIdAuthorization?: AuthResultStatus
 }
 
 /**
@@ -193,7 +193,7 @@ export interface AuthorizationResult {
   }
 
   /** Authorization status */
-  readonly status: AuthorizationStatus
+  readonly status: AuthResultStatus
 
   /** Timestamp of authorization */
   readonly timestamp: Date
@@ -369,23 +369,23 @@ export const requiresAdditionalInfo = (type: IdentifierType): boolean => {
  * @example
  * ```typescript
  * const status = mapOCPP16Status(OCPP16AuthorizationStatus.ACCEPTED)
- * // Returns: AuthorizationStatus.ACCEPTED
+ * // Returns: AuthResultStatus.ACCEPTED
  * ```
  */
-export const mapOCPP16Status = (status: OCPP16AuthorizationStatus): AuthorizationStatus => {
+export const mapOCPP16Status = (status: OCPP16AuthorizationStatus): AuthResultStatus => {
   switch (status) {
     case OCPP16AuthorizationStatus.ACCEPTED:
-      return AuthorizationStatus.ACCEPTED
+      return AuthResultStatus.ACCEPTED
     case OCPP16AuthorizationStatus.BLOCKED:
-      return AuthorizationStatus.BLOCKED
+      return AuthResultStatus.BLOCKED
     case OCPP16AuthorizationStatus.CONCURRENT_TX:
-      return AuthorizationStatus.CONCURRENT_TX
+      return AuthResultStatus.CONCURRENT_TX
     case OCPP16AuthorizationStatus.EXPIRED:
-      return AuthorizationStatus.EXPIRED
+      return AuthResultStatus.EXPIRED
     case OCPP16AuthorizationStatus.INVALID:
-      return AuthorizationStatus.INVALID
+      return AuthResultStatus.INVALID
     default:
-      return AuthorizationStatus.INVALID
+      return AuthResultStatus.INVALID
   }
 }
 
@@ -396,35 +396,35 @@ export const mapOCPP16Status = (status: OCPP16AuthorizationStatus): Authorizatio
  * @example
  * ```typescript
  * const status = mapOCPP20AuthorizationStatus(OCPP20AuthorizationStatusEnumType.Accepted)
- * // Returns: AuthorizationStatus.ACCEPTED
+ * // Returns: AuthResultStatus.ACCEPTED
  * ```
  */
 export const mapOCPP20AuthorizationStatus = (
   status: OCPP20AuthorizationStatusEnumType
-): AuthorizationStatus => {
+): AuthResultStatus => {
   switch (status) {
     case OCPP20AuthorizationStatusEnumType.Accepted:
-      return AuthorizationStatus.ACCEPTED
+      return AuthResultStatus.ACCEPTED
     case OCPP20AuthorizationStatusEnumType.Blocked:
-      return AuthorizationStatus.BLOCKED
+      return AuthResultStatus.BLOCKED
     case OCPP20AuthorizationStatusEnumType.ConcurrentTx:
-      return AuthorizationStatus.CONCURRENT_TX
+      return AuthResultStatus.CONCURRENT_TX
     case OCPP20AuthorizationStatusEnumType.Expired:
-      return AuthorizationStatus.EXPIRED
+      return AuthResultStatus.EXPIRED
     case OCPP20AuthorizationStatusEnumType.Invalid:
-      return AuthorizationStatus.INVALID
+      return AuthResultStatus.INVALID
     case OCPP20AuthorizationStatusEnumType.NoCredit:
-      return AuthorizationStatus.NO_CREDIT
+      return AuthResultStatus.NO_CREDIT
     case OCPP20AuthorizationStatusEnumType.NotAllowedTypeEVSE:
-      return AuthorizationStatus.NOT_ALLOWED_TYPE_EVSE
+      return AuthResultStatus.NOT_ALLOWED_TYPE_EVSE
     case OCPP20AuthorizationStatusEnumType.NotAtThisLocation:
-      return AuthorizationStatus.NOT_AT_THIS_LOCATION
+      return AuthResultStatus.NOT_AT_THIS_LOCATION
     case OCPP20AuthorizationStatusEnumType.NotAtThisTime:
-      return AuthorizationStatus.NOT_AT_THIS_TIME
+      return AuthResultStatus.NOT_AT_THIS_TIME
     case OCPP20AuthorizationStatusEnumType.Unknown:
-      return AuthorizationStatus.UNKNOWN
+      return AuthResultStatus.UNKNOWN
     default:
-      return AuthorizationStatus.INVALID
+      return AuthResultStatus.INVALID
   }
 }
 
@@ -467,25 +467,25 @@ export const mapOCPP20TokenType = (type: OCPP20IdTokenEnumType): IdentifierType
  * @returns OCPP 1.6 authorization status
  * @example
  * ```typescript
- * const ocpp16Status = mapToOCPP16Status(AuthorizationStatus.ACCEPTED)
+ * const ocpp16Status = mapToOCPP16Status(AuthResultStatus.ACCEPTED)
  * // Returns: OCPP16AuthorizationStatus.ACCEPTED
  * ```
  */
-export const mapToOCPP16Status = (status: AuthorizationStatus): OCPP16AuthorizationStatus => {
+export const mapToOCPP16Status = (status: AuthResultStatus): OCPP16AuthorizationStatus => {
   switch (status) {
-    case AuthorizationStatus.ACCEPTED:
+    case AuthResultStatus.ACCEPTED:
       return OCPP16AuthorizationStatus.ACCEPTED
-    case AuthorizationStatus.BLOCKED:
+    case AuthResultStatus.BLOCKED:
       return OCPP16AuthorizationStatus.BLOCKED
-    case AuthorizationStatus.CONCURRENT_TX:
+    case AuthResultStatus.CONCURRENT_TX:
       return OCPP16AuthorizationStatus.CONCURRENT_TX
-    case AuthorizationStatus.EXPIRED:
+    case AuthResultStatus.EXPIRED:
       return OCPP16AuthorizationStatus.EXPIRED
-    case AuthorizationStatus.INVALID:
-    case AuthorizationStatus.NOT_AT_THIS_LOCATION:
-    case AuthorizationStatus.NOT_AT_THIS_TIME:
-    case AuthorizationStatus.PENDING:
-    case AuthorizationStatus.UNKNOWN:
+    case AuthResultStatus.INVALID:
+    case AuthResultStatus.NOT_AT_THIS_LOCATION:
+    case AuthResultStatus.NOT_AT_THIS_TIME:
+    case AuthResultStatus.PENDING:
+    case AuthResultStatus.UNKNOWN:
     default:
       return OCPP16AuthorizationStatus.INVALID
   }
@@ -497,22 +497,22 @@ export const mapToOCPP16Status = (status: AuthorizationStatus): OCPP16Authorizat
  * @returns OCPP 2.0.1 RequestStartStopStatus
  * @example
  * ```typescript
- * const ocpp20Status = mapToOCPP20Status(AuthorizationStatus.ACCEPTED)
+ * const ocpp20Status = mapToOCPP20Status(AuthResultStatus.ACCEPTED)
  * // Returns: RequestStartStopStatusEnumType.Accepted
  * ```
  */
-export const mapToOCPP20Status = (status: AuthorizationStatus): RequestStartStopStatusEnumType => {
+export const mapToOCPP20Status = (status: AuthResultStatus): RequestStartStopStatusEnumType => {
   switch (status) {
-    case AuthorizationStatus.ACCEPTED:
+    case AuthResultStatus.ACCEPTED:
       return RequestStartStopStatusEnumType.Accepted
-    case AuthorizationStatus.BLOCKED:
-    case AuthorizationStatus.CONCURRENT_TX:
-    case AuthorizationStatus.EXPIRED:
-    case AuthorizationStatus.INVALID:
-    case AuthorizationStatus.NOT_AT_THIS_LOCATION:
-    case AuthorizationStatus.NOT_AT_THIS_TIME:
-    case AuthorizationStatus.PENDING:
-    case AuthorizationStatus.UNKNOWN:
+    case AuthResultStatus.BLOCKED:
+    case AuthResultStatus.CONCURRENT_TX:
+    case AuthResultStatus.EXPIRED:
+    case AuthResultStatus.INVALID:
+    case AuthResultStatus.NOT_AT_THIS_LOCATION:
+    case AuthResultStatus.NOT_AT_THIS_TIME:
+    case AuthResultStatus.PENDING:
+    case AuthResultStatus.UNKNOWN:
     default:
       return RequestStartStopStatusEnumType.Rejected
   }
index b49ced81be37b2706b2ec9c3f11cdee445e06606..494cab44919aeabe77b4e14b6af592d7b0234d33 100644 (file)
@@ -9,7 +9,7 @@ import type {
 } from '../types/AuthTypes.js'
 
 import { isEmpty, truncateId } from '../../../../utils/index.js'
-import { AuthorizationStatus } from '../types/AuthTypes.js'
+import { AuthResultStatus } from '../types/AuthTypes.js'
 
 /**
  * @param expiryDate - Expiry timestamp to compute TTL from
@@ -62,7 +62,7 @@ function createAuthRequest (
  * @returns AuthorizationResult with isOffline=false
  */
 function createRejectedResult (
-  status: AuthorizationStatus,
+  status: AuthResultStatus,
   method: AuthenticationMethod,
   reason?: string
 ): AuthorizationResult {
@@ -90,25 +90,25 @@ function formatAuthError (error: Error, identifier: Identifier): string {
  * @param status - Authorization status to describe
  * @returns Descriptive message for the status
  */
-function getStatusMessage (status: AuthorizationStatus): string {
+function getStatusMessage (status: AuthResultStatus): string {
   switch (status) {
-    case AuthorizationStatus.ACCEPTED:
+    case AuthResultStatus.ACCEPTED:
       return 'Authorization accepted'
-    case AuthorizationStatus.BLOCKED:
+    case AuthResultStatus.BLOCKED:
       return 'Identifier is blocked'
-    case AuthorizationStatus.CONCURRENT_TX:
+    case AuthResultStatus.CONCURRENT_TX:
       return 'Concurrent transaction in progress'
-    case AuthorizationStatus.EXPIRED:
+    case AuthResultStatus.EXPIRED:
       return 'Authorization has expired'
-    case AuthorizationStatus.INVALID:
+    case AuthResultStatus.INVALID:
       return 'Invalid identifier'
-    case AuthorizationStatus.NOT_AT_THIS_LOCATION:
+    case AuthResultStatus.NOT_AT_THIS_LOCATION:
       return 'Not authorized at this location'
-    case AuthorizationStatus.NOT_AT_THIS_TIME:
+    case AuthResultStatus.NOT_AT_THIS_TIME:
       return 'Not authorized at this time'
-    case AuthorizationStatus.PENDING:
+    case AuthResultStatus.PENDING:
       return 'Authorization pending'
-    case AuthorizationStatus.UNKNOWN:
+    case AuthResultStatus.UNKNOWN:
       return 'Unknown authorization status'
     default:
       return 'Authorization failed'
@@ -121,11 +121,9 @@ function getStatusMessage (status: AuthorizationStatus): string {
  * @returns `true` if BLOCKED, EXPIRED, or INVALID
  */
 function isPermanentFailure (result: AuthorizationResult): boolean {
-  return [
-    AuthorizationStatus.BLOCKED,
-    AuthorizationStatus.EXPIRED,
-    AuthorizationStatus.INVALID,
-  ].includes(result.status)
+  return [AuthResultStatus.BLOCKED, AuthResultStatus.EXPIRED, AuthResultStatus.INVALID].includes(
+    result.status
+  )
 }
 
 /**
@@ -134,7 +132,7 @@ function isPermanentFailure (result: AuthorizationResult): boolean {
  * @returns `true` if ACCEPTED and expiry date has not passed
  */
 function isResultValid (result: AuthorizationResult): boolean {
-  if (result.status !== AuthorizationStatus.ACCEPTED) {
+  if (result.status !== AuthResultStatus.ACCEPTED) {
     return false
   }
 
@@ -152,11 +150,11 @@ function isResultValid (result: AuthorizationResult): boolean {
  * @returns `true` if PENDING or UNKNOWN
  */
 function isTemporaryFailure (result: AuthorizationResult): boolean {
-  if (result.status === AuthorizationStatus.PENDING) {
+  if (result.status === AuthResultStatus.PENDING) {
     return true
   }
 
-  if (result.status === AuthorizationStatus.UNKNOWN) {
+  if (result.status === AuthResultStatus.UNKNOWN) {
     return true
   }
 
@@ -173,7 +171,7 @@ function mergeAuthResults (results: AuthorizationResult[]): AuthorizationResult
     return undefined
   }
 
-  const acceptedResult = results.find(r => r.status === AuthorizationStatus.ACCEPTED)
+  const acceptedResult = results.find(r => r.status === AuthResultStatus.ACCEPTED)
   if (acceptedResult) {
     return acceptedResult
   }
index 078470edcef2ab313682671db22ed4bcc8eb1748..71168e5e862a7a6d75dbf15a20e112f472b9386c 100644 (file)
@@ -28,6 +28,7 @@ import {
   getErrorMessage,
   isEmpty,
   isNotEmptyArray,
+  isOCPP20x,
   JSONStringify,
   logger,
 } from '../../utils/index.js'
@@ -188,7 +189,7 @@ export class UIMCPServer extends AbstractUIServer {
       if (expectedVersion === OCPPVersion.VERSION_16) {
         return s.version !== OCPPVersion.VERSION_16
       }
-      return s.version !== OCPPVersion.VERSION_20 && s.version !== OCPPVersion.VERSION_201
+      return !isOCPP20x(s.version)
     })
     if (isNotEmptyArray(mismatched)) {
       const ids = mismatched.map(s => s.hashId).join(', ')
index 97244d2b0b43dc067cf2d21e6559ffcf4bf48d7f..39414951138f7b30245ea74e37626a4e8b086f7a 100644 (file)
@@ -7,6 +7,7 @@ import {
   isEmpty,
   isLoopback,
   isNotEmptyArray,
+  isNotEmptyString,
   normalizeHost,
   normalizeIPAddress,
   UI_SERVER_ACCESS_POLICY_DEFAULTS,
@@ -320,7 +321,7 @@ const pickForwardedValue = (
 }
 
 const nonEmpty = (value: string | undefined): string | undefined =>
-  value == null || value.trim() === '' ? undefined : value
+  isNotEmptyString(value) ? value : undefined
 
 // RFC 7239 §6: "unknown" and obfuscated node identifiers ("_" + token chars).
 // Optional ":port" suffix is stripped before comparison.
index b09f6a5402aba7c6c194d221f5e99f30737d239a..7d14cad94ec45405ac70cecb3ab1efa419fb8bd0 100644 (file)
@@ -27,6 +27,7 @@ import {
   Constants,
   ensureError,
   getErrorMessage,
+  isEmpty,
   isNotEmptyArray,
   JSONStringify,
   logger,
@@ -193,7 +194,7 @@ export abstract class AbstractUIService {
       }
       if (
         requestContext.outstandingHashIds.delete(hashId) &&
-        requestContext.outstandingHashIds.size === 0
+        isEmpty(requestContext.outstandingHashIds)
       ) {
         this.uiServiceWorkerBroadcastChannel.completeReconciledRequest(uuid)
       }
@@ -212,7 +213,7 @@ export abstract class AbstractUIService {
     ) {
       return 'untracked'
     }
-    return requestContext.outstandingHashIds.size === 0 ? 'completed' : 'outstanding'
+    return isEmpty(requestContext.outstandingHashIds) ? 'completed' : 'outstanding'
   }
 
   public async requestHandler (
@@ -548,7 +549,7 @@ export abstract class AbstractUIService {
         ? payload.hashIds
         : this.uiServer.getChargingStationHashIds()
     )
-    if (outstandingHashIds.size === 0) {
+    if (isEmpty(outstandingHashIds)) {
       throw new BaseError('No charging station is available to handle the broadcast request')
     }
     // Safety-net timeout: if not all expected worker responses arrive (e.g. a
index 13a1a185cb234df92957419d5597fd38fc4af506..3399a47a9909539bb8036aee73fb5b9219c43825 100644 (file)
@@ -331,7 +331,7 @@ export class Configuration {
     }
     try {
       return watch(Configuration.configurationFile, (event, filename): void => {
-        if ((filename?.trim().length ?? 0) === 0 || event !== 'change') {
+        if (!isNotEmptyString(filename) || event !== 'change') {
           return
         }
         if (Configuration.configurationFileReloading) {
index 9f79a4880f70bdb4b4160074ae1f40efacd81ddb..040ec6d6499c60bfaa6e7d3a0a52385a5cbab7a7 100644 (file)
@@ -14,7 +14,7 @@ import {
 import { WorkerProcessType } from '../worker/index.js'
 import { CURRENT_CONFIGURATION_SCHEMA_VERSION } from './ConfigurationMigrations.js'
 import { isHostLiteralWithoutPort } from './HostUtils.js'
-import { has } from './Utils.js'
+import { has, isNotEmptyArray } from './Utils.js'
 
 // ---------------------------------------------------------------
 // Sub-schemas
@@ -165,17 +165,10 @@ const UIServerAccessPolicySchema = z
       .optional(),
   })
   .strict()
-  .refine(
-    value =>
-      !(
-        value.allowLoopbackProxy === true &&
-        (value.trustedProxies == null || value.trustedProxies.length === 0)
-      ),
-    {
-      message: "'allowLoopbackProxy' requires at least one entry in 'trustedProxies'",
-      path: ['trustedProxies'],
-    }
-  )
+  .refine(value => !(value.allowLoopbackProxy === true && !isNotEmptyArray(value.trustedProxies)), {
+    message: "'allowLoopbackProxy' requires at least one entry in 'trustedProxies'",
+    path: ['trustedProxies'],
+  })
 
 /**
  * UIServerListenOptionsObjectSchema — typed object layer for `node:net`
index 376144470fcea91a9c8ae5760dcdffb2fa7e4ac6..a8ca2e8dffbd71fa5049ffb297416471260b7062 100644 (file)
@@ -18,6 +18,7 @@ import {
   type JsonObject,
   MapStringifyFormat,
   MessageType,
+  OCPPVersion,
   type TimestampedData,
   type UUIDv4,
   WebSocketCloseEventStatusString,
@@ -116,6 +117,9 @@ export const isEmpty = (value: unknown): boolean => {
   return false
 }
 
+export const isOCPP20x = (version: OCPPVersion | undefined): boolean =>
+  version === OCPPVersion.VERSION_20 || version === OCPPVersion.VERSION_201
+
 // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
 export const mergeDeepRight = <T extends object, S extends object>(target: T, source: S): T => {
   const output: Record<string, unknown> = { ...(target as Record<string, unknown>) }
index 17d02bfb540939c4740c71e4cd4ab3f589598a81..02d1f1cdba94f707c6c9af8a8ba5a6afeec62265 100644 (file)
@@ -93,6 +93,7 @@ export {
   isJsonObject,
   isNotEmptyArray,
   isNotEmptyString,
+  isOCPP20x,
   isValidDate,
   isValidRandomIntBounds,
   JSONStringify,
index a233d6dfe38a46c104c0d3c19d48561ebf195b01..e6324f5c5cfa51ca421c231847d35aafe745aa89 100644 (file)
@@ -1,6 +1,6 @@
 import type { Worker } from 'node:worker_threads'
 
-import { type PoolEvent, PoolEvents, type ThreadPoolOptions } from 'poolifier'
+import { type ThreadPoolOptions } from 'poolifier'
 
 export enum WorkerMessageEvents {
   addedWorkerElement = 'addedWorkerElement',
@@ -50,13 +50,6 @@ export interface WorkerDataError extends WorkerData {
   stack?: string
 }
 
-export const WorkerEvents = {
-  ...PoolEvents,
-  ...WorkerSetEvents,
-} as const
-// eslint-disable-next-line @typescript-eslint/no-redeclare
-export type WorkerEvents = PoolEvent | WorkerSetEvents
-
 export interface WorkerMessage<T extends WorkerData> {
   data: T
   event: WorkerMessageEvents
index c0f9c65556e7b2e7055345c9a6e3e5008e96b560..07c9521cbcc304b0b9696dc9bd8ad61130581fc0 100644 (file)
@@ -10,7 +10,6 @@ export { WorkerFactory } from './WorkerFactory.js'
 export {
   type WorkerData,
   type WorkerDataError,
-  WorkerEvents,
   type WorkerMessage,
   WorkerMessageEvents,
   WorkerProcessType,
diff --git a/tests/charging-station/ChargingStation-RequestStatistic.test.ts b/tests/charging-station/ChargingStation-RequestStatistic.test.ts
new file mode 100644 (file)
index 0000000..dffb580
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * @file Tests for ChargingStation.recordRequestStatistic
+ * @description Verifies the single-sourced `enableStatistics` gate applied before
+ * delegating to performanceStatistics.addRequestStatistic.
+ */
+import assert from 'node:assert/strict'
+import { afterEach, describe, it, mock } from 'node:test'
+
+import type { ChargingStation } from '../../src/charging-station/index.js'
+
+import { ChargingStation as ChargingStationClass } from '../../src/charging-station/ChargingStation.js'
+import { MessageType, RequestCommand } from '../../src/types/index.js'
+import { standardCleanup } from '../helpers/TestLifecycleHelpers.js'
+
+interface RecordRequestStatisticContext {
+  performanceStatistics?: { addRequestStatistic: (...args: unknown[]) => void }
+  stationInfo?: { enableStatistics?: boolean }
+}
+
+const callRecordRequestStatistic = (
+  context: RecordRequestStatisticContext,
+  command: RequestCommand,
+  messageType: MessageType
+): void => {
+  ChargingStationClass.prototype.recordRequestStatistic.call(
+    context as unknown as ChargingStation,
+    command,
+    messageType
+  )
+}
+
+await describe('ChargingStation.recordRequestStatistic', async () => {
+  afterEach(() => {
+    standardCleanup()
+  })
+
+  await it('should record the statistic when enableStatistics is true', () => {
+    const addRequestStatistic = mock.fn()
+    callRecordRequestStatistic(
+      { performanceStatistics: { addRequestStatistic }, stationInfo: { enableStatistics: true } },
+      RequestCommand.HEARTBEAT,
+      MessageType.CALL_MESSAGE
+    )
+    assert.strictEqual(addRequestStatistic.mock.callCount(), 1)
+    assert.deepStrictEqual(addRequestStatistic.mock.calls[0].arguments, [
+      RequestCommand.HEARTBEAT,
+      MessageType.CALL_MESSAGE,
+    ])
+  })
+
+  await it('should not record the statistic when enableStatistics is not true', () => {
+    const addRequestStatistic = mock.fn()
+    callRecordRequestStatistic(
+      { performanceStatistics: { addRequestStatistic }, stationInfo: { enableStatistics: false } },
+      RequestCommand.HEARTBEAT,
+      MessageType.CALL_RESULT_MESSAGE
+    )
+    callRecordRequestStatistic(
+      { performanceStatistics: { addRequestStatistic }, stationInfo: {} },
+      RequestCommand.HEARTBEAT,
+      MessageType.CALL_RESULT_MESSAGE
+    )
+    assert.strictEqual(addRequestStatistic.mock.callCount(), 0)
+  })
+
+  await it('should not throw when performanceStatistics is undefined and enableStatistics is true', () => {
+    assert.doesNotThrow(() => {
+      callRecordRequestStatistic(
+        { stationInfo: { enableStatistics: true } },
+        RequestCommand.HEARTBEAT,
+        MessageType.CALL_ERROR_MESSAGE
+      )
+    })
+  })
+})
index 6cba65d532ca56e5cc8cd19d7e94888760aceacf..5db6c7976e92b224e067144d4dae213e0f3fd25a 100644 (file)
@@ -113,6 +113,31 @@ await describe('OCPP 1.6 Request Call Chain — requestHandler → buildRequestP
     })
   })
 
+  await describe('preRequestHook — OCPP 1.6 StartTransaction connector status transition', async () => {
+    await it('should set the connector status to Preparing before sending StartTransaction', async () => {
+      const connectorStatus = station.getConnectorStatus(1)
+      assert.strictEqual(connectorStatus?.status, OCPP16ChargePointStatus.Available)
+
+      await requestService.requestHandler(station, OCPP16RequestCommand.START_TRANSACTION, {
+        connectorId: 1,
+        idTag: 'TEST001',
+      })
+
+      assert.strictEqual(station.getConnectorStatus(1)?.status, OCPP16ChargePointStatus.Preparing)
+    })
+
+    await it('should not change the connector status for a command without a pre-request hook', async () => {
+      const connectorStatus = station.getConnectorStatus(1)
+      assert.strictEqual(connectorStatus?.status, OCPP16ChargePointStatus.Available)
+
+      await requestService.requestHandler(station, OCPP16RequestCommand.AUTHORIZE, {
+        idTag: 'TEST001',
+      })
+
+      assert.strictEqual(station.getConnectorStatus(1)?.status, OCPP16ChargePointStatus.Available)
+    })
+  })
+
   await describe('HEARTBEAT — no builder, empty payload', async () => {
     await it('should send empty payload for Heartbeat', async () => {
       await requestService.requestHandler(station, OCPP16RequestCommand.HEARTBEAT)
index 94293e6c4f667b5d8baa8dc33b398fcd89051084..0acdbe075d3887baca2a0b59e06112c5d0eaf021 100644 (file)
@@ -12,7 +12,7 @@ import { afterEach, describe, it } from 'node:test'
 
 import { OCPP16ServiceUtils } from '../../../../src/charging-station/ocpp/1.6/OCPP16ServiceUtils.js'
 import {
-  AuthorizationStatus,
+  AuthResultStatus,
   OCPPAuthServiceFactory,
 } from '../../../../src/charging-station/ocpp/auth/index.js'
 import {
@@ -662,7 +662,7 @@ await describe('OCPP16ServiceUtils — pure functions', async () => {
       const authCache = getTestAuthCache(authService)
       const cached = authCache.get(TEST_ID_TAG)
       assert.ok(cached != null)
-      assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
     })
 
     await it('should update auth cache with rejected status', () => {
@@ -686,7 +686,7 @@ await describe('OCPP16ServiceUtils — pure functions', async () => {
       const authCache = getTestAuthCache(authService)
       const cached = authCache.get(TEST_ID_TAG)
       assert.ok(cached != null)
-      assert.strictEqual(cached.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(cached.status, AuthResultStatus.BLOCKED)
     })
 
     await it('should set TTL from expiryDate when in future', () => {
@@ -712,7 +712,7 @@ await describe('OCPP16ServiceUtils — pure functions', async () => {
       const authCache = getTestAuthCache(authService)
       const cached = authCache.get(TEST_ID_TAG)
       assert.ok(cached != null, 'Cache entry should exist with future TTL')
-      assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
     })
 
     await it('should skip caching when expiryDate is in the past', () => {
@@ -761,7 +761,7 @@ await describe('OCPP16ServiceUtils — pure functions', async () => {
       const authCache = getTestAuthCache(authService)
       const cached = authCache.get(TEST_ID_TAG)
       assert.ok(cached != null, 'Cache entry should exist without TTL')
-      assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
     })
   })
 })
index d5df6670baadc61b84bd2774764e4a29a6972a76..e6746c01afe44228e1925838be1e5287f81004b9 100644 (file)
@@ -23,7 +23,7 @@ import { OCPP20IncomingRequestService } from '../../../../src/charging-station/o
 import { OCPP20VariableManager } from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableManager.js'
 import {
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   OCPPAuthServiceFactory,
 } from '../../../../src/charging-station/ocpp/auth/index.js'
 import {
@@ -122,7 +122,7 @@ await describe('F01 & F02 - Remote Start Transaction', async () => {
         Promise.resolve(
           createMockAuthorizationResult({
             method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-            status: AuthorizationStatus.INVALID,
+            status: AuthResultStatus.INVALID,
           })
         ),
     })
@@ -159,7 +159,7 @@ await describe('F01 & F02 - Remote Start Transaction', async () => {
           return Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           )
         }
@@ -167,7 +167,7 @@ await describe('F01 & F02 - Remote Start Transaction', async () => {
         return Promise.resolve(
           createMockAuthorizationResult({
             method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-            status: AuthorizationStatus.BLOCKED,
+            status: AuthResultStatus.BLOCKED,
           })
         )
       },
index 48d067aa926a756e1593c86e7e1cb4c33c854d1a..bc4541662fb81781ff6c8d5a078bae2d1775b852 100644 (file)
@@ -11,7 +11,7 @@ import type { ChargingStation } from '../../../../src/charging-station/index.js'
 import type { AuthCache } from '../../../../src/charging-station/ocpp/auth/interfaces/OCPPAuthService.js'
 
 import {
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
   OCPPAuthServiceFactory,
 } from '../../../../src/charging-station/ocpp/auth/index.js'
@@ -56,7 +56,7 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Act
     authService.updateCacheEntry(
       TEST_TOKEN_ISO14443,
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       undefined,
       IdentifierType.ISO14443
     )
@@ -64,7 +64,7 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Assert
     const cached = authCache.get(TEST_TOKEN_ISO14443)
     assert.ok(cached != null, 'Cache entry should exist')
-    assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+    assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
   })
 
   await it('C10.FR.09 - should use cacheExpiryDateTime as TTL when present in idTokenInfo', () => {
@@ -74,7 +74,7 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Act
     authService.updateCacheEntry(
       TEST_TOKEN_ISO14443,
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       futureDate,
       IdentifierType.ISO14443
     )
@@ -82,14 +82,14 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Assert
     const cached = authCache.get(TEST_TOKEN_ISO14443)
     assert.ok(cached != null, 'Cache entry should exist with explicit TTL')
-    assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+    assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
   })
 
   await it('C10.FR.08 - should use AuthCacheLifeTime as TTL when cacheExpiryDateTime absent', () => {
     // Act — no expiryDate, uses config.authorizationCacheLifetime
     authService.updateCacheEntry(
       TEST_TOKEN_ISO14443,
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       undefined,
       IdentifierType.ISO14443
     )
@@ -97,14 +97,14 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Assert
     const cached = authCache.get(TEST_TOKEN_ISO14443)
     assert.ok(cached != null, 'Cache entry should exist with default TTL')
-    assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+    assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
   })
 
   await it('C02.FR.03 - should NOT cache NoAuthorization token type', () => {
     // Act
     authService.updateCacheEntry(
       '',
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       undefined,
       IdentifierType.NO_AUTHORIZATION
     )
@@ -118,7 +118,7 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Act
     authService.updateCacheEntry(
       'CENTRAL_TOKEN_001',
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       undefined,
       IdentifierType.CENTRAL
     )
@@ -132,13 +132,13 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Act
     authService.updateCacheEntry(
       'BLOCKED_TOKEN',
-      AuthorizationStatus.BLOCKED,
+      AuthResultStatus.BLOCKED,
       undefined,
       IdentifierType.ISO14443
     )
     authService.updateCacheEntry(
       'EXPIRED_TOKEN',
-      AuthorizationStatus.EXPIRED,
+      AuthResultStatus.EXPIRED,
       undefined,
       IdentifierType.ISO14443
     )
@@ -146,11 +146,11 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Assert
     const cachedBlocked = authCache.get('BLOCKED_TOKEN')
     assert.ok(cachedBlocked != null, 'Blocked status should be cached')
-    assert.strictEqual(cachedBlocked.status, AuthorizationStatus.BLOCKED)
+    assert.strictEqual(cachedBlocked.status, AuthResultStatus.BLOCKED)
 
     const cachedExpired = authCache.get('EXPIRED_TOKEN')
     assert.ok(cachedExpired != null, 'Expired status should be cached')
-    assert.strictEqual(cachedExpired.status, AuthorizationStatus.EXPIRED)
+    assert.strictEqual(cachedExpired.status, AuthResultStatus.EXPIRED)
   })
 
   await it('should skip caching when expiryDate is in the past', () => {
@@ -160,7 +160,7 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Act
     authService.updateCacheEntry(
       TEST_TOKEN_ISO14443,
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       pastDate,
       IdentifierType.ISO14443
     )
@@ -187,7 +187,7 @@ await describe('C10 - TransactionEventResponse Cache Update', async () => {
     // Act
     disabledService.updateCacheEntry(
       TEST_TOKEN_ISO14443,
-      AuthorizationStatus.ACCEPTED,
+      AuthResultStatus.ACCEPTED,
       undefined,
       IdentifierType.ISO14443
     )
index 4ab7c67a3db0ad9747c2a1e4bb9ed46f9156fdcc..d8c0be5a3badb333033c6e5d8ec3b35fc3304e8d 100644 (file)
@@ -12,7 +12,7 @@ import type { AuthCache } from '../../../../src/charging-station/ocpp/auth/inter
 
 import { OCPP20ServiceUtils } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js'
 import {
-  AuthorizationStatus,
+  AuthResultStatus,
   OCPPAuthServiceFactory,
 } from '../../../../src/charging-station/ocpp/auth/index.js'
 import { OCPPAuthServiceImpl } from '../../../../src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.js'
@@ -74,7 +74,7 @@ await describe('OCPP20ServiceUtils.updateAuthorizationCache', async () => {
     // Assert
     const cached = authCache.get(TEST_TOKEN_ISO14443)
     assert.ok(cached != null, 'AuthorizeResponse should update the cache')
-    assert.strictEqual(cached.status, AuthorizationStatus.ACCEPTED)
+    assert.strictEqual(cached.status, AuthResultStatus.ACCEPTED)
   })
 
   await it('C10.FR.01 - should cache non-Accepted status through utility helper', () => {
@@ -90,7 +90,7 @@ await describe('OCPP20ServiceUtils.updateAuthorizationCache', async () => {
 
     const cached = authCache.get('BLOCKED_TOKEN_001')
     assert.ok(cached != null, 'Blocked status should be cached per C10.FR.01')
-    assert.strictEqual(cached.status, AuthorizationStatus.BLOCKED)
+    assert.strictEqual(cached.status, AuthResultStatus.BLOCKED)
   })
 
   await it('should handle auth service initialization failure gracefully', () => {
diff --git a/tests/charging-station/ocpp/2.0/OCPP20VariableRegistry.test.ts b/tests/charging-station/ocpp/2.0/OCPP20VariableRegistry.test.ts
new file mode 100644 (file)
index 0000000..71605b0
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * @file Tests for OCPP 2.0 VariableMetadata predicates
+ * @description Unit tests for the isPersistent/isVolatile/isReadOnly/isWriteOnly
+ * predicates consumed by OCPP20VariableManager.
+ */
+import assert from 'node:assert/strict'
+import { afterEach, describe, it } from 'node:test'
+
+import {
+  isPersistent,
+  isReadOnly,
+  isVolatile,
+  isWriteOnly,
+  type VariableMetadata,
+} from '../../../../src/charging-station/ocpp/2.0/OCPP20VariableRegistry.js'
+import { MutabilityEnumType, PersistenceEnumType } from '../../../../src/types/index.js'
+import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js'
+
+const buildMetadata = (
+  mutability: MutabilityEnumType,
+  persistence: PersistenceEnumType
+): VariableMetadata => ({ mutability, persistence }) as unknown as VariableMetadata
+
+await describe('OCPP20VariableRegistry metadata predicates', async () => {
+  afterEach(() => {
+    standardCleanup()
+  })
+
+  await it('should detect persistent versus volatile persistence', () => {
+    assert.strictEqual(
+      isPersistent(buildMetadata(MutabilityEnumType.ReadWrite, PersistenceEnumType.Persistent)),
+      true
+    )
+    assert.strictEqual(
+      isPersistent(buildMetadata(MutabilityEnumType.ReadWrite, PersistenceEnumType.Volatile)),
+      false
+    )
+    assert.strictEqual(
+      isVolatile(buildMetadata(MutabilityEnumType.ReadWrite, PersistenceEnumType.Volatile)),
+      true
+    )
+    assert.strictEqual(
+      isVolatile(buildMetadata(MutabilityEnumType.ReadWrite, PersistenceEnumType.Persistent)),
+      false
+    )
+  })
+
+  await it('should detect read-only and write-only mutability', () => {
+    assert.strictEqual(
+      isReadOnly(buildMetadata(MutabilityEnumType.ReadOnly, PersistenceEnumType.Persistent)),
+      true
+    )
+    assert.strictEqual(
+      isReadOnly(buildMetadata(MutabilityEnumType.ReadWrite, PersistenceEnumType.Persistent)),
+      false
+    )
+    assert.strictEqual(
+      isReadOnly(buildMetadata(MutabilityEnumType.WriteOnly, PersistenceEnumType.Persistent)),
+      false
+    )
+    assert.strictEqual(
+      isWriteOnly(buildMetadata(MutabilityEnumType.WriteOnly, PersistenceEnumType.Persistent)),
+      true
+    )
+    assert.strictEqual(
+      isWriteOnly(buildMetadata(MutabilityEnumType.ReadOnly, PersistenceEnumType.Persistent)),
+      false
+    )
+    assert.strictEqual(
+      isWriteOnly(buildMetadata(MutabilityEnumType.ReadWrite, PersistenceEnumType.Persistent)),
+      false
+    )
+  })
+})
index 4f24efcc71484d494682b993ab987b4b9a346895..c62fc6f636a0318dad501ce26eec800db98771f9 100644 (file)
@@ -11,7 +11,7 @@ import { afterEach, describe, it } from 'node:test'
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   OCPPAuthServiceFactory,
 } from '../../../src/charging-station/ocpp/auth/index.js'
 import {
@@ -301,7 +301,7 @@ await describe('OCPPServiceOperations', async () => {
       })
       injectMockAuthService(station, {
         authorize: () =>
-          Promise.resolve(createMockAuthorizationResult({ status: AuthorizationStatus.INVALID })),
+          Promise.resolve(createMockAuthorizationResult({ status: AuthResultStatus.INVALID })),
       })
 
       // Act
@@ -319,7 +319,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.LOCAL_LIST,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -339,7 +339,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.LOCAL_LIST,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -362,7 +362,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.CACHE,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -387,7 +387,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -409,7 +409,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -434,7 +434,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.BLOCKED,
+              status: AuthResultStatus.BLOCKED,
             })
           ),
       })
@@ -454,7 +454,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.LOCAL_LIST,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -476,7 +476,7 @@ await describe('OCPPServiceOperations', async () => {
           Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.OFFLINE_FALLBACK,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           ),
       })
@@ -515,7 +515,7 @@ await describe('OCPPServiceOperations', async () => {
           return Promise.resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.LOCAL_LIST,
-              status: AuthorizationStatus.ACCEPTED,
+              status: AuthResultStatus.ACCEPTED,
             })
           )
         },
index f2a6649610fb337627af68521fd604e44221754c..0bdbf5949ee89692cfc005c25fc1862d8a381475 100644 (file)
@@ -14,7 +14,7 @@ import { LocalAuthStrategy } from '../../../../src/charging-station/ocpp/auth/st
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { OCPPVersion } from '../../../../src/types/index.js'
@@ -82,7 +82,7 @@ await describe('OCPP Authentication', async () => {
       assert.ok(result.timestamp instanceof Date)
       assert.strictEqual(typeof result.isOffline, 'boolean')
       // Status should be one of the valid authorization statuses
-      assert.ok(Object.values(AuthorizationStatus).includes(result.status))
+      assert.ok(Object.values(AuthResultStatus).includes(result.status))
     })
 
     await it('should handle multiple auth contexts', async () => {
@@ -137,7 +137,7 @@ await describe('OCPP Authentication', async () => {
       assert.notStrictEqual(result, undefined)
       assert.ok(result.timestamp instanceof Date)
       assert.strictEqual(typeof result.isOffline, 'boolean')
-      assert.ok(Object.values(AuthorizationStatus).includes(result.status))
+      assert.ok(Object.values(AuthResultStatus).includes(result.status))
     })
 
     await it('should handle all auth contexts', async () => {
@@ -183,7 +183,7 @@ await describe('OCPP Authentication', async () => {
 
       // Should return a result (not throw) with non-ACCEPTED status
       assert.notStrictEqual(result, undefined)
-      assert.notStrictEqual(result.status, AuthorizationStatus.ACCEPTED)
+      assert.notStrictEqual(result.status, AuthResultStatus.ACCEPTED)
     })
   })
 
index 82ac7d53bcb41f60c12409ff73cca090f0ced40d..4f2dda2471893e2faf2408e52cd4bc26cc607e60 100644 (file)
@@ -13,7 +13,7 @@ import {
   type AuthConfiguration,
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { OCPP16AuthorizationStatus, OCPPVersion } from '../../../../../src/types/index.js'
@@ -154,7 +154,7 @@ await describe('OCPP16AuthAdapter', async () => {
 
       const result = await adapter.authorizeRemote(identifier, 1, 123)
 
-      assert.strictEqual(result.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result.status, AuthResultStatus.ACCEPTED)
       assert.notStrictEqual(result.method, undefined)
       assert.strictEqual(result.isOffline, false)
       assert.ok(result.timestamp instanceof Date)
@@ -171,7 +171,7 @@ await describe('OCPP16AuthAdapter', async () => {
 
       const result = await adapter.authorizeRemote(identifier, 1)
 
-      assert.strictEqual(result.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result.status, AuthResultStatus.INVALID)
       assert.notStrictEqual(result.additionalInfo?.error, undefined)
     })
   })
index b190b72ecd43cf19fde78f82747186be89b71efa..7f80781ca6f3016a86a508578df1314966bf848c 100644 (file)
@@ -13,7 +13,7 @@ import {
   type AuthConfiguration,
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import {
@@ -222,7 +222,7 @@ await describe('OCPP20AuthAdapter', async () => {
 
       const result = await adapter.authorizeRemote(identifier, 1, 'tx_123')
 
-      assert.strictEqual(result.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
       assert.strictEqual(result.isOffline, false)
       assert.ok(result.timestamp instanceof Date)
@@ -233,7 +233,7 @@ await describe('OCPP20AuthAdapter', async () => {
 
       const result = await adapter.authorizeRemote(identifier, 1)
 
-      assert.strictEqual(result.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result.status, AuthResultStatus.INVALID)
       assert.notStrictEqual(result.additionalInfo?.error, undefined)
     })
   })
@@ -344,9 +344,9 @@ await describe('OCPP20AuthAdapter', async () => {
 
     await it('should convert rejection statuses to OCPP 2.0 Rejected', () => {
       const statuses = [
-        AuthorizationStatus.BLOCKED,
-        AuthorizationStatus.INVALID,
-        AuthorizationStatus.EXPIRED,
+        AuthResultStatus.BLOCKED,
+        AuthResultStatus.INVALID,
+        AuthResultStatus.EXPIRED,
       ]
 
       for (const status of statuses) {
index 4b4b7cba30f9febc892c6319d43c1916c6ee661e..7e81210542643708bfeaabcd88a3768ddb7b7042 100644 (file)
@@ -10,7 +10,7 @@ import type { AuthorizationResult } from '../../../../../src/charging-station/oc
 import { InMemoryAuthCache } from '../../../../../src/charging-station/ocpp/auth/cache/InMemoryAuthCache.js'
 import {
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { standardCleanup, withMockTimers } from '../../../../helpers/TestLifecycleHelpers.js'
 import { createMockAuthorizationResult } from '../helpers/MockFactories.js'
@@ -50,7 +50,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
 
     beforeEach(() => {
       mockResult = createMockAuthorizationResult({
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
       })
     })
 
@@ -64,7 +64,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
       const cachedResult = cache.get(identifier)
 
       assert.notStrictEqual(cachedResult, undefined)
-      assert.strictEqual(cachedResult?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(cachedResult?.status, AuthResultStatus.ACCEPTED)
       assert.deepStrictEqual(cachedResult.timestamp, mockResult.timestamp)
     })
 
@@ -175,7 +175,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
         const result = cache.get(identifier)
 
         assert.notStrictEqual(result, undefined)
-        assert.strictEqual(result?.status, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(result?.status, AuthResultStatus.EXPIRED)
       })
     })
 
@@ -209,7 +209,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
 
         const result = cacheWithShortTTL.get('token')
         assert.notStrictEqual(result, undefined)
-        assert.strictEqual(result?.status, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(result?.status, AuthResultStatus.EXPIRED)
       })
     })
 
@@ -507,7 +507,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
 
       const result = cache.get('token')
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.EXPIRED)
+      assert.strictEqual(result?.status, AuthResultStatus.EXPIRED)
     })
 
     await it('should handle very large TTL values', () => {
@@ -523,25 +523,25 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
     await it('should cache ACCEPTED authorization results', () => {
       const mockResult = createMockAuthorizationResult({
         method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
       })
 
       cache.set('valid-token', mockResult)
       const result = cache.get('valid-token')
 
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
     })
 
     await it('should handle BLOCKED authorization results', () => {
       const mockResult = createMockAuthorizationResult({
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
       })
 
       cache.set('blocked-token', mockResult)
       const result = cache.get('blocked-token')
 
-      assert.strictEqual(result?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(result?.status, AuthResultStatus.BLOCKED)
     })
 
     await it('should preserve authorization result metadata', () => {
@@ -550,7 +550,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
           customField: 'test-value',
           reason: 'test-reason',
         },
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
       })
 
       cache.set('token', mockResult)
@@ -570,7 +570,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
       const mockResult = createMockAuthorizationResult({
         isOffline: true,
         method: AuthenticationMethod.OFFLINE_FALLBACK,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
       })
 
       cache.set('offline-token', mockResult)
@@ -592,8 +592,8 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
         rateLimit: { enabled: false },
       })
 
-      const accepted = createMockAuthorizationResult({ status: AuthorizationStatus.ACCEPTED })
-      const blocked = createMockAuthorizationResult({ status: AuthorizationStatus.BLOCKED })
+      const accepted = createMockAuthorizationResult({ status: AuthResultStatus.ACCEPTED })
+      const blocked = createMockAuthorizationResult({ status: AuthResultStatus.BLOCKED })
 
       lruCache.set('valid-token', accepted)
       lruCache.set('blocked-token', blocked)
@@ -609,7 +609,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
       const newResult = lruCache.get('new-token')
 
       assert.notStrictEqual(validResult, undefined)
-      assert.strictEqual(validResult?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(validResult?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(blockedResult, undefined)
       assert.notStrictEqual(newResult, undefined)
     })
@@ -621,7 +621,7 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
         rateLimit: { enabled: false },
       })
 
-      const accepted = createMockAuthorizationResult({ status: AuthorizationStatus.ACCEPTED })
+      const accepted = createMockAuthorizationResult({ status: AuthResultStatus.ACCEPTED })
 
       lruCache.set('token-a', accepted)
       lruCache.set('token-b', accepted)
@@ -651,18 +651,18 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
           rateLimit: { enabled: false },
         })
 
-        const accepted = createMockAuthorizationResult({ status: AuthorizationStatus.ACCEPTED })
+        const accepted = createMockAuthorizationResult({ status: AuthResultStatus.ACCEPTED })
         shortCache.set('token', accepted)
 
         t.mock.timers.tick(50)
         const midResult = shortCache.get('token')
         assert.notStrictEqual(midResult, undefined)
-        assert.strictEqual(midResult?.status, AuthorizationStatus.ACCEPTED)
+        assert.strictEqual(midResult?.status, AuthResultStatus.ACCEPTED)
 
         t.mock.timers.tick(50)
         const lateResult = shortCache.get('token')
         assert.notStrictEqual(lateResult, undefined)
-        assert.strictEqual(lateResult?.status, AuthorizationStatus.ACCEPTED)
+        assert.strictEqual(lateResult?.status, AuthResultStatus.ACCEPTED)
       })
     })
 
@@ -674,13 +674,13 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
           rateLimit: { enabled: false },
         })
 
-        const accepted = createMockAuthorizationResult({ status: AuthorizationStatus.ACCEPTED })
+        const accepted = createMockAuthorizationResult({ status: AuthResultStatus.ACCEPTED })
         shortCache.set('token', accepted)
 
         t.mock.timers.tick(200)
         const result = shortCache.get('token')
         assert.notStrictEqual(result, undefined)
-        assert.strictEqual(result?.status, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(result?.status, AuthResultStatus.EXPIRED)
       })
     })
   })
@@ -694,14 +694,14 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
           rateLimit: { enabled: false },
         })
 
-        const accepted = createMockAuthorizationResult({ status: AuthorizationStatus.ACCEPTED })
+        const accepted = createMockAuthorizationResult({ status: AuthResultStatus.ACCEPTED })
         shortCache.set('token', accepted)
 
         t.mock.timers.tick(10)
 
         const result = shortCache.get('token')
         assert.notStrictEqual(result, undefined)
-        assert.strictEqual(result?.status, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(result?.status, AuthResultStatus.EXPIRED)
       })
     })
 
@@ -713,19 +713,19 @@ await describe('InMemoryAuthCache - OCPP 2.0.1 Authorization Cache Conformance',
           rateLimit: { enabled: false },
         })
 
-        const accepted = createMockAuthorizationResult({ status: AuthorizationStatus.ACCEPTED })
+        const accepted = createMockAuthorizationResult({ status: AuthResultStatus.ACCEPTED })
         shortCache.set('token', accepted)
 
         t.mock.timers.tick(10)
 
         // First access transitions to EXPIRED
         const first = shortCache.get('token')
-        assert.strictEqual(first?.status, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(first?.status, AuthResultStatus.EXPIRED)
 
         // Second access should still return the entry (now with refreshed TTL as EXPIRED)
         const second = shortCache.get('token')
         assert.notStrictEqual(second, undefined)
-        assert.strictEqual(second?.status, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(second?.status, AuthResultStatus.EXPIRED)
 
         const stats = shortCache.getStats()
         assert.strictEqual(stats.totalEntries, 1)
index cf5aeb0589ca1a494754844bf96de5f778ad7b2e..2f5381aa26ce74b9d39654534580414e6ed5e6e8 100644 (file)
@@ -20,8 +20,8 @@ import {
   AuthContext,
   AuthenticationMethod,
   type AuthorizationResult,
-  AuthorizationStatus,
   type AuthRequest,
+  AuthResultStatus,
   type Identifier,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
@@ -68,7 +68,7 @@ export const createMockAuthRequest = (overrides?: Partial<AuthRequest>): AuthReq
 /**
  * Create a mock AuthorizationResult with configurable properties.
  *
- * Supports all AuthorizationStatus values: ACCEPTED, INVALID, BLOCKED, EXPIRED, CONCURRENT_TX.
+ * Supports all AuthResultStatus values: ACCEPTED, INVALID, BLOCKED, EXPIRED, CONCURRENT_TX.
  * @param overrides - Partial AuthorizationResult properties to override defaults
  * @returns Mock AuthorizationResult with specified properties (defaults to ACCEPTED from local list)
  * @example
@@ -77,17 +77,17 @@ export const createMockAuthRequest = (overrides?: Partial<AuthRequest>): AuthReq
  * const accepted = createMockAuthorizationResult()
  *
  * // Rejected with INVALID status
- * const rejected = createMockAuthorizationResult({ status: AuthorizationStatus.INVALID })
+ * const rejected = createMockAuthorizationResult({ status: AuthResultStatus.INVALID })
  *
  * // Blocked with custom method
  * const blocked = createMockAuthorizationResult({
- *   status: AuthorizationStatus.BLOCKED,
+ *   status: AuthResultStatus.BLOCKED,
  *   method: AuthenticationMethod.REMOTE_AUTHORIZATION
  * })
  *
  * // Expired with custom expiry date
  * const expired = createMockAuthorizationResult({
- *   status: AuthorizationStatus.EXPIRED,
+ *   status: AuthResultStatus.EXPIRED,
  *   expiryDate: new Date(Date.now() - 1000)
  * })
  * ```
@@ -95,14 +95,14 @@ export const createMockAuthRequest = (overrides?: Partial<AuthRequest>): AuthReq
 export const createMockAuthorizationResult = (
   overrides?: Partial<AuthorizationResult>
 ): AuthorizationResult => {
-  const status = overrides?.status ?? AuthorizationStatus.ACCEPTED
+  const status = overrides?.status ?? AuthResultStatus.ACCEPTED
   return {
     isOffline: false,
     method: AuthenticationMethod.LOCAL_LIST,
     status,
     timestamp: new Date(),
     // For expired status, include a default expiryDate in the past
-    ...(status === AuthorizationStatus.EXPIRED && { expiryDate: new Date(Date.now() - 1000) }),
+    ...(status === AuthResultStatus.EXPIRED && { expiryDate: new Date(Date.now() - 1000) }),
     ...overrides,
   }
 }
@@ -234,7 +234,7 @@ export const expectAcceptedAuthorization = (
   result: AuthorizationResult,
   expectedMethod?: AuthenticationMethod
 ): void => {
-  assert.strictEqual(result.status, AuthorizationStatus.ACCEPTED)
+  assert.strictEqual(result.status, AuthResultStatus.ACCEPTED)
   assert.ok(result.timestamp instanceof Date)
   if (expectedMethod !== undefined) {
     assert.strictEqual(result.method, expectedMethod)
@@ -248,10 +248,10 @@ export const expectAcceptedAuthorization = (
  */
 export const expectRejectedAuthorization = (
   result: AuthorizationResult,
-  expectedStatus: AuthorizationStatus = AuthorizationStatus.INVALID
+  expectedStatus: AuthResultStatus = AuthResultStatus.INVALID
 ): void => {
   assert.strictEqual(result.status, expectedStatus)
-  assert.notStrictEqual(result.status, AuthorizationStatus.ACCEPTED)
+  assert.notStrictEqual(result.status, AuthResultStatus.ACCEPTED)
   assert.ok(result.timestamp instanceof Date)
 }
 
index 554c36e4be8c4a9ad02cecdd6cc664617288cecc..7f139b9b935112d36b04f32440fa65ef91b8ebb8 100644 (file)
@@ -12,7 +12,7 @@ import { OCPPAuthServiceImpl } from '../../../../../src/charging-station/ocpp/au
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   type Identifier,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
@@ -238,7 +238,7 @@ await describe('OCPPAuthServiceImpl', async () => {
         timestamp: new Date(),
       })
 
-      assert.strictEqual(result.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result.status, AuthResultStatus.INVALID)
       assert.strictEqual(result.method, AuthenticationMethod.NONE)
     })
   })
@@ -336,7 +336,7 @@ await describe('OCPPAuthServiceImpl', async () => {
         timestamp: new Date(),
       })
 
-      assert.strictEqual(result.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result.status, AuthResultStatus.INVALID)
     })
   })
 
index 5fe4c621391d59ae9cba755c2cbcd548b4848270..011fc1917edb6fd920ec034e3640880f1db1d8f9 100644 (file)
@@ -12,7 +12,7 @@ import { CertificateAuthStrategy } from '../../../../../src/charging-station/ocp
 import {
   AuthenticationMethod,
   type AuthorizationResult,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { OCPPVersion } from '../../../../../src/types/index.js'
@@ -191,7 +191,7 @@ await describe('CertificateAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.CERTIFICATE_BASED)
     })
 
@@ -213,7 +213,7 @@ await describe('CertificateAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(result?.status, AuthResultStatus.BLOCKED)
     })
 
     await it('should reject revoked certificates', async () => {
@@ -234,7 +234,7 @@ await describe('CertificateAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(result?.status, AuthResultStatus.BLOCKED)
     })
 
     await it('should handle missing certificate data', async () => {
@@ -249,7 +249,7 @@ await describe('CertificateAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result?.status, AuthResultStatus.INVALID)
     })
 
     await it('should handle invalid hash algorithm', async () => {
@@ -270,7 +270,7 @@ await describe('CertificateAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result?.status, AuthResultStatus.INVALID)
     })
 
     await it('should handle invalid hash format', async () => {
@@ -291,7 +291,7 @@ await describe('CertificateAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(result?.status, AuthResultStatus.INVALID)
     })
   })
 
index 4bf4134ca46752ad6523b37a16657f9f1a5de8fc..be39959ad2c9a9d1458103c95cc3d84a0837b593 100644 (file)
@@ -8,7 +8,7 @@ import { afterEach, describe, it } from 'node:test'
 import { LocalAuthStrategy } from '../../../../../src/charging-station/ocpp/auth/strategies/LocalAuthStrategy.js'
 import {
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { standardCleanup } from '../../../../helpers/TestLifecycleHelpers.js'
@@ -33,7 +33,7 @@ await describe('LocalAuthStrategy - DisablePostAuthorize', async () => {
       // Arrange
       const blockedResult = createMockAuthorizationResult({
         method: AuthenticationMethod.CACHE,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
       })
       const mockAuthCache = createMockAuthCache({
         get: () => blockedResult,
@@ -53,7 +53,7 @@ await describe('LocalAuthStrategy - DisablePostAuthorize', async () => {
 
       // Assert
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(result?.status, AuthResultStatus.BLOCKED)
       assert.strictEqual(result.method, AuthenticationMethod.CACHE)
     })
 
@@ -61,7 +61,7 @@ await describe('LocalAuthStrategy - DisablePostAuthorize', async () => {
       // Arrange
       const blockedResult = createMockAuthorizationResult({
         method: AuthenticationMethod.CACHE,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
       })
       const mockAuthCache = createMockAuthCache({
         get: () => blockedResult,
@@ -105,7 +105,7 @@ await describe('LocalAuthStrategy - DisablePostAuthorize', async () => {
       const result = strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(result?.status, AuthResultStatus.BLOCKED)
       assert.strictEqual(result.method, AuthenticationMethod.LOCAL_LIST)
     })
   })
@@ -115,7 +115,7 @@ await describe('LocalAuthStrategy - DisablePostAuthorize', async () => {
       // Arrange
       const blockedResult = createMockAuthorizationResult({
         method: AuthenticationMethod.CACHE,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
       })
       const mockAuthCache = createMockAuthCache({
         get: () => blockedResult,
index 5d85ff4f0ce2abc40e851ce4c9a1f1ab2c1172db..0fe78be91918e1d9af170ebbf4db3deef78cedb0 100644 (file)
@@ -14,7 +14,7 @@ import { LocalAuthStrategy } from '../../../../../src/charging-station/ocpp/auth
 import {
   AuthContext,
   AuthenticationMethod,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { standardCleanup } from '../../../../helpers/TestLifecycleHelpers.js'
@@ -121,7 +121,7 @@ await describe('LocalAuthStrategy', async () => {
       const result = strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.LOCAL_LIST)
     })
 
@@ -141,7 +141,7 @@ await describe('LocalAuthStrategy', async () => {
       const result = strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.CACHE)
     })
 
@@ -156,7 +156,7 @@ await describe('LocalAuthStrategy', async () => {
       const result = strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.OFFLINE_FALLBACK)
       assert.strictEqual(result.isOffline, true)
     })
index 6f6520b44406d48f1c8b0c69b110bee6eff928aa..5c09d90ce6906ee7ded339b98ed829dadfa86ea1 100644 (file)
@@ -15,7 +15,7 @@ import { RemoteAuthStrategy } from '../../../../../src/charging-station/ocpp/aut
 import {
   AuthenticationMethod,
   type AuthorizationResult,
-  AuthorizationStatus,
+  AuthResultStatus,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { OCPPVersion } from '../../../../../src/types/index.js'
@@ -123,7 +123,7 @@ await describe('RemoteAuthStrategy', async () => {
       const result = await strategy.authenticate(request, config)
 
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(result.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
     })
 
@@ -147,7 +147,7 @@ await describe('RemoteAuthStrategy', async () => {
 
       await strategy.authenticate(request, config)
       assert.strictEqual(cachedKey, 'CACHE_TAG')
-      assert.strictEqual(cachedValue?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(cachedValue?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(cachedTtl, 300)
     })
 
@@ -165,7 +165,7 @@ await describe('RemoteAuthStrategy', async () => {
           resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.BLOCKED,
+              status: AuthResultStatus.BLOCKED,
             })
           )
         })
@@ -180,7 +180,7 @@ await describe('RemoteAuthStrategy', async () => {
 
       await strategy.authenticate(request, config)
       assert.strictEqual(cachedKey, 'BLOCKED_TAG')
-      assert.strictEqual(cachedValue?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(cachedValue?.status, AuthResultStatus.BLOCKED)
       assert.strictEqual(cachedTtl, 300)
     })
 
@@ -198,7 +198,7 @@ await describe('RemoteAuthStrategy', async () => {
           resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.EXPIRED,
+              status: AuthResultStatus.EXPIRED,
             })
           )
         })
@@ -213,7 +213,7 @@ await describe('RemoteAuthStrategy', async () => {
 
       await strategy.authenticate(request, config)
       assert.strictEqual(cachedKey, 'EXPIRED_TAG')
-      assert.strictEqual(cachedValue?.status, AuthorizationStatus.EXPIRED)
+      assert.strictEqual(cachedValue?.status, AuthResultStatus.EXPIRED)
       assert.strictEqual(cachedTtl, 300)
     })
 
@@ -231,7 +231,7 @@ await describe('RemoteAuthStrategy', async () => {
           resolve(
             createMockAuthorizationResult({
               method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-              status: AuthorizationStatus.INVALID,
+              status: AuthResultStatus.INVALID,
             })
           )
         })
@@ -246,7 +246,7 @@ await describe('RemoteAuthStrategy', async () => {
 
       await strategy.authenticate(request, config)
       assert.strictEqual(cachedKey, TEST_ID_TAG_INVALID)
-      assert.strictEqual(cachedValue?.status, AuthorizationStatus.INVALID)
+      assert.strictEqual(cachedValue?.status, AuthResultStatus.INVALID)
       assert.strictEqual(cachedTtl, 300)
     })
 
@@ -270,7 +270,7 @@ await describe('RemoteAuthStrategy', async () => {
 
       await strategy.authenticate(request, config)
       assert.strictEqual(cachedKey, 'ACCEPTED_TAG')
-      assert.strictEqual(cachedValue?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(cachedValue?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(cachedTtl, 300)
     })
 
@@ -331,7 +331,7 @@ await describe('RemoteAuthStrategy', async () => {
 
       const result = await strategy.authenticate(request, config)
       assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(result?.status, AuthResultStatus.ACCEPTED)
     })
 
     await it('C13.FR.01.T01 - should not cache identifier that is in local auth list', async () => {
index 5564dc15dad107fed42e4d60a765cc4f97eea41a..22dc29ba79eb10b613e5e72a1de4df3d74d4cc24 100644 (file)
@@ -9,7 +9,7 @@ import {
   AuthContext,
   AuthenticationError,
   AuthErrorCode,
-  AuthorizationStatus,
+  AuthResultStatus,
   type Identifier,
   IdentifierType,
   isCertificateBased,
@@ -68,27 +68,27 @@ await describe('AuthTypes', async () => {
     await describe('OCPP 1.6 Status Mapping', async () => {
       await it('should map OCPP 1.6 ACCEPTED to ACCEPTED', () => {
         const result = mapOCPP16Status(OCPP16AuthorizationStatus.ACCEPTED)
-        assert.strictEqual(result, AuthorizationStatus.ACCEPTED)
+        assert.strictEqual(result, AuthResultStatus.ACCEPTED)
       })
 
       await it('should map OCPP 1.6 BLOCKED to BLOCKED', () => {
         const result = mapOCPP16Status(OCPP16AuthorizationStatus.BLOCKED)
-        assert.strictEqual(result, AuthorizationStatus.BLOCKED)
+        assert.strictEqual(result, AuthResultStatus.BLOCKED)
       })
 
       await it('should map OCPP 1.6 EXPIRED to EXPIRED', () => {
         const result = mapOCPP16Status(OCPP16AuthorizationStatus.EXPIRED)
-        assert.strictEqual(result, AuthorizationStatus.EXPIRED)
+        assert.strictEqual(result, AuthResultStatus.EXPIRED)
       })
 
       await it('should map OCPP 1.6 INVALID to INVALID', () => {
         const result = mapOCPP16Status(OCPP16AuthorizationStatus.INVALID)
-        assert.strictEqual(result, AuthorizationStatus.INVALID)
+        assert.strictEqual(result, AuthResultStatus.INVALID)
       })
 
       await it('should map OCPP 1.6 CONCURRENT_TX to CONCURRENT_TX', () => {
         const result = mapOCPP16Status(OCPP16AuthorizationStatus.CONCURRENT_TX)
-        assert.strictEqual(result, AuthorizationStatus.CONCURRENT_TX)
+        assert.strictEqual(result, AuthResultStatus.CONCURRENT_TX)
       })
     })
 
@@ -121,31 +121,31 @@ await describe('AuthTypes', async () => {
 
     await describe('Auth to OCPP 1.6 Status Mapping', async () => {
       await it('should map ACCEPTED to OCPP 1.6 ACCEPTED', () => {
-        const result = mapToOCPP16Status(AuthorizationStatus.ACCEPTED)
+        const result = mapToOCPP16Status(AuthResultStatus.ACCEPTED)
         assert.strictEqual(result, OCPP16AuthorizationStatus.ACCEPTED)
       })
 
       await it('should map BLOCKED to OCPP 1.6 BLOCKED', () => {
-        const result = mapToOCPP16Status(AuthorizationStatus.BLOCKED)
+        const result = mapToOCPP16Status(AuthResultStatus.BLOCKED)
         assert.strictEqual(result, OCPP16AuthorizationStatus.BLOCKED)
       })
 
       await it('should map EXPIRED to OCPP 1.6 EXPIRED', () => {
-        const result = mapToOCPP16Status(AuthorizationStatus.EXPIRED)
+        const result = mapToOCPP16Status(AuthResultStatus.EXPIRED)
         assert.strictEqual(result, OCPP16AuthorizationStatus.EXPIRED)
       })
 
       await it('should map unsupported statuses to OCPP 1.6 INVALID', () => {
         assert.strictEqual(
-          mapToOCPP16Status(AuthorizationStatus.PENDING),
+          mapToOCPP16Status(AuthResultStatus.PENDING),
           OCPP16AuthorizationStatus.INVALID
         )
         assert.strictEqual(
-          mapToOCPP16Status(AuthorizationStatus.UNKNOWN),
+          mapToOCPP16Status(AuthResultStatus.UNKNOWN),
           OCPP16AuthorizationStatus.INVALID
         )
         assert.strictEqual(
-          mapToOCPP16Status(AuthorizationStatus.NOT_AT_THIS_LOCATION),
+          mapToOCPP16Status(AuthResultStatus.NOT_AT_THIS_LOCATION),
           OCPP16AuthorizationStatus.INVALID
         )
       })
@@ -153,21 +153,21 @@ await describe('AuthTypes', async () => {
 
     await describe('Auth to OCPP 2.0 Status Mapping', async () => {
       await it('should map ACCEPTED to OCPP 2.0 Accepted', () => {
-        const result = mapToOCPP20Status(AuthorizationStatus.ACCEPTED)
+        const result = mapToOCPP20Status(AuthResultStatus.ACCEPTED)
         assert.strictEqual(result, RequestStartStopStatusEnumType.Accepted)
       })
 
       await it('should map rejection statuses to OCPP 2.0 Rejected', () => {
         assert.strictEqual(
-          mapToOCPP20Status(AuthorizationStatus.BLOCKED),
+          mapToOCPP20Status(AuthResultStatus.BLOCKED),
           RequestStartStopStatusEnumType.Rejected
         )
         assert.strictEqual(
-          mapToOCPP20Status(AuthorizationStatus.INVALID),
+          mapToOCPP20Status(AuthResultStatus.INVALID),
           RequestStartStopStatusEnumType.Rejected
         )
         assert.strictEqual(
-          mapToOCPP20Status(AuthorizationStatus.EXPIRED),
+          mapToOCPP20Status(AuthResultStatus.EXPIRED),
           RequestStartStopStatusEnumType.Rejected
         )
       })
index fe2e625a53b8d5d9d8ca0f66d087b1387268ed6b..b48ac649fae1bb1d3d265084ff157c155d4f48ed 100644 (file)
@@ -9,7 +9,7 @@ import { afterEach, describe, it } from 'node:test'
 import {
   type AuthConfiguration,
   AuthenticationError,
-  AuthorizationStatus,
+  AuthResultStatus,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
 import { AuthConfigValidator } from '../../../../../src/charging-station/ocpp/auth/utils/AuthConfigValidator.js'
 import { standardCleanup } from '../../../../helpers/TestLifecycleHelpers.js'
@@ -32,7 +32,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.doesNotThrow(() => {
@@ -53,7 +53,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -74,7 +74,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -95,7 +95,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -116,7 +116,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: -1,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -137,7 +137,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 0,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -158,7 +158,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000.5,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -179,7 +179,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -200,7 +200,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -221,7 +221,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.throws(() => {
@@ -242,7 +242,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.doesNotThrow(() => {
@@ -263,7 +263,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 1,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.doesNotThrow(() => {
@@ -284,7 +284,7 @@ await describe('AuthConfigValidator', async () => {
         localPreAuthorize: false,
         maxCacheEntries: 10000,
         offlineAuthorizationEnabled: true,
-        unknownIdAuthorization: AuthorizationStatus.INVALID,
+        unknownIdAuthorization: AuthResultStatus.INVALID,
       }
 
       assert.doesNotThrow(() => {
index e3c6091b2fe94ec06f6ea84c172d9fbe5f44b4f5..a3441420a906cbaa56e726886e85ee050f671b66 100644 (file)
@@ -9,7 +9,7 @@ import {
   AuthContext,
   AuthenticationMethod,
   type AuthorizationResult,
-  AuthorizationStatus,
+  AuthResultStatus,
   type Identifier,
   IdentifierType,
 } from '../../../../../src/charging-station/ocpp/auth/types/AuthTypes.js'
@@ -98,11 +98,11 @@ await describe('AuthHelpers', async () => {
   await describe('createRejectedResult', async () => {
     await it('should create rejected result without reason', () => {
       const result = AuthHelpers.createRejectedResult(
-        AuthorizationStatus.BLOCKED,
+        AuthResultStatus.BLOCKED,
         AuthenticationMethod.LOCAL_LIST
       )
 
-      assert.strictEqual(result.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(result.status, AuthResultStatus.BLOCKED)
       assert.strictEqual(result.method, AuthenticationMethod.LOCAL_LIST)
       assert.strictEqual(result.isOffline, false)
       assert.ok(result.timestamp instanceof Date)
@@ -111,12 +111,12 @@ await describe('AuthHelpers', async () => {
 
     await it('should create rejected result with reason', () => {
       const result = AuthHelpers.createRejectedResult(
-        AuthorizationStatus.EXPIRED,
+        AuthResultStatus.EXPIRED,
         AuthenticationMethod.REMOTE_AUTHORIZATION,
         'Token expired on 2024-01-01'
       )
 
-      assert.strictEqual(result.status, AuthorizationStatus.EXPIRED)
+      assert.strictEqual(result.status, AuthResultStatus.EXPIRED)
       assert.strictEqual(result.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
       assert.deepStrictEqual(result.additionalInfo, { reason: 'Token expired on 2024-01-01' })
     })
@@ -156,70 +156,70 @@ await describe('AuthHelpers', async () => {
   await describe('getStatusMessage', async () => {
     await it('should return message for ACCEPTED status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.ACCEPTED),
+        AuthHelpers.getStatusMessage(AuthResultStatus.ACCEPTED),
         'Authorization accepted'
       )
     })
 
     await it('should return message for BLOCKED status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.BLOCKED),
+        AuthHelpers.getStatusMessage(AuthResultStatus.BLOCKED),
         'Identifier is blocked'
       )
     })
 
     await it('should return message for EXPIRED status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.EXPIRED),
+        AuthHelpers.getStatusMessage(AuthResultStatus.EXPIRED),
         'Authorization has expired'
       )
     })
 
     await it('should return message for INVALID status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.INVALID),
+        AuthHelpers.getStatusMessage(AuthResultStatus.INVALID),
         'Invalid identifier'
       )
     })
 
     await it('should return message for CONCURRENT_TX status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.CONCURRENT_TX),
+        AuthHelpers.getStatusMessage(AuthResultStatus.CONCURRENT_TX),
         'Concurrent transaction in progress'
       )
     })
 
     await it('should return message for NOT_AT_THIS_LOCATION status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.NOT_AT_THIS_LOCATION),
+        AuthHelpers.getStatusMessage(AuthResultStatus.NOT_AT_THIS_LOCATION),
         'Not authorized at this location'
       )
     })
 
     await it('should return message for NOT_AT_THIS_TIME status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.NOT_AT_THIS_TIME),
+        AuthHelpers.getStatusMessage(AuthResultStatus.NOT_AT_THIS_TIME),
         'Not authorized at this time'
       )
     })
 
     await it('should return message for PENDING status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.PENDING),
+        AuthHelpers.getStatusMessage(AuthResultStatus.PENDING),
         'Authorization pending'
       )
     })
 
     await it('should return message for UNKNOWN status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.UNKNOWN),
+        AuthHelpers.getStatusMessage(AuthResultStatus.UNKNOWN),
         'Unknown authorization status'
       )
     })
 
     await it('should return generic message for unknown status', () => {
       assert.strictEqual(
-        AuthHelpers.getStatusMessage(AuthorizationStatus.NO_CREDIT),
+        AuthHelpers.getStatusMessage(AuthResultStatus.NO_CREDIT),
         'Authorization failed'
       )
     })
@@ -230,7 +230,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
         timestamp: new Date(),
       }
 
@@ -241,7 +241,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.EXPIRED,
+        status: AuthResultStatus.EXPIRED,
         timestamp: new Date(),
       }
 
@@ -252,7 +252,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.INVALID,
+        status: AuthResultStatus.INVALID,
         timestamp: new Date(),
       }
 
@@ -263,7 +263,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date(),
       }
 
@@ -274,7 +274,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.PENDING,
+        status: AuthResultStatus.PENDING,
         timestamp: new Date(),
       }
 
@@ -287,7 +287,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
         timestamp: new Date(),
       }
 
@@ -298,7 +298,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date(),
       }
 
@@ -310,7 +310,7 @@ await describe('AuthHelpers', async () => {
         expiryDate: new Date(Date.now() - 1000),
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date(),
       }
 
@@ -322,7 +322,7 @@ await describe('AuthHelpers', async () => {
         expiryDate: new Date(Date.now() + 10000),
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date(),
       }
 
@@ -335,7 +335,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.PENDING,
+        status: AuthResultStatus.PENDING,
         timestamp: new Date(),
       }
 
@@ -346,7 +346,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.UNKNOWN,
+        status: AuthResultStatus.UNKNOWN,
         timestamp: new Date(),
       }
 
@@ -357,7 +357,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
         timestamp: new Date(),
       }
 
@@ -368,7 +368,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date(),
       }
 
@@ -387,25 +387,25 @@ await describe('AuthHelpers', async () => {
         {
           isOffline: false,
           method: AuthenticationMethod.LOCAL_LIST,
-          status: AuthorizationStatus.BLOCKED,
+          status: AuthResultStatus.BLOCKED,
           timestamp: new Date(),
         },
         {
           isOffline: false,
           method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-          status: AuthorizationStatus.ACCEPTED,
+          status: AuthResultStatus.ACCEPTED,
           timestamp: new Date(),
         },
         {
           isOffline: false,
           method: AuthenticationMethod.CERTIFICATE_BASED,
-          status: AuthorizationStatus.ACCEPTED,
+          status: AuthResultStatus.ACCEPTED,
           timestamp: new Date(),
         },
       ]
 
       const merged = AuthHelpers.mergeAuthResults(results)
-      assert.strictEqual(merged?.status, AuthorizationStatus.ACCEPTED)
+      assert.strictEqual(merged?.status, AuthResultStatus.ACCEPTED)
       assert.strictEqual(merged.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
     })
 
@@ -414,19 +414,19 @@ await describe('AuthHelpers', async () => {
         {
           isOffline: false,
           method: AuthenticationMethod.LOCAL_LIST,
-          status: AuthorizationStatus.BLOCKED,
+          status: AuthResultStatus.BLOCKED,
           timestamp: new Date(),
         },
         {
           isOffline: true,
           method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-          status: AuthorizationStatus.EXPIRED,
+          status: AuthResultStatus.EXPIRED,
           timestamp: new Date(),
         },
       ]
 
       const merged = AuthHelpers.mergeAuthResults(results)
-      assert.strictEqual(merged?.status, AuthorizationStatus.BLOCKED)
+      assert.strictEqual(merged?.status, AuthResultStatus.BLOCKED)
       assert.strictEqual(merged.method, AuthenticationMethod.LOCAL_LIST)
       assert.strictEqual(merged.isOffline, true)
       assert.deepStrictEqual(merged.additionalInfo, {
@@ -447,7 +447,7 @@ await describe('AuthHelpers', async () => {
           content: 'Welcome',
           format: OCPP20MessageFormatEnumType.ASCII,
         },
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: new Date('2024-01-01T00:00:00Z'),
       }
 
@@ -459,7 +459,7 @@ await describe('AuthHelpers', async () => {
         hasPersonalMessage: true,
         isOffline: false,
         method: AuthenticationMethod.LOCAL_LIST,
-        status: AuthorizationStatus.ACCEPTED,
+        status: AuthResultStatus.ACCEPTED,
         timestamp: '2024-01-01T00:00:00.000Z',
       })
     })
@@ -468,7 +468,7 @@ await describe('AuthHelpers', async () => {
       const result: AuthorizationResult = {
         isOffline: true,
         method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
         timestamp: new Date('2024-06-15T12:30:45Z'),
       }
 
@@ -480,7 +480,7 @@ await describe('AuthHelpers', async () => {
         hasPersonalMessage: false,
         isOffline: true,
         method: AuthenticationMethod.REMOTE_AUTHORIZATION,
-        status: AuthorizationStatus.BLOCKED,
+        status: AuthResultStatus.BLOCKED,
         timestamp: '2024-06-15T12:30:45.000Z',
       })
     })
index d92d3910fdbbe8bf6fee672bf85861a7ed1187af..83f195c46c5a661c2ddbbb5258a4922339854816 100644 (file)
@@ -14,7 +14,7 @@ import { satisfies } from 'semver'
 import type { TimestampedData } from '../../src/types/index.js'
 
 import { JSRuntime, runtime } from '../../scripts/runtime.js'
-import { MapStringifyFormat, MessageType } from '../../src/types/index.js'
+import { MapStringifyFormat, MessageType, OCPPVersion } from '../../src/types/index.js'
 import { Constants } from '../../src/utils/index.js'
 import {
   clampToSafeTimerValue,
@@ -42,6 +42,7 @@ import {
   isEmpty,
   isNotEmptyArray,
   isNotEmptyString,
+  isOCPP20x,
   isValidDate,
   JSONStringify,
   logPrefix,
@@ -469,6 +470,13 @@ await describe('Utils', async () => {
     assert.strictEqual(isEmpty(new WeakSet()), false)
   })
 
+  await it('should detect OCPP 2.0.x versions', () => {
+    assert.strictEqual(isOCPP20x(OCPPVersion.VERSION_20), true)
+    assert.strictEqual(isOCPP20x(OCPPVersion.VERSION_201), true)
+    assert.strictEqual(isOCPP20x(OCPPVersion.VERSION_16), false)
+    assert.strictEqual(isOCPP20x(undefined), false)
+  })
+
   await it('should detect non-empty strings correctly', () => {
     assert.strictEqual(isNotEmptyString(''), false)
     assert.strictEqual(isNotEmptyString(' '), false)
index 1109c48f6a10d0049a6c0aa7b08c2d0df7ba3f3f..b0a2329df879fb317a738e471b8b2f2e103b2e9c 100644 (file)
@@ -8,8 +8,6 @@ import { AuthenticationType, ResponseStatus } from '../types/UIProtocol.js'
 import { randomUUID, validateUUID } from '../utils/UUID.js'
 import { WebSocketReadyState } from './types.js'
 
-export { ServerFailureError } from '../errors.js'
-
 export class WebSocketClient {
   public get connected (): boolean {
     return this.ws?.readyState === WebSocketReadyState.OPEN
index 12c63bbf8d037fc7516cbe1f9835639049884d29..8e0ca5f9e0a3ad86b1b327874b4332296150cb0b 100644 (file)
@@ -6,8 +6,9 @@ import { describe, it } from 'node:test'
 import type { WebSocketFactory } from '../src/client/types.js'
 import type { ResponsePayload } from '../src/types/UIProtocol.js'
 
-import { ServerFailureError, WebSocketClient } from '../src/client/WebSocketClient.js'
+import { WebSocketClient } from '../src/client/WebSocketClient.js'
 import { DEFAULT_HOST, DEFAULT_PORT } from '../src/constants.js'
+import { ServerFailureError } from '../src/errors.js'
 import {
   AuthenticationType,
   ProcedureName,