Skip to content

Add application version gating for firmware-specific APIs#18

Merged
chiconws merged 1 commit into
devfrom
add-application-version-gating
May 17, 2026
Merged

Add application version gating for firmware-specific APIs#18
chiconws merged 1 commit into
devfrom
add-application-version-gating

Conversation

@chiconws
Copy link
Copy Markdown
Collaborator

Summary

Adds reusable application-version gating for NanoKVM APIs that were introduced in specific firmware releases.

This follows the same general pattern as the existing hardware guard: methods can declare a minimum supported application version for non-Pro and/or Pro devices, and the client checks the detected device version before calling the endpoint.

This keeps firmware-specific API support centralized and predictable as upstream adds endpoints, avoiding scattered per-method fallback logic and unclear runtime failures on older devices.

Details

  • Adds cached application/image version state to NanoKVMClient.
  • Adds detect_versions() using /vm/info.
  • Adds read-only application_version and image_version properties.
  • Adds internal version parsing/comparison without adding a dependency.
  • Adds @require_application_version(non_pro=..., pro=...).
  • Applies version gates only where the upstream changelog clearly maps to existing public client methods.
  • Raises NanoKVMNotSupportedError before the feature endpoint is called when the detected version is too old.
  • Includes the device family in version-gate error messages, for example:
    • get_shortcuts requires Pro application version >= 1.2.8 (detected: 1.2.7)
    • get_shortcuts requires non-Pro application version >= 2.3.2 (detected: 2.3.1)

Decorator Examples

  • Shared method with different minimum versions for non-Pro and Pro:
@require_application_version(non_pro="2.3.2", pro="1.2.8")
async def get_shortcuts(self) -> GetShortcutsRsp:
    ...
  • Pro-only method gated by both hardware and application version:
@require_hardware(HWVersion.PRO)
@require_application_version(pro="1.2.7")
async def refresh_virtual_device(self, device: str) -> None:
    ...
  • Non-Pro-only version gate. Pro devices are allowed through because no Pro minimum is declared:
@require_application_version(non_pro="2.2.6")
async def get_hostname(self) -> GetHostnameRsp:
    ...

Compatibility Notes

  • This is mostly additive, but it intentionally changes behavior for firmware-specific APIs on older devices. Instead of calling an endpoint that may not exist and surfacing a lower-level API/HTTP error, the client now raises NanoKVMNotSupportedError before the feature endpoint is called when the detected application version is below the known minimum.

  • Consumers that currently catch NanoKVMApiError for unsupported endpoints on older firmware may also need to catch NanoKVMNotSupportedError.

  • Unknown or custom versions such as dev are allowed through, so custom builds are not blocked.

  • The client also caches image_version from /vm/info for future compatibility checks, but this PR only gates by application version. Current endpoint availability is mapped to upstream application changelog entries, and no public client method is currently gated by image version.

Copy link
Copy Markdown
Owner

@puddly puddly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@chiconws
Copy link
Copy Markdown
Collaborator Author

Nice, thanks!
I'll merge it and then I'm gonna add a couple of new methods for the non-pro that were added in the last version (DNS management in 2.4.1) in a new PR so we can do a new version of the library with those as well.

@chiconws chiconws merged commit 7e975e8 into dev May 17, 2026
2 checks passed
@chiconws chiconws deleted the add-application-version-gating branch May 17, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants