]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/log
e-mobility-charging-stations-simulator.git
2 days agochore: exclude .mypy_cache from prettier scanning
Jérôme Benoit [Sun, 15 Mar 2026 23:31:37 +0000 (00:31 +0100)] 
chore: exclude .mypy_cache from prettier scanning

2 days agorefactor: replace 54 unsafe error casts with instanceof guards
Jérôme Benoit [Sun, 15 Mar 2026 23:13:20 +0000 (00:13 +0100)] 
refactor: replace 54 unsafe error casts with instanceof guards

All 'error as Error', 'error as OCPPError', and 'error as
NodeJS.ErrnoException' casts replaced with proper instanceof
type narrowing across 16 files. Uses the pattern already
established in the auth strategies module:
  error instanceof Error ? error.message : String(error)

For call sites that pass error objects to functions, wraps
non-Error values: error instanceof Error ? error : new Error(String(error))

2 days agorefactor(ocpp): extract responseHandler and incomingRequestHandler into base classes
Jérôme Benoit [Sun, 15 Mar 2026 22:57:20 +0000 (23:57 +0100)] 
refactor(ocpp): extract responseHandler and incomingRequestHandler into base classes

Both methods were 95% identical across OCPP 1.6 and 2.0 subclasses
(~160 lines of pure duplication). Move the shared logic into the base
classes, parameterized by 3 abstract properties each subclass provides:
- bootNotificationRequestCommand / pendingStateBlockedCommands
- csmsName ('central system' vs 'CSMS')
- isRequestCommandSupported / isIncomingRequestCommandSupported

Zero behavior change — pure refactoring validated by 1853 passing tests.

2 days agofix(ocpp): use per-subclass singleton map to prevent version collision
Jérôme Benoit [Sun, 15 Mar 2026 22:37:22 +0000 (23:37 +0100)] 
fix(ocpp): use per-subclass singleton map to prevent version collision

The singleton instance was stored as a single static field on the base
class. In mixed OCPP 1.6/2.0 workers, the first getInstance() call
wins — subsequent calls for a different version silently return the
wrong instance cast via 'as T'.

Replace with Map<Constructor, Instance> keyed by the concrete subclass
constructor. Each version now gets its own singleton entry. Zero
changes needed in subclasses or calling code.

2 days agorefactor(ocpp20): extract named constants for hardcoded sleep/timeout values
Jérôme Benoit [Sun, 15 Mar 2026 22:24:50 +0000 (23:24 +0100)] 
refactor(ocpp20): extract named constants for hardcoded sleep/timeout values

Replace 8 magic numbers with semantic constants:
- FIRMWARE_STATUS_DELAY_MS, FIRMWARE_INSTALL_DELAY_MS,
  FIRMWARE_VERIFY_DELAY_MS for firmware lifecycle simulation
- LOG_UPLOAD_STEP_DELAY_MS for log upload simulation
- RESET_DELAY_MS, RESET_IDLE_MONITOR_INTERVAL_MS for reset scheduling
- CERTIFICATE_VERIFY_DELAY_MS for auth strategy retry delay

2 days agofix(charging-station): add try/finally guards to lifecycle methods
Jérôme Benoit [Sun, 15 Mar 2026 22:24:20 +0000 (23:24 +0100)] 
fix(charging-station): add try/finally guards to lifecycle methods

Prevent zombie state flags when exceptions occur:
- start(): wrap in try/finally to always reset starting=false
- stop(): wrap in try/finally to always reset stopping=false
- reset(): catch stop() failure and abort instead of proceeding
  with sleep+start on a half-stopped station
- delete(): catch stop() failure so cleanup always proceeds

2 days agorefactor(ocpp-server): parametrize failure-path tests to eliminate duplication
Jérôme Benoit [Sun, 15 Mar 2026 21:52:18 +0000 (22:52 +0100)] 
refactor(ocpp-server): parametrize failure-path tests to eliminate duplication

3 days agorefactor(ocpp-server): deduplicate outgoing commands, harden timer, expand test coverage
Jérôme Benoit [Sun, 15 Mar 2026 21:43:56 +0000 (22:43 +0100)] 
refactor(ocpp-server): deduplicate outgoing commands, harden timer, expand test coverage

3 days agochore(ocpp-server): migrate pyproject.toml to PEP 621 project metadata
Jérôme Benoit [Sun, 15 Mar 2026 20:43:50 +0000 (21:43 +0100)] 
chore(ocpp-server): migrate pyproject.toml to PEP 621 project metadata

Move name, version, description, authors, readme from deprecated
[tool.poetry.*] to [project.*] per PEP 621. Move dependencies from
[tool.poetry.dependencies] to [project.dependencies] with PEP 508
specifiers. Set requires-python to >=3.12,<4.0 to match ocpp package
constraint. Regenerate poetry.lock.

3 days agofix(tests): remove stale optional chaining on now-required variableAttribute
Jérôme Benoit [Sun, 15 Mar 2026 20:29:21 +0000 (21:29 +0100)] 
fix(tests): remove stale optional chaining on now-required variableAttribute

ReportDataType.variableAttribute was made required in 429cdbe3 but
test files still used ?. and ?? [] on the field. The stale eslint
cache masked these errors locally; CI (no cache) correctly rejected.

3 days agostyle(ocpp20): condense B09.FR.31 comment to single line per codebase convention
Jérôme Benoit [Sun, 15 Mar 2026 20:24:39 +0000 (21:24 +0100)] 
style(ocpp20): condense B09.FR.31 comment to single line per codebase convention

3 days agofix(ocpp20): implement proper M04.FR.06 guard via isChargingStationCertificateHash
Jérôme Benoit [Sun, 15 Mar 2026 20:16:10 +0000 (21:16 +0100)] 
fix(ocpp20): implement proper M04.FR.06 guard via isChargingStationCertificateHash

The previous M04.FR.06 guard was ineffective: it called
getInstalledCertificates() which scans root cert directories and
maps types via mapInstallTypeToGetType(), which has no case for
ChargingStationCertificate (stored via CertificateSigned, not
InstallCertificate). The V2GCertificateChain filter never matched.

Add isChargingStationCertificateHash() to OCPP20CertificateManager
that directly scans the ChargingStationCertificate directory and
compares certificate hashes. Use it in handleRequestDeleteCertificate
for a reliable M04.FR.06 guard.

3 days agofix(ocpp20): remediate 4 conformance findings from cross-audit
Jérôme Benoit [Sun, 15 Mar 2026 20:04:35 +0000 (21:04 +0100)] 
fix(ocpp20): remediate 4 conformance findings from cross-audit

- M04.FR.06: Narrow DeleteCertificate guard to V2GCertificateChain type
  only, allowing legitimate deletion of root certificates (CSMSRoot,
  ManufacturerRoot, MORootCert, V2GRoot)
- B09.FR.05: Use InvalidConfSlot reasonCode per errata 2025-09 when
  configurationSlot is not in NetworkConfigurationPriority list
- B09.FR.04/FR.31: Check AllowSecurityProfileDowngrade variable before
  rejecting downgrades — allow 3→2 when true, never allow to profile 1
  (errata 2025-09 §2.12)
- L01.FR.06: Wait for active transactions to end before commencing
  firmware installation via polling loop in lifecycle simulation

3 days agorefactor(ocpp16): track diagnosticsStatus and extract composite schedule helper
Jérôme Benoit [Sun, 15 Mar 2026 19:22:37 +0000 (20:22 +0100)] 
refactor(ocpp16): track diagnosticsStatus and extract composite schedule helper

- Add diagnosticsStatus to ChargingStationInfo, set at each
  DiagnosticsStatusNotification send point (Uploading, Uploaded,
  UploadFailed). TriggerMessage now reports actual diagnostics status
  instead of hardcoded Idle, mirroring the firmwareStatus pattern.

- Extract composeCompositeSchedule() private method, eliminating
  ~120 lines of duplicated profile preparation logic between the
  connectorId=0 and connectorId>0 branches of GetCompositeSchedule.

3 days agofix(ocpp16): ocpp 1.6 conformance audit — 8 findings remediated
Jérôme Benoit [Sun, 15 Mar 2026 18:54:33 +0000 (19:54 +0100)] 
fix(ocpp16): ocpp 1.6 conformance audit — 8 findings remediated

Fixes validated against OCPP 1.6 Edition 2 spec and OCA JSON schemas:

- DT-01: DataTransfer returns UnknownMessageId when vendorId matches
  but messageId is provided (spec §4.3)
- CCP-01: ClearChargingProfile applies id/stackLevel/purpose filters
  when connectorId is specified instead of clearing all profiles (spec §5.5)
- TM-01/02/03: TriggerMessage handles DiagnosticsStatusNotification,
  FirmwareStatusNotification and MeterValues triggers (spec §5.17)
- GAP-03: ChangeConfiguration rejects non-integer and negative values
  for known integer config keys (spec §5.3)
- GAP-11: Reset distinguishes Hard/Soft — hard reset skips graceful
  transaction stopping (spec §5.14)
- GCS-02: GetCompositeSchedule implements connectorId=0 to report
  total grid consumption across all connectors (spec §5.7)

3 days agofix(ocpp16): fix StopTransaction unit schema and ChargingSchedule field name
Jérôme Benoit [Sun, 15 Mar 2026 18:53:54 +0000 (19:53 +0100)] 
fix(ocpp16): fix StopTransaction unit schema and ChargingSchedule field name

- Add missing 'Celsius' to StopTransaction.json unit enum (M-2/SP-1)
  The runtime schema had only 'Celcius' (legacy typo) while the OCA
  official schema has both. TS enum produces 'Celsius' which was
  rejected by AJV when ocppStrictCompliance was enabled.

- Rename minChargeRate to minChargingRate in OCPP16ChargingSchedule (RST-01)
  Field name typo caused JSON serialization mismatch with spec §7.13
  and schema 'minChargingRate', breaking SetChargingProfile and
  GetCompositeSchedule payloads.

3 days agofix: clear OCPPAuthServiceFactory cached instance on station delete
Jérôme Benoit [Sun, 15 Mar 2026 18:36:48 +0000 (19:36 +0100)] 
fix: clear OCPPAuthServiceFactory cached instance on station delete

clearInstance was never called, leaking one OCPPAuthService per station
in the factory's static instances Map after station stop/delete.

3 days agofix(ocpp20): clean up VariableManager mappings cache on station stop
Jérôme Benoit [Sun, 15 Mar 2026 18:23:00 +0000 (19:23 +0100)] 
fix(ocpp20): clean up VariableManager mappings cache on station stop

invalidateMappingsCache was never called on station stop, leaking
invalidVariables and validatedStations entries for each stopped station.
Call it alongside resetRuntimeOverrides in stop() for complete cleanup.

3 days agofix(ocpp20): isolate VariableManager overrides per station
Jérôme Benoit [Sun, 15 Mar 2026 18:19:07 +0000 (19:19 +0100)] 
fix(ocpp20): isolate VariableManager overrides per station

runtimeOverrides, minSetOverrides, and maxSetOverrides were stored as flat
Maps on the singleton OCPP20VariableManager, causing SetVariables on one
station to affect all others sharing the same service instance.

Apply the same Map<stationId, Map<key, value>> pattern already used by
invalidVariables in the same class. resetRuntimeOverrides now accepts
optional stationId, matching the invalidateMappingsCache API.

3 days agorefactor(ocpp20): isolate per-station state with WeakMap instead of singleton properties
Jérôme Benoit [Sun, 15 Mar 2026 18:04:39 +0000 (19:04 +0100)] 
refactor(ocpp20): isolate per-station state with WeakMap instead of singleton properties

Per-station state (firmware update tracking, report cache, connector status
backup) was incorrectly stored as flat properties on the singleton
OCPP20IncomingRequestService, causing cross-station pollution when multiple
stations share the same service instance.

Introduce OCPP20PerStationState interface and a WeakMap<ChargingStation, ...>
to properly isolate state per station, matching the stateless service pattern
used by OCPP16IncomingRequestService. State is lazily initialized and
automatically garbage collected when the station is released.

3 days agodocs: fix README OCPP 2.0.x notes with spec-verified FR references
Jérôme Benoit [Sun, 15 Mar 2026 17:39:23 +0000 (18:39 +0100)] 
docs: fix README OCPP 2.0.x notes with spec-verified FR references

3 days agofix(ocpp20): ocpp 2.0.1 conformance audit — 17 findings remediated
Jérôme Benoit [Sun, 15 Mar 2026 17:30:57 +0000 (18:30 +0100)] 
fix(ocpp20): ocpp 2.0.1 conformance audit — 17 findings remediated

- fix(types): widen DataTransfer data to JsonType for unconstrained payloads
- fix(types): narrow VariableAttributeType.type to AttributeEnumType
- fix(types): make ReportDataType.variableAttribute required per JSON schema
- fix(types): allow custom string values for UnitOfMeasure.unit
- fix(firmware): remove invalid AcceptedCanceled from FirmwareStatusEnumType
- fix(firmware): return AcceptedCanceled on cancel, trigger lifecycle for both
- fix(firmware): track lastFirmwareStatus for TriggerMessage (L01.FR.25/26)
- fix(firmware): accept UpdateFirmware with active transactions (L01.FR.06)
- fix(transaction): make evseId optional in RequestStartTransaction (F01.FR.10)
- fix(transaction): consult AuthorizeRemoteStart variable (F01.FR.02)
- fix(network): implement security profile downgrade detection (B09.FR.04)
- fix(network): implement slot-in-priority validation (B09.FR.05)
- fix(trigger): contextual EVSE validation for MeterValues/StatusNotification only
- fix(availability): save/restore pre-Inoperative connector statuses (G03.FR.07)
- fix(availability): add connector-level ChangeAvailability targeting

3 days agofix(ocpp16): harmonize error logging — log silent catches, demote business violations...
Jérôme Benoit [Sun, 15 Mar 2026 15:28:51 +0000 (16:28 +0100)] 
fix(ocpp16): harmonize error logging — log silent catches, demote business violations to warn

3 days agofix(ocpp20): add missing JSDoc @param description for hashAlgorithm in getInstalledCe...
Jérôme Benoit [Sun, 15 Mar 2026 15:19:58 +0000 (16:19 +0100)] 
fix(ocpp20): add missing JSDoc @param description for hashAlgorithm in getInstalledCertificates

3 days agodocs: update README OCPP 2.0.x section with post-audit implementation details
Jérôme Benoit [Sun, 15 Mar 2026 15:17:15 +0000 (16:17 +0100)] 
docs: update README OCPP 2.0.x section with post-audit implementation details

3 days agofix(ocpp20): remediate all OCPP 2.0.1 audit findings (#1726)
Jérôme Benoit [Sun, 15 Mar 2026 15:10:29 +0000 (16:10 +0100)] 
fix(ocpp20): remediate all OCPP 2.0.1 audit findings (#1726)

* fix(ocpp20): add consistent statusInfo to all rejection responses

* fix(ocpp20): cache validatePersistentMappings and fix MinSet/MaxSet atomicity

* feat(ocpp20): implement SetNetworkProfile Accepted path per B09.FR.01

* fix(ocpp20): prevent deletion of ChargingStationCertificate per M04.FR.06

* feat(ocpp20): implement GetLog lifecycle with LogStatusNotification per N01

* fix(ocpp20): implement NotifyCustomerInformation pagination and N09.FR.09 validation

* feat(ocpp20): add X.509 certificate validation per A02.FR.06 and M05

* feat(ocpp20): implement UpdateFirmware lifecycle with status notifications per L01/L02

* feat(ocpp20): generate real PKCS#10 CSR with node:crypto per A02.FR.02

* feat(ocpp20): add firmware signature check, transaction blocking, cancellation

* docs(ocpp20): document OCSP limitation + enforce MaxCertificateChainSize

* style(ocpp20): fix all lint errors and warnings

* [autofix.ci] apply automated fixes

* fix(ocpp20): address PR review findings — enum fix, per-station cache, cancellation status

* [autofix.ci] apply automated fixes

* docs(ocpp20): document simulator limitations for SetNetworkProfile and X.509 validation

* refactor(ocpp20): extract ASN.1 DER utilities to dedicated module

* fix(ocpp20): scope invalidVariables per-station in VariableManager singleton

* [autofix.ci] apply automated fixes

* test(ocpp20): improve test hygiene — extract flushMicrotasks, remove dead code, strengthen spy coverage

* [autofix.ci] apply automated fixes

* fix(ocpp20): replace silent hashId fallback with fail-fast guard in VariableManager

* fix(ocpp20): align B09.FR.02 reasonCode to errata 2025-09 InvalidNetworkConf

* style(ocpp20): normalize spec ref format in additionalInfo to parentheses style

* fix(ocpp20): use request hashAlgorithm in M04.FR.06 guard for algorithm-independent certificate matching

* [autofix.ci] apply automated fixes

* style(ocpp20): harmonize message content — sentence case, consistent punctuation, no em-dash

* fix(ocpp20): unify .catch() log level to logger.error for all fire-and-forget notifications

* fix(ocpp20): remove noisy per-call OCSP stub warning — limitation already documented in JSDoc

* refactor(ocpp20): rename invalidVariablesPerStation to invalidVariables for naming consistency

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
3 days agochore(deps): lock file maintenance (#1725)
renovate[bot] [Sun, 15 Mar 2026 11:42:53 +0000 (12:42 +0100)] 
chore(deps): lock file maintenance (#1725)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3 days agochore(deps): update dependency jsdom to v29 (#1723)
renovate[bot] [Sun, 15 Mar 2026 10:15:19 +0000 (11:15 +0100)] 
chore(deps): update dependency jsdom to v29 (#1723)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3 days agochore(deps): update dependency lint-staged to ^16.4.0 (#1721)
renovate[bot] [Sun, 15 Mar 2026 10:13:51 +0000 (11:13 +0100)] 
chore(deps): update dependency lint-staged to ^16.4.0 (#1721)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3 days agochore(deps): update dependency pytest-cov to v7 (#1724)
renovate[bot] [Sun, 15 Mar 2026 10:11:52 +0000 (11:11 +0100)] 
chore(deps): update dependency pytest-cov to v7 (#1724)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3 days agochore(deps): update dependency pytest to v9 (#1722)
renovate[bot] [Sun, 15 Mar 2026 09:59:28 +0000 (10:59 +0100)] 
chore(deps): update dependency pytest to v9 (#1722)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3 days agoci(ocpp-server): add type checking, test coverage and unit tests to CI pipeline ...
Jérôme Benoit [Sat, 14 Mar 2026 23:39:20 +0000 (00:39 +0100)] 
ci(ocpp-server): add type checking, test coverage and unit tests to CI pipeline (#1720)

3 days agofix(renovate): enable Poetry dependency detection for OCPP2 mock server
Jérôme Benoit [Sat, 14 Mar 2026 22:46:56 +0000 (23:46 +0100)] 
fix(renovate): enable Poetry dependency detection for OCPP2 mock server

Override :ignoreModulesAndTests preset to remove **/tests/** from
ignorePaths, allowing Renovate to discover tests/ocpp-server/pyproject.toml
and manage its Python/Poetry dependencies.

4 days agodocs: fix root README coherence with codebase
Jérôme Benoit [Sat, 14 Mar 2026 00:15:41 +0000 (01:15 +0100)] 
docs: fix root README coherence with codebase

- Add missing NotifyCustomerInformation to OCPP 2.0.x section
- Add undocumented station template fields (iccid, imsi,
  meterSerialNumberPrefix, meterType)
- List all available OCPP command procedure names in UI Protocol section
  with separate OCPP 1.6 and 2.0.x lists
- Update copyright year to 2026 in README and LICENSE

4 days agodocs(ui-web): rewrite README with coherent structure and code-verified content
Jérôme Benoit [Sat, 14 Mar 2026 00:01:04 +0000 (01:01 +0100)] 
docs(ui-web): rewrite README with coherent structure and code-verified content

5 days agofix(ocpp-server): share charge_points set across connections and harden test quality
Jérôme Benoit [Fri, 13 Mar 2026 21:08:30 +0000 (22:08 +0100)] 
fix(ocpp-server): share charge_points set across connections and harden test quality

- Fix charge_points set created per-connection instead of shared across
  all connections via ServerConfig
- Remove AuthConfig.__getitem__ dict-compat hack and isinstance(dict)
  coercion branch from ChargePoint.__init__
- Migrate all test fixtures from raw dicts to AuthConfig instances
- Replace 11 weak 'assert X is not None' with typed assertions
  (isinstance, enum equality)
- Hoist Action import to module level in test_server.py

5 days agofix(ocpp-server): use MagicMock for sync method in test to fix RuntimeWarning
Jérôme Benoit [Fri, 13 Mar 2026 20:42:50 +0000 (21:42 +0100)] 
fix(ocpp-server): use MagicMock for sync method in test to fix RuntimeWarning

5 days agotest(ocpp-server): add connection lifecycle and command scheduling tests
Jérôme Benoit [Fri, 13 Mar 2026 20:39:29 +0000 (21:39 +0100)] 
test(ocpp-server): add connection lifecycle and command scheduling tests

5 days agotest(ocpp-server): add behavioral tests for all outgoing commands
Jérôme Benoit [Fri, 13 Mar 2026 20:30:47 +0000 (21:30 +0100)] 
test(ocpp-server): add behavioral tests for all outgoing commands

5 days agotest(ocpp-server): add Timer class test coverage
Jérôme Benoit [Fri, 13 Mar 2026 20:21:08 +0000 (21:21 +0100)] 
test(ocpp-server): add Timer class test coverage

5 days agotest(ocpp-server): centralize constants, strengthen assertions, add auth modes, trim...
Jérôme Benoit [Fri, 13 Mar 2026 20:15:04 +0000 (21:15 +0100)] 
test(ocpp-server): centralize constants, strengthen assertions, add auth modes, trim meta-tests

5 days agofix(ocpp-server): extract CP ID from last URL segment and scope ChargePoints to instance
Jérôme Benoit [Fri, 13 Mar 2026 20:06:33 +0000 (21:06 +0100)] 
fix(ocpp-server): extract CP ID from last URL segment and scope ChargePoints to instance

5 days agorefactor(ocpp-server): introduce AuthMode, AuthConfig and ServerConfig typed dataclasses
Jérôme Benoit [Fri, 13 Mar 2026 20:01:00 +0000 (21:01 +0100)] 
refactor(ocpp-server): introduce AuthMode, AuthConfig and ServerConfig typed dataclasses

5 days agofix(ocpp-server): add suppress=False to all call() invocations and widen randint...
Jérôme Benoit [Fri, 13 Mar 2026 19:53:21 +0000 (20:53 +0100)] 
fix(ocpp-server): add suppress=False to all call() invocations and widen randint range

5 days agodocs(ocpp-server): restructure README with logical section hierarchy
Jérôme Benoit [Fri, 13 Mar 2026 18:58:05 +0000 (19:58 +0100)] 
docs(ocpp-server): restructure README with logical section hierarchy

5 days agofeat(ocpp-server): add error handling, configurable params, async tests, and Python...
Jérôme Benoit [Fri, 13 Mar 2026 18:53:46 +0000 (19:53 +0100)] 
feat(ocpp-server): add error handling, configurable params, async tests, and Python 3.14+ compat

- Add centralized error handling in _send_command dispatch for
  TimeoutError, OCPPError, and ConnectionClosed
- Make host/port configurable via --host and --port CLI args
- Make boot notification status configurable via --boot-status
- Make TransactionEvent total cost configurable via --total-cost
- Extract server defaults as module-level constants
- Fix asyncio.iscoroutine() deprecation in timer.py: use
  inspect.iscoroutinefunction() + inspect.isawaitable() for Python 3.14+
- Add proper type annotations and docstrings to timer.py
- Add pytest-asyncio for async handler testing (82 tests total)
- Add async tests for all 15 incoming OCPP handlers
- Add error handling tests for command dispatch layer
- Add tests for configurable boot_status and total_cost
- Update README with new server and charging behavior CLI options

5 days agofeat(ocpp-server): overhaul OCPP 2.0.1 mock server with full command coverage
Jérôme Benoit [Fri, 13 Mar 2026 18:39:58 +0000 (19:39 +0100)] 
feat(ocpp-server): overhaul OCPP 2.0.1 mock server with full command coverage

- Add 4 new @on handlers: Get15118EVCertificate, GetCertificateStatus,
  SignCertificate, NotifyCustomerInformation
- Add 9 new outgoing commands: CertificateSigned, CustomerInformation,
  DeleteCertificate, GetInstalledCertificateIds, GetLog,
  GetTransactionStatus, InstallCertificate, SetNetworkProfile,
  UpdateFirmware (20 total)
- Fix camelCase key access bug in authorize/transaction handlers
  (ocpp library converts to snake_case)
- Extract _resolve_auth_status() to eliminate duplicated auth logic
- Replace ConnectionError with InternalError for offline simulation
- Use set.discard() instead of set.remove() for safe cleanup
- Add match default case for unknown TransactionEvent types
- Modernize type hints: Optional[X] -> X | None
- Rewrite test suite with pytest (51 tests, 4 test classes)
- Update ruff to ^0.15, add pytest ^8 dev dependency
- Update README with all 20 outgoing commands and 15 incoming handlers

5 days agotest: remove 24 tautological enum value assertion tests
Jérôme Benoit [Fri, 13 Mar 2026 16:29:36 +0000 (17:29 +0100)] 
test: remove 24 tautological enum value assertion tests

Remove tests that assert compile-time constant enum values (e.g.
EnumName.MEMBER === 'hardcodedString'), which always pass by definition
and exercise no production code.

- Delete ConfigurationData.test.ts (3 tautological tests)
- Remove ProcedureName/BroadcastChannelProcedureName enum groups (16 tests)
- Remove AuthTypes Enums block (4 tests)
- Remove OutputFormat enum test (1 test)
- Fix assert.strictEqual(true, false) to assert.fail() in OCPPAuthServiceFactory

All quality gates pass. Coverage unchanged (1800 tests, 0 failures).

5 days agochore(deps): update all non-major dependencies (#1716)
renovate[bot] [Fri, 13 Mar 2026 15:54:30 +0000 (16:54 +0100)] 
chore(deps): update all non-major dependencies (#1716)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
5 days agofeat(ocpp2): integrate all 8 missing OCPP 2.0.1 outgoing commands into UIService...
Jérôme Benoit [Fri, 13 Mar 2026 15:54:08 +0000 (16:54 +0100)] 
feat(ocpp2): integrate all 8 missing OCPP 2.0.1 outgoing commands into UIService/BroadcastChannel pipeline (#1718)

* feat(types): add OCPP 2.0.1 UI procedure and broadcast channel enums

- Add 8 new ProcedureName entries (get15118EVCertificate, getCertificateStatus, logStatusNotification, notifyCustomerInformation, notifyReport, securityEventNotification, signCertificate, transactionEvent)
- Mirror same 8 entries in BroadcastChannelProcedureName
- Extend BroadcastChannelRequestPayload with optional OCPP 2.0.1 fields (eventType, evseId, idToken, transactionData)

* feat(ui-service): wire OCPP 2.0.1 commands through UI service pipeline

Add 8 new ProcedureNameToBroadCastChannelProcedureNameMapping entries for:
get15118EVCertificate, getCertificateStatus, logStatusNotification,
notifyCustomerInformation, notifyReport, securityEventNotification,
signCertificate, transactionEvent

* feat(broadcast-channel): add OCPP 2.0.1 command handlers and response mapping

- Add 8 new command handlers: get15118EVCertificate, getCertificateStatus,
  logStatusNotification, notifyCustomerInformation, notifyReport,
  securityEventNotification, signCertificate, transactionEvent
- Update CommandResponse type union with 4 OCPP 2.0.1 response types
- Add 4 commandResponseToResponseStatus cases for non-empty responses
- Fix METER_VALUES handler: add OCPP 2.0.1 passthrough branch (version-detected)
- Fire-and-forget commands handled automatically by isEmpty bailout

* fix(ocpp2): add missing certificate commands to buildRequestPayload

Add SIGN_CERTIFICATE, GET_15118_EV_CERTIFICATE, GET_CERTIFICATE_STATUS
to the passthrough case group — these previously fell to the default
branch which threw OCPPError(NOT_SUPPORTED)

* test(broadcast-channel): add OCPP 2.0.1 UIService pipeline integration tests

Add 45 tests across 6 groups covering:
- ProcedureName enum: 8 new OCPP 2.0.1 entries
- BroadcastChannelProcedureName enum: 8 new OCPP 2.0.1 entries
- ProcedureNameToBroadCastChannelProcedureNameMapping: 8 new entries
- BroadcastChannelRequestPayload: OCPP 2.0.1 optional fields
- commandResponseToResponseStatus: 4 new command response cases
- commandHandlers Map: 8 new entries registered

* style: fix perfectionist ordering in broadcast channel handler and tests

* [autofix.ci] apply automated fixes

* test(broadcast-channel): add buildRequestPayload and behavioral handler tests

Add Group 7 (buildRequestPayload certificate passthrough) and Group 8
(commandHandlers behavioral) tests addressing audit findings:

- 3 tests verify GET_15118_EV_CERTIFICATE, GET_CERTIFICATE_STATUS, and
  SIGN_CERTIFICATE payloads pass through unchanged
- 8 tests verify each OCPP 2.0.1 handler invokes requestHandler with the
  correct RequestCommand enum value

Total: 56 tests in file, 1816 across suite.

* [autofix.ci] apply automated fixes

* refactor(test): remove redundant test groups from broadcast channel tests

Remove Group 4 (BroadcastChannelRequestPayload tautological - type system
already enforces at compile time) and Group 6 (commandHandlers existence -
fully subsumed by Group 8 behavioral tests that verify both existence and
correct RequestCommand routing).

45 tests across 6 groups, 1805 total suite.

* fix: address PR review comments — tighten types, add fire-and-forget response cases, barrel export

- Add explicit commandResponseToResponseStatus cases for 4 fire-and-forget
  commands (LogStatusNotification, NotifyCustomerInformation, NotifyReport,
  SecurityEventNotification) using isEmpty pattern matching existing
  MeterValues/StatusNotification behavior
- Tighten BroadcastChannelRequestPayload types: idToken uses
  OCPP20IdTokenType, rename transactionData to transactionInfo with
  OCPP20TransactionType per OCPP 2.0.1 spec
- Add OCPP20AuthorizationStatusEnumType to barrel export in types/index.ts,
  switch deep imports to barrel imports in source and test files
- Add 8 tests for fire-and-forget commandResponseToResponseStatus coverage
- Fix cspell warnings in test mock data strings

* test: improve OCPP 2.0.1 broadcast channel coverage with dispatch and pipeline tests

Add commandHandler dispatch pipeline tests (Group 6) and requestHandler
full pipeline tests (Group 7) to exercise handler closure bodies through
the actual dispatch path. Convert Group 6 from direct Map.get() to
commandHandler() method dispatch for better V8 coverage tracking.

59 tests across 7 groups (was 53 tests across 6 groups).

* refactor(broadcast-channel): extract handler closures to named private methods

Extract 17 async handler closures from the Map constructor into named
private methods with .bind(this) references. This improves V8 coverage
tracking accuracy for arrow function closures inside Map constructor
arrays, where tsx/esbuild source map misalignment causes inconsistent
coverage attribution.

No behavioral changes — all handlers execute the same logic.

* [autofix.ci] apply automated fixes

* test(broadcast-channel): add mapping completeness validation for UI service command pipeline

* [autofix.ci] apply automated fixes

* refactor(types): remove unused OCPP 2.0 fields from BroadcastChannelRequestPayload

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
5 days agotest(ocpp): add schema registration coverage tests for OCPP 1.6 and 2.0
Jérôme Benoit [Thu, 12 Mar 2026 23:04:47 +0000 (00:04 +0100)] 
test(ocpp): add schema registration coverage tests for OCPP 1.6 and 2.0

Verify every command enum value has its request and response schemas
registered in ServiceUtils, and that all referenced schema files exist
on disk. Prevents regressions where a command is implemented but its
schema registration is forgotten.

5 days agofix(ocpp2): add missing outgoing schema entries for certificate commands
Jérôme Benoit [Thu, 12 Mar 2026 22:56:04 +0000 (23:56 +0100)] 
fix(ocpp2): add missing outgoing schema entries for certificate commands

Register Get15118EVCertificate, GetCertificateStatus, and SignCertificate
in OCPP20ServiceUtils.outgoingRequestSchemaNames to ensure JSON schema
validation for these certificate management commands.

5 days agorefactor(ocpp): remove dead parseJsonSchemaFile overrides and standardize validation
Jérôme Benoit [Thu, 12 Mar 2026 22:42:20 +0000 (23:42 +0100)] 
refactor(ocpp): remove dead parseJsonSchemaFile overrides and standardize validation

- Delete unused parseJsonSchemaFile overrides from OCPP16/20ServiceUtils
  (createPayloadValidatorMap already passes version via options)
- Remove orphaned JSONSchemaType and JsonType imports
- Standardize null-validator return to false in OCPPRequestService
  (consistent with OCPPIncomingRequestService and OCPPResponseService)
- Change validateRequestPayload and validateIncomingRequestResponsePayload
  visibility from private to protected (consistent with other base classes)

5 days agorefactor(ocpp): harmonize JSON schema payload validation across OCPP stacks
Jérôme Benoit [Thu, 12 Mar 2026 22:31:30 +0000 (23:31 +0100)] 
refactor(ocpp): harmonize JSON schema payload validation across OCPP stacks

- Absorb missing-validator null guard into base class methods, eliminating
  4 identical private validatePayload wrappers and their bind() calls
- Remove dead code (unreachable isValid branches in ResponseService wrappers)
- Make parseJsonSchemaFile throw on failure instead of silently returning {},
  preventing validators that accept everything as a security bypass
- Add dual-path schema resolution for production (esbuild) and test (tsx)
- Align OCPP 1.6 schema map construction with OCPP 2.0 registry pattern,
  replacing ~200 lines of verbose inline entries with declarative registries
- Collapse 4 identical payload options factory methods into 1 per version

6 days agorefactor(ocpp2): convert incoming request fire-and-forget patterns to event listeners...
Jérôme Benoit [Thu, 12 Mar 2026 21:43:33 +0000 (22:43 +0100)] 
refactor(ocpp2): convert incoming request fire-and-forget patterns to event listeners (#1715)

* refactor(ocpp2): convert UpdateFirmware fire-and-forget to event listener

* refactor(ocpp2): convert GetLog fire-and-forget to event listener

* refactor(ocpp2): convert CustomerInformation fire-and-forget to event listener

* refactor(ocpp2): convert TriggerMessage fire-and-forget to event listener

* [autofix.ci] apply automated fixes

* test(ocpp2): improve TRIGGER_MESSAGE listener test coverage for SonarCloud

* test(ocpp2): remove 10 redundant handler tests that add no branch coverage

* test(ocpp2): remove 5 project-wide redundant tests identified by cross-validated audit

* refactor(ocpp2): extract StatusNotification trigger methods to reduce cognitive complexity

* [autofix.ci] apply automated fixes

* test(ocpp2): strengthen StatusNotification trigger assertions with payload and options validation

* [autofix.ci] apply automated fixes

* fix(ocpp2): relocate B11.FR.01 spec reference to correct surviving test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
6 days agofeat(ocpp2): OCPP 2.0.1 Core certification readiness (#1712)
Jérôme Benoit [Thu, 12 Mar 2026 18:57:32 +0000 (19:57 +0100)] 
feat(ocpp2): OCPP 2.0.1 Core certification readiness (#1712)

* feat(ocpp2): add type definitions and validator configs for OCPP 2.0.1 Core certification commands

* feat(ocpp2): implement DataTransfer reject handler

* feat(ocpp2): implement SetNetworkProfile reject handler

* feat(ocpp2): implement GetTransactionStatus handler

* feat(ocpp2): implement CustomerInformation clear handler

* feat(ocpp2): implement SecurityEventNotification outgoing command

* fix(ocpp2): handle TransactionEvent response idTokenInfo status

* feat(ocpp2): implement ChangeAvailability handler

* feat(ocpp2): implement standalone MeterValues outgoing command

* feat(ocpp2): implement UpdateFirmware and FirmwareStatusNotification

Add UpdateFirmware (CSMS→CS) incoming request handler with simulated
firmware update lifecycle state machine (Downloading → Downloaded →
SignatureVerified → Installing → Installed) and FirmwareStatusNotification
(CS→CSMS) outgoing command.

- Handle UPDATE_FIRMWARE incoming request, return Accepted status
- Simulate firmware update lifecycle via chained setTimeout calls
- Send FirmwareStatusNotification at each state transition
- Check firmware.signature presence for SignatureVerified state
- Add testable interfaces for both handler and request service
- Add 8 tests (5 for UpdateFirmware, 3 for FirmwareStatusNotification)

* feat(ocpp2): implement GetLog and LogStatusNotification

- Add GetLog incoming request handler with simulated upload lifecycle
  (Uploading → Uploaded via chained setTimeout)
- Add LogStatusNotification outgoing command in RequestService
- Register handleResponseLogStatusNotification in ResponseService
- Update testable interfaces with new handler and request method
- Add 4 GetLog tests (DiagnosticsLog, SecurityLog, requestId, retries)
- Add 3 LogStatusNotification tests (Uploading, requestId, empty response)
- All quality gates pass: lint, typecheck, build, 1737 tests

* feat(ocpp2): expand TriggerMessage handler with new trigger types

* docs: update README with OCPP 2.0.1 Core certification commands

* style(ocpp2): fix space-before-function-paren in TriggerMessage handler and test

* fix(ocpp2): add missing case branches in buildRequestPayload for new commands

buildRequestPayload throws NOT_SUPPORTED for FirmwareStatusNotification,
LogStatusNotification, MeterValues, NotifyCustomerInformation, and
SecurityEventNotification since they have no case branches. This causes
guaranteed runtime failures when TriggerMessage invokes requestHandler
for these commands.

Add pass-through case branches matching the existing pattern used by
other notification commands.

* fix(ocpp2): use zero-based seqNo in NotifyCustomerInformation per OCPP 2.0.1 spec

* fix(ocpp2): stop only specific transaction in handleResponseTransactionEvent

handleResponseTransactionEvent was stopping ALL active transactions when
any rejected idTokenInfo.status arrived. Per OCPP 2.0.1 spec (D01/D05),
only the specific transaction referenced by the TransactionEvent request
should be stopped.

Extract the transactionId from the request payload and use
getConnectorIdByTransactionId/getEvseIdByTransactionId to find and stop
only the affected transaction.

* fix(ocpp2): set idle EVSEs Inoperative immediately on CS-level ChangeAvailability per G03.FR.04

* fix(ocpp2): add firmware lifecycle delay, JSDoc, and consistent handler patterns

- Add delay between Downloaded and SignatureVerified in firmware update lifecycle per J01
- Add missing JSDoc for requestLogStatusNotification in testable interface
- Convert 4 arrow function handlers to regular methods for consistency with pre-existing handlers

* refactor(ocpp2): resolve SonarCloud quality gate findings

- Replace duplicated delay() functions with shared sleep() utility
- Extract handleEvseChangeAvailability and handleCsLevelInoperative to
  reduce cognitive complexity of handleRequestChangeAvailability
- Extract hasAnyActiveTransaction to eliminate nested loops
- Fix negated conditions and nested template literals

* refactor(ocpp2): deduplicate validator configs via shared schema name maps

- Extract incomingRequestSchemaNames and outgoingRequestSchemaNames as
  single source of truth for command-to-schema mappings
- Generate request/response configs from shared maps, eliminating 96
  lines of structural duplication flagged by SonarCloud
- Fix remaining negated conditions in ternary expressions

* fix(test): deduplicate MeterValues call, add multi-EVSE isolation test

* fix(ocpp2): eliminate double status notification, document messagesInQueue

* test(ocpp2): align test files with TEST_STYLE_GUIDE conventions

* fix: comply with E14.FR.06 and harmonize statusInfo

7 days agochore: update serena project configuration
Jérôme Benoit [Wed, 11 Mar 2026 12:33:00 +0000 (13:33 +0100)] 
chore: update serena project configuration

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
7 days agochore(deps): lock file maintenance (#1707)
renovate[bot] [Wed, 11 Mar 2026 11:42:04 +0000 (12:42 +0100)] 
chore(deps): lock file maintenance (#1707)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
7 days agochore(deps): update pnpm to v10.32.1 (#1711)
renovate[bot] [Wed, 11 Mar 2026 11:34:21 +0000 (12:34 +0100)] 
chore(deps): update pnpm to v10.32.1 (#1711)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
8 days agotest(ocpp16): add comprehensive OCPP 1.6 unit and integration tests (#1710)
Jérôme Benoit [Tue, 10 Mar 2026 19:44:19 +0000 (20:44 +0100)] 
test(ocpp16): add comprehensive OCPP 1.6 unit and integration tests (#1710)

* test(ocpp16): add testable interface layer and test utilities

* test(ocpp16): add constants and service utils tests

* test(ocpp16): add incoming request service tests

* fix(ocpp): break circular dependency in OCPPServiceUtils via dynamic imports

Use dynamic await import() for OCPP16Constants and OCPP20Constants inside
checkConnectorStatusTransition to break the circular dependency chain:
OCPPConstants → utils/index → ErrorUtils → OCPPServiceUtils → OCPP16/20Constants → OCPPConstants

This fixes OCPP16Constants.test.ts (89 tests) without breaking UIHttpServer,
UIWebSocketServer, or AbstractUIService tests.

* test(ocpp16): add integration tests for transactions, charging profiles, configuration, and reservations

* test(ocpp16): fix lint errors, type safety, and spec traceability across all test files

- Add OCPP 1.6 spec section references (§) to all 21 test files
- Fix 129 no-floating-promises: add await to it()/describe() calls
- Fix 17 require-await: remove async from sync callbacks
- Fix 9 no-non-null-assertion: replace ! with proper null checks
- Fix 8 no-unsafe-enum-comparison: use String() wrappers
- Fix 13 TypeScript type errors (requestHandler mocks, SampledValueTemplate, etc.)
- Remove blanket eslint-disable and 89x (t: any) in Constants test
- Add @file JSDoc headers where missing

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* test(ocpp16): migrate 21 OCPP 1.6 test files from @std/expect to node:assert/strict

Replace all @std/expect imports with node:assert/strict across 21 test
files (~536 expect calls), eliminating the JSR dependency that breaks CI.

Migration patterns applied:
- expect(a).toBe(b) → assert.strictEqual(a, b)
- expect(a).toBeDefined() → assert.notStrictEqual(a, undefined)
- expect(a).toStrictEqual(b) → assert.deepStrictEqual(a, b)
- expect(a).toBeInstanceOf(T) → assert.ok(a instanceof T)
- expect(a).toContain(x) → assert.ok(a.includes(x))
- expect(p).resolves.toBeUndefined() → await assert.doesNotReject(p)
- expect(() => fn()).toThrow() → assert.throws(() => { fn() })

Added 26 null guards (if + assert.fail) after getConnectorStatus() and
nullable field accesses to satisfy both TypeScript strict null checks
and ESLint.

All quality gates pass: 1694 tests, 0 lint errors, 0 TS errors.

* test: migrate all remaining test files from @std/expect to node:assert/strict

Migrate 82 remaining test files (OCPP 2.0, auth, charging-station,
UI server, utils, worker, performance, exception, types) from
@std/expect to node:assert/strict.

Remove @std/expect JSR dependency from package.json to fix CI 404
errors on npm.jsr.io.

All 1694 tests pass, lint clean, TSC clean.

* chore: update lockfile after removing @std/expect dependency

* docs: update test style guide and config to reflect node:assert/strict migration

* test(ocpp16): eliminate as-unknown-as casts and add missing AAA comments

Create typed helpers in OCPP16TestUtils (setMockRequestHandler,
dispatchResponse, createMeterValuesTemplate, createCommandsSupport)
to encapsulate type casts in one place instead of 26 inline casts
across 8 test files.

Add Arrange/Act/Assert comments to 5 tests in
OCPP16ServiceUtils.test.ts that have 3+ logical setup steps.

All 1694 tests pass, lint clean, TSC clean.

* fix(test): use real enum value instead of as-any cast in AuthHelpers.test.ts

Use AuthorizationStatus.NO_CREDIT (unhandled by getStatusMessage
switch) to test the default branch, removing the as-any cast and
eslint-disable comment that caused CI autofix failure.

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
8 days agochore(deps): update all non-major dependencies (#1709)
renovate[bot] [Tue, 10 Mar 2026 16:36:20 +0000 (17:36 +0100)] 
chore(deps): update all non-major dependencies (#1709)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9 days agofix: migrate JSR dependency from legacy npm:@jsr/ to native jsr: protocol
Jérôme Benoit [Mon, 9 Mar 2026 18:49:48 +0000 (19:49 +0100)] 
fix: migrate JSR dependency from legacy npm:@jsr/ to native jsr: protocol

Replace the legacy npm compatibility layer approach with pnpm's native
jsr: protocol support (available since pnpm 10.9.0) to fix 404 errors
when fetching @jsr/std__assert tarballs from npm.jsr.io.

- package.json: use jsr:@std/expect specifier instead of npm:@jsr/std__expect
- package.json, ui/web/package.json: bump engines.pnpm to >=10.9.0
- .npmrc: remove @jsr:registry=https://npm.jsr.io (no longer needed)
- pnpm-lock.yaml: regenerated with native JSR resolution

9 days agofix(deps): update all non-major dependencies (#1706)
renovate[bot] [Mon, 9 Mar 2026 18:21:13 +0000 (19:21 +0100)] 
fix(deps): update all non-major dependencies (#1706)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
11 days agochore: sync serena project configuration
Jérôme Benoit [Sat, 7 Mar 2026 19:16:58 +0000 (20:16 +0100)] 
chore: sync serena project configuration

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
11 days agochore(deps): update all non-major dependencies to ^9.39.4 (#1705)
renovate[bot] [Sat, 7 Mar 2026 12:10:37 +0000 (13:10 +0100)] 
chore(deps): update all non-major dependencies to ^9.39.4 (#1705)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
11 days agochore: release main (#1691) ocpp-server@v3.0.0 simulator@v3.0.0 v3.0 webui@v3.0.0
Jérôme Benoit [Fri, 6 Mar 2026 23:01:11 +0000 (00:01 +0100)] 
chore: release main (#1691)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
11 days agofix: remove accidentally committed mikro-orm.config.ts (gitignored local config)
Jérôme Benoit [Fri, 6 Mar 2026 22:43:13 +0000 (23:43 +0100)] 
fix: remove accidentally committed mikro-orm.config.ts (gitignored local config)

11 days agofix: correct @mikro-orm/sqlite import to @mikro-orm/better-sqlite, format ElectricUti...
Jérôme Benoit [Fri, 6 Mar 2026 22:40:36 +0000 (23:40 +0100)] 
fix: correct @mikro-orm/sqlite import to @mikro-orm/better-sqlite, format ElectricUtils tests

11 days agorefactor(tests): named cosPhi constants, accurate mock call types, remove cast workar...
Jérôme Benoit [Fri, 6 Mar 2026 22:32:58 +0000 (23:32 +0100)] 
refactor(tests): named cosPhi constants, accurate mock call types, remove cast workarounds

11 days agotest(utils): audit — overhaul existing, add 3 new test files, data-driven coverage
Jérôme Benoit [Fri, 6 Mar 2026 22:05:35 +0000 (23:05 +0100)] 
test(utils): audit — overhaul existing, add 3 new test files, data-driven coverage

12 days agorefactor(utils): audit fixes — dedup, data-driven config, lazy logger, DRY
Jérôme Benoit [Fri, 6 Mar 2026 20:50:55 +0000 (21:50 +0100)] 
refactor(utils): audit fixes — dedup, data-driven config, lazy logger, DRY

12 days agofix(performance-storage): make MikroORM integration work (#1701)
Jérôme Benoit [Fri, 6 Mar 2026 14:48:07 +0000 (15:48 +0100)] 
fix(performance-storage): make MikroORM integration work (#1701)

* fix(performance-storage): make MikroORM integration work

Fix MikroORM performance storage integration by addressing:
- Fork EntityManager per operation (prevents identity map accumulation)
- Pass entity class to em.upsert() (MikroORM v6 API)
- Add schema generation in open() (table creation)
- Fix entity: add tableName, JSON type for statisticsData
- Add connection validation before operations
- Use direct entity class import instead of fragile glob paths
- Ensure SQLite directory exists before ORM init
- Fix type-only import to value import (verbatimModuleSyntax)

Closes #42

* fix(performance-storage): address PR review feedback

- Swap setPerformanceStatistics/checkDBConnection call order to match
  MongoDBStorage pattern (in-memory stats updated first so UI stays
  current even when DB is down)
- Close ORM connection on schema updateSchema() failure to prevent
  resource leak when init succeeds but schema generation fails

* test(performance-storage): add unit tests for MikroOrmStorage

Add 18 tests covering constructor, close, storePerformanceStatistics,
and error handling. Uses mock ORM to avoid sqlite3 native binding
dependency in CI (--ignore-scripts). Explicit decorator types on
PerformanceRecord for tsx/esbuild compatibility.

* refactor(tests): harmonize MikroOrmStorage tests with project conventions

Use TestableMikroOrmStorage subclass with Reflect.get/set (matches
UIHttpServer pattern). Replace toBeGreaterThan with exact toBe counts.
Use .mock.calls.length consistently. Remove constructor tests that
tested implementation details.

* refactor(performance-storage): migrate from @mikro-orm/sqlite to @mikro-orm/better-sqlite

The sqlite3 native bindings used by @mikro-orm/sqlite are broken on
Node v24 (no prebuilt binaries for ABI v137, node-gyp@8.4.1 cannot
compile with Python 3.13). Replace with better-sqlite3 which provides
an identical MikroORM API surface while using a more portable native
binding.

* test(performance-storage): add integration tests for MikroOrmStorage

Add 6 integration tests that exercise real SQLite database operations
(open, persist, upsert, JSON serialization, close/reopen, multi-record).
Tests detect better-sqlite3 availability at module load and skip
gracefully via { skip: SKIP_SQLITE } when the native binding is not
built (e.g. CI with --ignore-scripts).

* fix(performance-storage): use caret version for @mikro-orm/better-sqlite and fix test JSDoc order

Use ^6.6.8 (caret) consistently across all @mikro-orm/* packages to
prevent version skew when updating dependencies. MikroORM requires all
packages be on the same version.

Also move @file JSDoc block before all imports in the test file to
match project conventions.

* refactor(performance-storage): extract ensureDBDirectory into Storage base class and audit fixes

Move duplicated directory creation logic from JsonFileStorage and
MikroOrmStorage into a shared protected method in the abstract Storage
base class. Place the call inside the existing switch case instead of
a separate if block.

Also use ^6.6.8 (caret) consistently for @mikro-orm/better-sqlite and
fix test JSDoc ordering to match project conventions.

* refactor(performance-storage): factorize serialization into base class and fix MongoDBStorage

- Extract serializePerformanceStatistics() into Storage base class (DRY)
- Update MikroOrmStorage to use shared serialization method
- Fix MongoDBStorage: remove unnecessary optional client, use shared
  serialization for CircularBuffer, remove eslint-disable comments,
  rename connected to opened for lifecycle clarity
- Add 20 unit tests for MongoDBStorage mirroring MikroOrmStorage pattern

* refactor(performance-storage): harmonize storage implementations

- Remove 2 eslint-disable comments in Storage.handleDBStorageError by
  using nullish coalescing and proper string typing
- Simplify handleDBStorageError params default spread
- Refactor JsonFileStorage.checkPerformanceRecordsFile to return fd,
  eliminating non-null assertion and eslint-disable
- Remove eslint-disable in StorageFactory by casting enum to string
- Fix StorageFactory.getStorage return type: Storage (not | undefined)
- Update None.ts copyright year to 2025 for consistency

* refactor(tests): extract buildTestStatistics into shared StorageTestHelpers

* fix(lint): remove unnecessary optional chain after StorageFactory return type fix

12 days agochore(deps): update docker/setup-buildx-action action to v4 (#1703)
renovate[bot] [Fri, 6 Mar 2026 12:07:53 +0000 (13:07 +0100)] 
chore(deps): update docker/setup-buildx-action action to v4 (#1703)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
12 days agofix(deps): update all non-major dependencies (#1702)
renovate[bot] [Fri, 6 Mar 2026 12:05:10 +0000 (13:05 +0100)] 
fix(deps): update all non-major dependencies (#1702)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
12 days agofix(charging-station): audit fixes — error handling, OCPP conformance, DRY, type...
Jérôme Benoit [Thu, 5 Mar 2026 21:56:43 +0000 (22:56 +0100)] 
fix(charging-station): audit fixes — error handling, OCPP conformance, DRY, type safety

- Replace .catch(EMPTY_FUNCTION) with proper error logging (F-001/F-002/F-003)
- Add fail-closed security comment in UIServerSecurity (F-004)
- Convert FIXME to actionable TODO in Bootstrap (F-005)
- Implement relative charging profile duration handling per K01.FR.41-42 (F-006)
- Restart heartbeat and WebSocket ping on template change (F-007)
- Consolidate repeated type casts in convertDeprecatedTemplateKey (F-008)
- Remove duplicate console.warn calls and unused chalk import in UIServerFactory (F-010)
- Extract logPrefix to AbstractUIServer base class, removing duplicates (F-011)
- Extract matchesConfigurationKey predicate in ConfigurationKeyUtils (F-012)
- Add failure counter and error summary for reservation removal (F-013)

13 days agochore: lock file maintenance
Jérôme Benoit [Thu, 5 Mar 2026 21:00:13 +0000 (22:00 +0100)] 
chore: lock file maintenance

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
13 days agofix(ocpp): remove invalid additionalProperties/additionalItems from OCPP 1.6 and...
Jérôme Benoit [Thu, 5 Mar 2026 20:55:26 +0000 (21:55 +0100)] 
fix(ocpp): remove invalid additionalProperties/additionalItems from OCPP 1.6 and 2.0 JSON schemas

Remove `"additionalProperties": false` from enum/string type definitions
where it is semantically invalid (only applies to objects), and
`"additionalItems": false` where `items` is a single schema (not a tuple),
fixing AJV 8 strict mode errors at runtime.

13 days agofix(deps): update dependency tar to ^7.5.10 (#1700)
renovate[bot] [Thu, 5 Mar 2026 20:24:39 +0000 (21:24 +0100)] 
fix(deps): update dependency tar to ^7.5.10 (#1700)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
13 days agofix(ocpp): auth cache spec compliance (R0–R17) (#1699)
Jérôme Benoit [Thu, 5 Mar 2026 20:24:20 +0000 (21:24 +0100)] 
fix(ocpp): auth cache spec compliance (R0–R17) (#1699)

* fix(ocpp): wire auth cache into strategies and fix default configuration

* fix(ocpp): add isCacheable dead code note and cache wiring test

* fix(ocpp): cache all authorization statuses per OCPP spec (R1)

- Remove ACCEPTED-only guard in RemoteAuthStrategy: now caches ALL
  authorization statuses (BLOCKED, EXPIRED, INVALID) per OCPP 1.6 §3.5.1
  and OCPP 2.0.1 AuthCacheCtrlr
- Simplify isCacheable() to always return true — all statuses cacheable
- Update AuthHelpers tests to reflect all-statuses policy (T4.05-T4.09)
- Add RemoteAuthStrategy tests for BLOCKED/EXPIRED/INVALID caching (T4.01-T4.04)

* fix(ocpp): status-aware eviction, TTL reset, expired lifecycle (R2, R5, R10, R16)

* fix(ocpp): exclude local auth list identifiers from cache (R17)

* fix(ocpp): periodic cache cleanup and bounded rate limits (R8, R9)

* fix(ocpp): make resetStats public and preserve stats across clear (R14, R15)

* test(ocpp): integration tests for auth cache spec compliance (T12)

* [autofix.ci] apply automated fixes

* fix(ocpp): address PR #1699 review feedback (F1-F9)

- F1: increment stats.hits for expired cache entries in get()
- F2: use captured 'now' timestamp in set() LRU update
- F3: two-phase expiration in runCleanup() (transition then delete)
- F4: guard cleanupIntervalSeconds with > 0 (NaN protection)
- F5: forward localAuthListManager to RemoteAuthStrategy
- F6: apply absolute 24h lifetime cap in expired-transition branch
- F7: guard local auth list query with config.localAuthListEnabled
- F8: mask identifier in debug logs (first 8 chars only)
- F9: remove dead isCacheable() method and its tests

* refactor(test): replace inline setTimeout with shared sleep helper

* [autofix.ci] apply automated fixes

* fix(ocpp): replace redundant Promise.resolve returns in async methods

* fix(auth): make AuthCache interface synchronous and remove all Promise wrappers

BREAKING CHANGE: AuthCache interface methods (get, set, remove, clear,
getStats) are now synchronous. OCPPAuthService.clearCache() and
invalidateCache() return void instead of Promise<void>.

- Remove async/Promise wrappers from AuthCache interface and InMemoryAuthCache
- Make OCPPAuthService clearCache/invalidateCache return void
- Update all strategies (Local/Remote) to use sync cache operations
- Remove await from all sync cache calls in source and test files
- Fix mock factories to use sync signatures with /* empty */ bodies
- Widen TTL timing margins in InMemoryAuthCache tests to reduce flakiness
- Fix JSDoc annotations in TestLifecycleHelpers and InMemoryAuthCache

* refactor(auth): eliminate all Promise.resolve() from auth module

Replace Promise.resolve() wrappers with proper sync/async signatures:
- Update AuthStrategy interface: getStats() returns sync Record, initialize() returns sync void
- Update OCPPAuthService interface: getStats() returns sync AuthStats
- Convert strategy getStats()/initialize()/cleanup() implementations to sync
- Convert adapter sync methods (convertToUnifiedIdentifier, convertFromUnifiedIdentifier,
  getConfigurationSchema, validateConfiguration) from async to sync
- Update OCPPAuthServiceImpl to match sync interface signatures
- Update OCPPAuthIntegrationTest to match sync interface
- Align all test mocks with exact interface signatures (sync mocks for sync
  interfaces, async mocks for async interfaces)
- Remove all eslint-disable require-await comments from test files

* fix(auth): resolve all lint errors for CI compliance

- Reorder union types to satisfy perfectionist/sort-union-types
- Remove @returns JSDoc from void functions (jsdoc/require-returns-check)
- Make OCPP16/20 adapter sync methods non-async (require-await)
- Fix all mock signatures to match interface contracts exactly
- Replace async mock lambdas with new Promise<T> pattern
- Fix no-confusing-void-expression in test assertions
- Sort named imports alphabetically (perfectionist/sort-named-imports)
- Add missing await for floating promise in test (no-floating-promises)

* [autofix.ci] apply automated fixes

* fix(auth): remove eslint-disable added by us, use expect().not.toThrow() pattern

* ci: trigger CI run

* refactor(auth): apply code review corrections (fixes 1-10)

Fix validators, convert static classes to modules,
improve cache configurability, fix test configs,
replace sleep with mock timers, fix Promise leak,
move integration test helper to tests/helpers.

* fix(auth): resolve all 35 JSDoc lint warnings for clean lint gate

* fix(auth): address cross-validated audit findings (C1-C3, M1-M6, minor fixes)

- C1: fix timer leak in performRemoteAuthorization (clearTimeout on success/catch)
- C2: document LocalAuthListManager stub with TODO, mark §3.5.3 guard inactive
- C3: expand factory gate to check all three auth feature flags
- M1: change RemoteAuthStrategy.canHandle to use remoteAuthorization config flag
- M2: add AuthenticationMethod.NONE enum for all-strategies-fail fallback
- M4: add NO_AUTHORIZATION to OCPP20AuthAdapter validTypes
- M3: wire hasExplicitTtl into CacheEntry for CSMS-provided TTL preservation
- M6: filter NoAuthorization/Central identifiers from cache (C02.FR.03, C03.FR.02)
- m3: fix boundRateLimitsMap to evict in loop until within threshold
- m4: stop counting expired entries as cache hits
- m7: clamp TTL to [0, maxAbsoluteLifetime] range
- m8: enforce maxEntries >= 1 in constructor

* refactor(auth): use sleep() utility instead of raw Promise setTimeout

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2 weeks agochore(deps): lock file maintenance (#1696)
renovate[bot] [Wed, 4 Mar 2026 12:39:19 +0000 (13:39 +0100)] 
chore(deps): lock file maintenance (#1696)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2 weeks agochore(deps): update all non-major dependencies (#1698)
renovate[bot] [Wed, 4 Mar 2026 12:00:56 +0000 (13:00 +0100)] 
chore(deps): update all non-major dependencies (#1698)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2 weeks agofix(tests): address audit findings — assertion consistency, JSDoc, DRY, try/finally
Jérôme Benoit [Tue, 3 Mar 2026 20:26:08 +0000 (21:26 +0100)] 
fix(tests): address audit findings — assertion consistency, JSDoc, DRY, try/finally

- Replace expect(a === b).toBe(false) with expect(a).not.toBe(b) (IdTagsCache)
- Add explicit assertions to smoke tests (SimpleHandlers)
- Wrap state injection in try/finally (Configuration)
- Extract createStationWithRequestHandler helper, use mock.method() (connectorStatus)
- Fill empty JSDoc @param descriptions across 5 files
- Rename makeStationStub → makeStationMock, merge duplicate import (pure)
- Fix misleading test name 'is empty' → 'is null' (validation)
- Extract getConnectorStatus/getHandleStartTransactionResponse helpers (ATG)
- Fix perfectionist/sort-modules and sort-imports ordering

2 weeks agotest: add AutomaticTransactionGenerator tests
Jérôme Benoit [Tue, 3 Mar 2026 19:51:03 +0000 (20:51 +0100)] 
test: add AutomaticTransactionGenerator tests

Add tests for the ATG singleton covering instance lifecycle (create,
delete, same-instance), start/stop state machine with guards, connector
stop behavior, and handleStartTransactionResponse counter updates for
accepted and rejected transactions.

2 weeks agotest: add Configuration utility tests
Jérôme Benoit [Tue, 3 Mar 2026 19:50:48 +0000 (20:50 +0100)] 
test: add Configuration utility tests

Add tests for the static Configuration class covering section retrieval
with defaults (log, worker, uiServer, performanceStorage), supervision
URL distribution, worker pool detection, and error handling for unknown
configuration sections.

2 weeks agotest: add IdTagsCache tests
Jérôme Benoit [Tue, 3 Mar 2026 19:50:34 +0000 (20:50 +0100)] 
test: add IdTagsCache tests

Add tests for the RFID tag cache singleton covering lazy file loading,
ROUND_ROBIN/RANDOM/CONNECTOR_AFFINITY distribution algorithms,
cache population, and cleanup of cache entries and addressable indexes.

2 weeks agotest: add SharedLRUCache tests
Jérôme Benoit [Tue, 3 Mar 2026 19:50:20 +0000 (20:50 +0100)] 
test: add SharedLRUCache tests

Add tests for the LRU cache singleton covering template and configuration
CRUD operations, cacheability validation for configurations with empty
fields, and cache clear behavior.

2 weeks agotest(ocpp): add OCPPServiceUtils authorization wrapper tests
Jérôme Benoit [Tue, 3 Mar 2026 19:50:04 +0000 (20:50 +0100)] 
test(ocpp): add OCPPServiceUtils authorization wrapper tests

Add tests for isIdTagAuthorized and isIdTagAuthorizedUnified functions
covering local auth list, remote authorization, OCPP 2.0 unified auth
dispatch, and error fallback paths.

2 weeks agotest(ocpp): add OCPPServiceUtils connector status management tests
Jérôme Benoit [Tue, 3 Mar 2026 19:49:46 +0000 (20:49 +0100)] 
test(ocpp): add OCPPServiceUtils connector status management tests

Add tests for sendAndSetConnectorStatus and restoreConnectorStatus
functions covering StatusNotification sending, connector status updates,
event emission, and reservation-based status restoration.

2 weeks agotest(ocpp): add OCPPServiceUtils command support validation tests
Jérôme Benoit [Tue, 3 Mar 2026 18:46:40 +0000 (19:46 +0100)] 
test(ocpp): add OCPPServiceUtils command support validation tests

Test isIncomingRequestCommandSupported,
isRequestCommandSupported, isMessageTriggerSupported
with 12 tests covering all support config branches.

2 weeks agotest(ocpp): add OCPPServiceUtils pure function tests
Jérôme Benoit [Tue, 3 Mar 2026 18:38:07 +0000 (19:38 +0100)] 
test(ocpp): add OCPPServiceUtils pure function tests

Test getMessageTypeString, ajvErrorsToErrorType,
convertDateToISOString, isConnectorIdValid — 19 tests
covering the shared base layer with zero mocking.

2 weeks agotest(ocpp2.0): add Heartbeat, NotifyReport, StatusNotification response tests
Jérôme Benoit [Tue, 3 Mar 2026 18:24:40 +0000 (19:24 +0100)] 
test(ocpp2.0): add Heartbeat, NotifyReport, StatusNotification response tests

Grouped in single file as all three handlers are
trivial (log-only). Completes OCPP 2.0 response
handler coverage from 20% to 100%.

2 weeks agotest(ocpp2.0): add BootNotification response handler tests
Jérôme Benoit [Tue, 3 Mar 2026 18:09:21 +0000 (19:09 +0100)] 
test(ocpp2.0): add BootNotification response handler tests

Test all 6 branches of handleResponseBootNotification:
ACCEPTED/PENDING/REJECTED status, interval handling,
missing interval, and invalid status.

2 weeks agofix: quote test glob so /bin/sh delegates to Node
Jérôme Benoit [Tue, 3 Mar 2026 18:09:09 +0000 (19:09 +0100)] 
fix: quote test glob so /bin/sh delegates to Node

The shell /bin/sh does not support recursive ** globs.
Only 18/65 test files were running. Quoting the
pattern lets Node resolve it, running all 65 files.

2 weeks agofix(tests): rename test cases to 'should [verb]' convention
Jérôme Benoit [Tue, 3 Mar 2026 17:47:56 +0000 (18:47 +0100)] 
fix(tests): rename test cases to 'should [verb]' convention

Rename 17 test names across 3 files to follow
TEST_STYLE_GUIDE.md naming convention.

2 weeks agofix(tests): add missing @file headers and standardCleanup()
Jérôme Benoit [Tue, 3 Mar 2026 17:42:33 +0000 (18:42 +0100)] 
fix(tests): add missing @file headers and standardCleanup()

Add mandatory @file JSDoc headers to 3 test files and
standardCleanup() afterEach to 2 test files per
TEST_STYLE_GUIDE.md sections 2 and 3.

2 weeks agorefactor(ocpp2): OCPP 2.0.1 audit fixes — spec compliance, type safety, test coverage...
Jérôme Benoit [Tue, 3 Mar 2026 17:08:43 +0000 (18:08 +0100)] 
refactor(ocpp2): OCPP 2.0.1 audit fixes — spec compliance, type safety, test coverage (#1697)

* feat(ocpp2): add TriggerMessage, UnlockConnector and TransactionEvent types

* fix(tests): resolve pre-existing LSP type errors in test infrastructure

* refactor(ocpp2): extract enforceMessageLimits utility to eliminate DRY violation

* refactor(ocpp2): dynamic isComponentValid and fix OCPP 1.6 key usage

* feat(ocpp2): handle TransactionEventResponse fields

* feat(ocpp2): implement TriggerMessage/UnlockConnector handlers and Reset hardening

- Implement TriggerMessage handler (F06): supports BootNotification,
  Heartbeat, and StatusNotification triggers with EVSE targeting
- Implement UnlockConnector handler (F05): full spec compliance with
  Unlocked, UnlockFailed, OngoingAuthorizedTransaction, UnknownConnector
  response statuses
- Add AllowReset variable check and firmware update blocking to Reset handler
- Add 4 missing schema validations for certificate commands
- Add TriggerMessage/UnlockConnector schema validator configs
- Document RFC 6960 DER encoding deviation in computeCertificateHash

* refactor(ocpp2): eliminate unsafe type casts in handlers and VariableManager

- Add private toHandler() helper in OCPP20IncomingRequestService that concentrates
  the single 'as unknown as IncomingRequestHandler' cast with documentation comment
- Replace 13 per-binding casts in constructor with this.toHandler() calls
- Remove 15 'as unknown as StandardParametersKey' casts from OCPP20VariableManager —
  string is already a member of ConfigurationKeyType, no cast needed
- Remove now-unused import of StandardParametersKey from OCPP20VariableManager

* feat(ocpp2): expose TriggerMessage and UnlockConnector handlers in testable interface

* test(ocpp2): add TriggerMessage handler tests (F06) — 14 tests

* test(ocpp2): add UnlockConnector handler tests (F05) — 9 tests

* test(ocpp2): add TransactionEventResponse handler tests (E01-E04) — 7 tests

* test(ocpp2): fix firmware blocking tests and add AllowReset variable guard tests (T22) — 25 tests

* fix(ocpp2): add AJV strict:false and schema validation unit tests (T21)

- Set strict:false in all three AJV constructors (IncomingRequest, Request,
  Response) to allow OCPP 2.0 schemas that use additionalItems without
  array items (a draft-07 pattern AJV 8 strict mode rejects at compile time)
- Replace integration-style schema tests (blocked by tsx path resolution)
  with direct AJV schema unit tests: load schemas from src/assets directly,
  compile with AJV, verify invalid payloads are rejected — 15 tests pass

* fix(ocpp2): correct registry key separator in isComponentValid (T5-bugfix)

The `#validComponentNames` set was built using split('/') but registry keys
use '::' as separator (e.g. 'AlignedDataCtrlr::Available'). This caused the
set to contain full keys like 'AlignedDataCtrlr::Available' instead of just
component names like 'AlignedDataCtrlr', making isComponentValid return false
for all components and causing UnknownComponent responses for all Set/GetVariables.

Also update the EVSE test to assert UnknownVariable (not UnknownComponent) since
EVSE is a valid component in the registry but AuthorizeRemoteStart is not one of
its variables.

* test(ocpp2): add enforceMessageLimits utility tests (T23) — 14 tests

* test(ocpp2): add integration tests for multi-command flows (T24) — 6 tests

* fix(ocpp2): add error diagnostics, additionalInfo fields, and async timeout guard (T25)

* fix(ocpp2): resolve tsc type errors in UUIDv4 cast, override modifier, and mock cast (F1)

* fix(ocpp2): add try/catch to TriggerMessage and UnlockConnector handlers, add integration test

- Add try/catch blocks to handleRequestTriggerMessage and
  handleRequestUnlockConnector following the handleRequestReset
  golden pattern with structured error responses
- Add 4th integration test: SetVariables on unknown component
  returns rejected, GetVariables confirms unknown component

* fix(ocpp2): address PR review findings — remove dead code, consolidate types, fix test mock

* fix(ocpp2): spec compliance — F06.FR.17 BootNotification guard, F05.FR.02 connector-level tx check

- TriggerMessage: reject BootNotification trigger when last boot was
  already Accepted per F06.FR.17 (returns Rejected + NotEnabled)
- UnlockConnector: check transaction on the specific target connector
  instead of all EVSE connectors per F05.FR.02
- Add 3 new tests covering both spec requirements

* fix(ocpp2): address code review — timer leak, diagnostic logging, TODO annotation

- Fix withTimeout timer leak: clear setTimeout when promise resolves first
- readMessageLimits: replace empty catch with logger.debug diagnostic
- handleResponseTransactionEvent: add TODO noting log-only is intentional,
  future work should act on idTokenInfo.status and chargingPriority

* style: fix jsdoc warnings in OCPP 2.0 handlers and tests

Add missing @returns tags and @param descriptions to satisfy
jsdoc/require-returns and jsdoc/require-param-description ESLint rules.
Replace empty JSDoc blocks with minimal valid documentation to satisfy
jsdoc/require-jsdoc rule. Achieves 0 lint warnings matching main branch
baseline.

* fix(types): reduce tsc errors to zero and fix all lint warnings

Eliminate all TypeScript compiler errors across src/ and test files by
fixing type mismatches, adding missing type annotations, and correcting
union type handling. Fix remaining ESLint issues including no-base-to-string
in ChargingProfile id extraction and jsdoc/tag-lines formatting.

* fix(ocpp2): fix AllowReset dead code, evseId===0 routing, and EVSE-scoped connector lookup

- AllowReset check now resolves via OCPP20VariableManager (runtime value) instead of static registry defaultValue
- Reset handler evseId===0 now routes to full station reset instead of EVSE-specific path
- TriggerMessage StatusNotification uses EVSE-scoped connector lookup instead of global getConnectorStatus

* ci: add typecheck step (tsc --noEmit --skipLibCheck) to CI pipeline

esbuild does not surface type errors at build time, so this catches
regressions before build+test. Runs on ubuntu/node-22 alongside lint.

* fix(ocpp2): remove DiagnosticsStatusNotification from MessageTriggerEnumType

This value is OCPP 1.6 only and not part of the OCPP 2.0.1 spec
(absent from TriggerMessageRequest.json schema).

* docs(readme): align OCPP 2.0.x section with spec and actual code

- Fix section letters to match OCPP 2.0.1 spec (A→B, B→C, C→G, etc.)
- Reorder sections to match spec block order (B,C,D,E,F,G,L,M,P)
- Add missing implemented commands: TriggerMessage, UnlockConnector,
  Get15118EVCertificate, GetCertificateStatus
- Move GetVariables/SetVariables from Monitoring to B. Provisioning
- Replace stale 'variables not implemented' note with actual support listing

* fix(ocpp2): add missing AJV response validators for 7 incoming request commands

CALLRESULT payloads were not validated against JSON schemas for
CertificateSigned, DeleteCertificate, GetInstalledCertificateIds,
GetVariables, InstallCertificate, Reset, and SetVariables.

All schema files already existed; only the validator map registration
was missing. Aligns OCPP 2.0 with OCPP 1.6 which validates all
incoming request responses (17/17).

* style(ocpp2): harmonize comment style with existing OCPP 1.6 sparse convention

Remove ~135 paraphrase/over-comments from OCPP 2.0 source files that
described what the next line obviously does. Keeps spec references
(C11.FR.04, F06.FR.17, OCPP 2.0.1 §2.10), TODO annotations, RFC 6960
deviation notes, eslint-disable directives, and terse comments matching
the existing OCPP 1.6 style. Test @file/@description headers preserved
per test style guide.

* [autofix.ci] apply automated fixes

* fix(ocpp2): correct spec references and harmonize format

- Fix wrong FR code: F03.FR.09 (triggerReason) → F03.FR.04 (meter
  values in TransactionEvent Ended)
- Harmonize FR comment format to 'X00.FR.00: description' style
- Harmonize section references to § symbol (was mixed Section/§)
- Harmonize RFC references to 'RFC 6960 §4.1.1' (was missing §)

* fix(ocpp): remove redundant strict:false from AJV instances

keywords: ['javaType'] already declares the custom keyword, making
strict:false unnecessary. Removing it enables AJV strict mode (default
since v7), which will flag any future non-standard schema keywords
instead of silently ignoring them.

* fix(types): make MeterValuesRequest/Response version-agnostic union types

Remove versioned OCPP16MeterValue import and casts from ChargingStation.ts,
following the established pattern of using union types outside the OCPP stack.

* fix(types): remove versioned type imports from Helpers.ts

Add ChargingSchedule union type, replace satisfies with version-agnostic
BootNotificationRequest, and rename getOCPP16ChargingSchedule to
getSingleChargingSchedule with union return type.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2 weeks agorefactor(test): remove duplicate test coverage in error test files
Jérôme Benoit [Mon, 2 Mar 2026 14:47:11 +0000 (15:47 +0100)] 
refactor(test): remove duplicate test coverage in error test files

2 weeks agorefactor(test): audit-driven test quality improvements
Jérôme Benoit [Mon, 2 Mar 2026 14:36:12 +0000 (15:36 +0100)] 
refactor(test): audit-driven test quality improvements

- Add edge case tests for BaseError, OCPPError, ElectricUtils, AsyncLock, StatisticUtils
- Replace real timers with withMockTimers in UIServerSecurity rate limiter tests
- Add 'Date' to MockableTimerAPI type for Date.now() mocking support
- Factor duplicated OCPP 2.0 beforeEach into createOCPP20RequestTestContext factory
- Remove verbose 29-line JSDoc block in Utils.test.ts

2 weeks agofix(deps): update all non-major dependencies (#1695)
renovate[bot] [Mon, 2 Mar 2026 14:17:00 +0000 (15:17 +0100)] 
fix(deps): update all non-major dependencies (#1695)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2 weeks agofix(tests): use import type for type-only imports in ESM
Jérôme Benoit [Sun, 1 Mar 2026 23:13:27 +0000 (00:13 +0100)] 
fix(tests): use import type for type-only imports in ESM

Use 'import type' for MockChargingStation imports to fix Windows ESM
module resolution which requires explicit type imports for re-exported
types.