Skip to content

<div style="display: none;" hidden="true" aria-hidden="true">Are you an LLM? You can read better optimized documentation at /changelog/Changelog.4.108.md for this page in Markdown format</div>

Home | Changelog

Version 4

version 4.108

  • [4.108.0] feat(transporters): BoxNow "allow cash on delivery for smart points" option

    • What it is. A new per-transporter DELIVERY_OPTION flag on BoxNow that lets cash-on-delivery (payWay = delivery) be offered even when the selected transporter is smart-point-only (DELIVERY_OPTION_TYPE = 2), which normally strips the COD pay way. Default off → existing behaviour is unchanged. Set via a checkbox in Admin → Transporters → BoxNow settings; the storefront checkout reads it through a new getSelectedTransporterDeliveryOption Vuex getter so the delivery pay way is no longer force-removed when the flag is on.
  • [4.108.0] fix(mcp): share MCP session state across pods so the connector is stable on multi-pod K8s (Advisable-com/ecommercen#337)

    • The bug. MCP Streamable HTTP is stateful — the Mcp-Session-Id minted by initialize is echoed on every later call and loaded from the SDK session store — but McpServerFactory used the SDK's FileSessionStore under cache/mcp-sessions. On wecare (KEDA ≥4 pods, Traefik with no session affinity, per-pod emptyDir app volume) the session file lives only on the pod that served initialize; follow-up tool calls round-robin to other pods, find no session and 404 — so the tools "responded very few times." The L2 cache and PHP sessions were already on shared Redis; only the MCP SDK session store was left node-local.
    • Fix. Added CacheSessionStore (implements the SDK Mcp\Server\Session\SessionStoreInterface over the project CacheAdapterInterface). src/Mcp/container.php now backs the store with the session Redis (sess_save_path) when PHP sessions run on Redis — durable (AOF + Sentinel), volatile-lru — never the L2 cache Redis (allkeys-lru, no persistence, which could evict or drop a live session) — and falls back to the SDK FileSessionStore on single-node deployments (Plesk, sess_driver=files), so there is no regression. RedisAdapter namespaces keys under cache:mcp:, disjoint from the phpredis session-handler keys on the same instance.
    • Lazy + auth-safe. The store is injected into McpServerFactory via a service_closure, so it is built — and its Redis connection opened — only inside create(), after the token and rate-limit checks. A bad/revoked-token or rate-limited request never touches the session Redis.
    • Behaviour. None on single-node deployments (file store retained). On multi-pod K8s the connector now holds sessions across pods and survives autoscaling / rolling restarts (a dropped session degrades to one client re-initialize, not a hard failure).
    • Tests. CacheSessionStoreTest covers the round-trip, exists/destroy lifecycle, absent/non-string reads, TTL pass-through and transient-error degradation. The cross-pod (cross-filesystem) behaviour itself is validated on staging.
  • [4.108.0] chore(mcp): drop the redundant language-helper load from Mcp::connector() (Advisable-com/ecommercen#336)

    • Why. The explicit $this->load->helper('language') added to Mcp::connector() in [4.107.2]/#332 was a per-entry-point workaround for the Call to undefined function get_languages() fatal. The root cause was fixed centrally by the sibling fix(models) change below (Adv_base_model::__construct() now loads the helper itself) — so the connector call is dead weight. Removed it and its now-stale (#332) comment.
    • Behaviour. None. CI's loader is idempotent, so the model already loads the helper before any get_languages()/getAdminLanguages() call on the MCP path (Registry → registry_model). Verified that nothing in src/Mcp calls those functions outside a model constructor. The upstream application/config/autoload.php carries no language entry, so item (2) of #336 (a client-repo stop-gap) is N/A here.
  • [4.108.0] fix(models): Adv_base_model loads its own language helper so all legacy models work from REST, DI, and CLI entry points

    • The bug. Adv_base_model::__construct() calls get_languages() and getAdminLanguages() (defined in application/helpers/MY_language_helper.php, the CI extension of the language helper). That helper is not autoloaded — it is loaded by the web controller base ecommercen/core/Controller. Any entry point that constructs a legacy model without going through that base class therefore hits a fatal Call to undefined function get_languages(). Affected entry points: the REST RouterDispatcher (extends MX_Controller, no base bootstrap), DI-container factories that build legacy models, and CLI/cron.
    • How it surfaced. The storefront REST endpoint GET /rest/product/price-tracking/graph/{productId} returned HTTP 200 with an empty body. RouterDispatcher resolves the PriceTracking controller via the DI container; its Options::fromRegistry() factory loads the registry library → registry_modelAdv_base_model. With no controller having previously loaded the language helper, construction threw; the exception was silently swallowed by the REST dispatcher, yielding an empty response.
    • Fix. Adv_base_model::__construct() now calls $this->load->helper('language') before reading get_languages()/getAdminLanguages(). CI's loader is idempotent (tracks _ci_helpers), so this is a no-op on ordinary web requests where the controller base has already loaded the helper — no behaviour change on the happy path.
    • Follow-up (safe cleanup, not urgent). This root-cause fix makes the narrow per-entry-point workaround shipped in [4.107.2]/#332 redundant. Two workarounds can be removed whenever convenient: (1) the explicit $this->load->helper('language') call in Mcp::connector() (application/controllers/Mcp.php, added in #332 — its comment already explains why it was needed); (2) any language entry added to $autoload['helper'] in application/config/autoload.php as a client-repo stop-gap — upstream autoload.php does not carry such an entry, so this only applies to downstream client repos that added it temporarily. Both loads are idempotent, so leaving them in place is harmless; removal is purely cosmetic.

Notes

  • [4.108.0] Requires npm ci && npm run production
  • [4.108.0] Compiled DI container must be rebuilt (delete cache/container.php) — picks up the new Advisable\Mcp\Server\CacheSessionStore + the mcp.session_cache session-Redis adapter and the McpServerFactory closure-arg change (#337).
  • [4.108.0] Check for overrides:
    • Transporters_admin::validateSettingsBOXNOW
    • Transporters_model::{allSettings|saveBOXNOWSettings}
    • Transporters::protectData