English · Русский
MiraBox Stream Dock SDK
A typed Python SDK for building MiraBox Stream Dock plugins
Build reusable actions for keys, touch panels, and dials
without hand-writing the Stream Dock WebSocket protocol.
Quick start · PyPI · Example plugin · Protocol · API · Development
About
mirabox-stream-dock-sdk provides the protocol, runtime, and browser-side tools
needed to build Python plugins for MiraBox Stream Dock. It validates launch
arguments and incoming messages, creates one typed action instance per visible
control, dispatches lifecycle events, and serializes commands back to the
Stream Dock application.
The SDK was originally developed as part of a Stream Dock plugin. It was later extracted into a standalone project so the protocol and runtime could be reused across plugins, tested independently, and evolved as a public package. The SDK will continue to be improved as it is used in real plugins and more Stream Dock behavior is verified.
[!IMPORTANT] The project is currently in the
0.xseries. It is ready for experimentation and real plugin development, but public APIs may evolve between minor releases before1.0.
[!NOTE] This is an unofficial community project and is not affiliated with or endorsed by MiraBox, HotSpot, or Elgato. The callback name
connectElgatoStreamDeckSocketis retained because Stream Dock uses it for Property Inspector compatibility.
Table of contents
- Features
- How it works
- Requirements
- Installation
- Quick start
- Property Inspector client
- Counter example plugin
- Protocol basis
- API overview
- Errors and unknown events
- Inbound event queue
- Outbound command bus
- Concurrency contract
- Logging
- Project structure
- Development
- Releasing
Features
| Feature | What it provides | |
|---|---|---|
| 🧩 | Typed protocol | Dataclass models for registration, commands, and key, touch, dial, device, application, and settings events. |
| 🧭 | Precise validation | Malformed payloads report the event name and exact JSON field path that failed validation. |
| 🎛️ | Action runtime | One action instance per Stream Dock context, declarative UUID registration, and automatic lifecycle dispatch. |
| 🔌 | WebSocket transport | Registration, message parsing, command serialization, logging, and graceful shutdown. |
| 🗃️ | Typed settings | Pluggable codecs for action settings, global settings, and Property Inspector messages. |
| 🖥️ | Property Inspector | A versioned, dependency-free JavaScript client with connection state, events, settings helpers, and queued startup messages. |
| 🧰 | Plugin services | Start and stop plugin-owned background services in a predictable order. |
| 📦 | Distribution tooling | A CLI resource copier, PyInstaller example, package verification, CI, and Trusted Publishing workflow. |
| 🛡️ | Forward compatibility | Unknown but valid events can be preserved as UnknownStreamDockEvent instead of breaking the plugin. |
How it works
flowchart LR
App["MiraBox Stream Dock<br>Windows"] <-->|"WebSocket · JSON"| Connection["WebSocketStreamDockConnection"]
Connection --> Runtime["StreamDockPlugin<br>event dispatcher"]
Registry["ActionRegistry<br>UUID → Action class"] --> Runtime
Runtime --> Actions["Action instances<br>one per context"]
Runtime --> Services["Lifecycle services"]
PI["Property Inspector<br>HTML / JavaScript"] <-->|"settings and messages"| App
Client["MiraBoxPropertyInspector<br>browser client"] --> PI
Stream Dock starts the packaged plugin executable with the WebSocket port,
plugin UUID, registration event, and application metadata. run_plugin_cli()
parses those arguments, while StreamDockPlugin registers the plugin and maps
incoming events to the appropriate action instance.
Requirements
- Python
3.11+; - MiraBox Stream Dock
2.10.179.426or newer (declared minimum); websocket-client>=1.8,<2(installed automatically);- Windows to run Stream Dock and package a standalone plugin with PyInstaller.
The SDK's Stream Dock integration has been manually verified with Stream Dock
3.10.203.0701.
The SDK itself and its test suite can be developed on Windows, Linux, or WSL.
The final .exe must be built on Windows because PyInstaller is not a
cross-compiler.
Installation
Install the released package from PyPI:
python -m pip install mirabox-stream-dock-sdk
To work on the SDK from source:
git clone https://github.com/Nekit678/MiraboxStreamDockSDK.git
cd MiraboxStreamDockSDK
python -m venv .venv
Windows PowerShell
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
Linux / WSL
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
Quick start
Define dependencies shared by your action instances, register each action UUID,
and return a configured StreamDockPlugin from the application factory:
from __future__ import annotations
from dataclasses import dataclass
from mirabox_sdk import (
Action,
ActionRegistry,
JsonObject,
KeyDownEvent,
PluginLaunchArguments,
StreamDockPlugin,
StreamDockSender,
WebSocketStreamDockConnection,
WillAppearEvent,
run_plugin_cli,
)
ACTION_UUID = "com.example.counter.increment"
@dataclass(frozen=True, slots=True)
class Dependencies:
stream_dock: StreamDockSender
registry: ActionRegistry[Dependencies] = ActionRegistry()
@registry.register(ACTION_UUID)
class CounterAction(Action[JsonObject, Dependencies]):
def _render(self) -> None:
count = self.settings.get("count", 0)
self.set_title(str(count if type(count) is int else 0))
def on_will_appear(self, _event: WillAppearEvent) -> None:
self._render()
def on_key_down(self, _event: KeyDownEvent) -> None:
count = self.settings.get("count", 0)
self.set_settings({"count": (count if type(count) is int else 0) + 1})
self._render()
def build_application(arguments: PluginLaunchArguments) -> StreamDockPlugin[Dependencies]:
connection = WebSocketStreamDockConnection(arguments.port)
return StreamDockPlugin(
arguments,
stream_dock=connection,
action_registry=registry,
action_dependencies=Dependencies(connection),
)
if __name__ == "__main__":
raise SystemExit(run_plugin_cli(build_application))
The exact same action UUID must appear in the plugin's manifest.json. Stream
Dock creates and removes action contexts through willAppear and
willDisappear; the runtime manages the corresponding Python instances.
Action callbacks
Override only the callbacks an action needs:
| Input or lifecycle | Action callback |
|---|---|
| Action becomes visible or disappears | on_will_appear, on_will_disappear |
| Key press or release | on_key_down, on_key_up |
| Touch panel tap | on_touch_tap |
| Dial press, release, or rotation | on_dial_down, on_dial_up, on_dial_rotate |
| Settings or title parameters change | on_did_receive_settings, on_title_parameters_did_change |
| Property Inspector opens, closes, or sends data | on_property_inspector_did_appear, on_property_inspector_did_disappear, on_send_to_plugin |
| Device, application, and wake-up notifications | on_device_did_connect, on_device_did_disconnect, on_application_did_launch, on_application_did_terminate, on_system_did_wake_up |
Action helper methods cover the common outbound commands: set_title(),
set_image(), set_state(), set_settings(), get_settings(), show_ok(),
show_alert(), open_url(), log_message(), and
send_to_property_inspector(). Display-only updates also have non-blocking
set_title_async(), set_image_async(), and set_state_async() variants.
Typed settings
Actions use JSON objects by default. To work with an application-specific type,
provide a JsonCodec on the action class:
from dataclasses import dataclass
from mirabox_sdk import Action, FunctionalJsonCodec, JsonObject
@dataclass(frozen=True, slots=True)
class CounterSettings:
count: int
def decode_settings(value: JsonObject) -> CounterSettings:
count = value.get("count", 0)
if type(count) is not int:
raise ValueError("count must be an integer")
return CounterSettings(count)
COUNTER_SETTINGS_CODEC = FunctionalJsonCodec(
decoder=decode_settings,
encoder=lambda value: {"count": value.count},
)
class CounterAction(Action[CounterSettings, Dependencies]):
settings_codec = COUNTER_SETTINGS_CODEC
The codec boundary verifies that encoded values are valid JSON. Decode errors are wrapped with the relevant event name and settings path.
Global settings
Use update_global_settings() when several in-memory changes belong to one
logical operation. The callback works on an isolated draft; an exception or
invalid JSON result rolls back the complete update:
def append_items(settings: JsonObject) -> None:
items = settings.get("items")
if not isinstance(items, list):
raise ValueError("items must be a list")
items.extend(values)
runtime.update_global_settings(append_items)
After the callback succeeds, the transaction validates the complete draft and
persists it with one setGlobalSettings command. Callback, validation, and send
failures leave the previous local state unchanged. Direct mutations of
runtime.global_settings remain supported for local replay state, but the
transactional method is preferred for a batch of related persisted changes.
Property Inspector client
Copy the JavaScript client shipped with the installed SDK into the plugin bundle:
mirabox-sdk copy-property-inspector \
com.example.counter.sdPlugin/property-inspector
The command refuses to overwrite a different copy by default. Pass --force
when intentionally updating the bundled client.
Load it before the action-specific script:
<script src="mirabox-sdk.js"></script>
<script src="counter.js"></script>
Stream Dock invokes the compatibility callback automatically. The action script
uses the shared client through window.MiraBoxPropertyInspector:
const client = window.MiraBoxPropertyInspector;
client.on("connected", ({ settings }) => {
console.log("Current settings", settings);
});
client.on("didReceiveSettings", ({ payload }) => {
console.log("Updated settings", payload.settings);
});
client.sendToPlugin({ event: "refresh" });
client.updateSettings({ mode: "toggle" });
The client exposes on(), off(), send(), sendToPlugin(), setSettings(),
updateSettings(), and getSettings(), plus connection and registration state.
Messages sent while the WebSocket is connecting are queued until it opens.
Counter example plugin
examples/counter_plugin
is a complete plugin rather
than an isolated code fragment. It includes:
- a package with a registered counter action;
- a Property Inspector that can reset the counter;
- a valid
.sdPluginbundle and manifest; - SVG assets and a PyInstaller specification;
- tests for the plugin behavior.
Build its executable on Windows:
python -m pip install pyinstaller
python -m PyInstaller --clean --noconfirm examples/counter_plugin/build.spec
Copy-Item dist\CounterPlugin.exe `
examples\counter_plugin\com.example.counter.sdPlugin\
Copy the resulting com.example.counter.sdPlugin directory to
%APPDATA%\HotSpot\StreamDock\plugins\ and restart Stream Dock. See the
example guide
for a source-run command and
the complete packaging flow.
Protocol basis
This package is an independent, typed Python implementation of the WebSocket / JSON plugin API published by MiraBox. The primary upstream sources are:
- the official StreamDock Plugin SDK repository, including its Python template;
- the official registration procedure, received events, and events sent reference;
- the official
manifest.jsonreference and Property Inspector guide; - the upstream template overview on DeepWiki for secondary, generated explanations of the repository;
- the Space Platform for publishing completed Stream Dock plugins.
The local protocol map connects each supported wire event and command to its Python model or helper and calls out behavior verified in Stream Dock but not currently listed in the upstream event reference. When the published documentation and observed runtime behavior differ, tests record the behavior implemented by this SDK.
API overview
| Area | Public API |
|---|---|
| Runtime | Action, ActionRegistry, ActionStore, GlobalSettingsStore, StreamDockPlugin, LifecycleService |
| Connection | WebSocketStreamDockConnection, inbound/outbound queue metrics and errors, StreamDockConnection, StreamDockSender, StreamDockListener |
| Launch and registration | PluginLaunchArguments, registration dataclasses, parse_plugin_cli_arguments, run_plugin_cli |
| Input events | Typed models plus the read-only EVENT_REGISTRY describing parser, scope, callback, and stateful runtime handler |
| Output commands | Registration, settings, title, image, state, feedback, URL, log, and Property Inspector command models; ValidatedWireMessage |
| Application data | JsonCodec, FunctionalJsonCodec, JsonObjectCodec, ValidatedJsonObject, OwnedJsonPayload, typed encode/decode helpers |
| Resources | copy_property_inspector_client, property_inspector_client_bytes, mirabox-sdk CLI |
| Parsing | parse_stream_dock_event, parse_registration_info, typed protocol errors |
| Logging | configure_logging with isolated console, file, and disable controls |
The supported public surface is exported from mirabox_sdk. Objects from
individual modules should be treated as implementation details unless they are
also exported there.
Errors and unknown events
| Exception | Meaning |
|---|---|
InvalidPluginLaunchArgumentsError |
Stream Dock did not provide valid executable arguments. |
InvalidRegistrationInfoError |
The registration metadata JSON has an invalid field. |
MalformedEventError / InvalidFieldError |
A known event is malformed; the error includes its JSON path. |
UnsupportedEventError |
An unknown event was parsed with allow_unknown=False. |
JsonCodecDecodeError |
Plugin-owned settings or messages could not be decoded. |
JsonCodecEncodeError |
A codec produced a value that cannot be sent as JSON. |
OutboundQueueFullError |
The bounded outbound command queue is full. |
OutboundCommandBusClosedError |
A command was submitted after outbound shutdown began. |
By default, parse_stream_dock_event() preserves an unknown but structurally
valid envelope as UnknownStreamDockEvent. This lets the SDK tolerate protocol
extensions while known events remain strictly validated. The standard runtime
delivers each preserved event once to StreamDockPlugin.on_unhandled_event();
override that no-op hook in a plugin subclass to inspect or log new protocol
events. Unknown envelopes are not broadcast to actions because their routing
semantics are not known yet.
Known events are parsed and dispatched from the same read-only
EVENT_REGISTRY. Each EventDescriptor records the wire name, event model,
parser, EventScope, action callback, and any stateful runtime handler. Registry
validation fails during import if a StreamDockEventType member is missing, and
the test suite verifies that every callback and package-level event export
exists.
Inbound event queue
WebSocketStreamDockConnection parses frames in the WebSocket reader and puts
valid events into a bounded queue. A keyed-serial worker pool invokes plugin
callbacks: one action context remains strictly ordered, while different
contexts can make progress concurrently. willAppear, willDisappear,
broadcast, and unknown events are exclusive ordering barriers; each waits for
earlier context callbacks and completes before later callbacks start. On normal
connection shutdown, the queue drains before run_forever() returns and before
the runtime releases actions and services.
The pool defaults to four workers and the queue defaults to 1,024 events.
Lifecycle, settings, input, broadcast, unknown, and every other event except
dialRotate are lossless by default. dialRotate is explicitly coalescable
and may be discarded on overflow. Configure worker concurrency, the limit, and
overflow behavior for discardable events when constructing the connection:
from mirabox_sdk import InboundOverflowPolicy, WebSocketStreamDockConnection
connection = WebSocketStreamDockConnection(
arguments.port,
inbound_queue_limit=512,
inbound_worker_count=4,
overflow_policy=InboundOverflowPolicy.DROP_OLDEST,
coalesce_dial_rotations=True,
inbound_shutdown_timeout=5.0,
)
DROP_NEWEST (the default) discards the newest eligible dialRotate;
DROP_OLDEST discards the oldest eligible rotation. Neither policy may evict a
lossless event. If the queue contains only lossless events, another lossless
event applies backpressure to the WebSocket reader until the dispatcher frees
space; an incoming rotation is discarded instead. This keeps memory bounded
without allowing overflow to corrupt runtime state.
Rotation coalescing is opt-in: compatible pending dialRotate events for the
same context and pressed state are combined by summing ticks; an intervening
event for that context, or any broadcast/unknown event, prevents coalescing.
Read connection.inbound_queue_metrics for an atomic
InboundQueueMetrics snapshot. It reports current and peak depth, received,
enqueued, coalesced, backpressured, dispatched, dropped, and callback-failure
and callback-timeout counts. The default inbound_shutdown_timeout=5.0 bounds
the drain; pass None explicitly only when an unbounded wait is required. At a
timeout, queued events are discarded and each callback still running is logged
with its event name and context.
Python cannot safely stop a running thread. A callback that exceeds the timeout
continues on its daemon worker until the callback itself returns, even though
close() proceeds. Callback code should therefore use its own bounded I/O and
cooperative cancellation where appropriate.
Outbound command bus
Every WebSocketStreamDockConnection owns one dedicated outbound writer.
Calling send() puts the typed command into a bounded FIFO queue; only that
writer validates and serializes the command, emits its protocol log, and calls
the WebSocket transport. Concurrent plugin threads therefore cannot interleave
frames. send() waits for its command's result, so serialization and transport
errors still reach the caller and state-update helpers retain their rollback
behavior.
send_async() performs the same queue acceptance but returns a
CommandFuture before serialization or WebSocket I/O. Queue-full and
shutdown rejections are raised immediately; call future.result() only when
the eventual writer-side error or completion matters. For high-frequency
display rendering, Action.set_image_async(), set_title_async(), and
set_state_async() avoid holding an inbound callback while the writer is slow.
Rollback-sensitive settings helpers remain synchronous.
The outbound queue holds 1,024 waiting commands by default. It never silently
drops a command when full: send() and send_async() raise
OutboundQueueFullError. Configure the queue and graceful-drain timeout on the
connection:
from mirabox_sdk import WebSocketStreamDockConnection
connection = WebSocketStreamDockConnection(
arguments.port,
outbound_queue_limit=512,
coalesce_outbound_commands=True,
outbound_shutdown_timeout=5.0,
)
Coalescing is opt-in. Compatible adjacent pending setState, setTitle,
setImage, setSettings, or setGlobalSettings commands for the same
semantic target are replaced by their newest value. Commands of another type or
target are ordering barriers. All callers whose commands were combined receive
distinct CommandFuture handles backed by the queued command's single
completion state, and therefore observe the same final write result. The queue
retains at most one completion state per physical entry.
Read connection.outbound_queue_metrics for an atomic OutboundQueueMetrics
snapshot. It reports current and peak depth, submissions, enqueues, coalescing,
successful serialization and writes, queue rejections, shutdown discards, and
serialization or transport failures. Once shutdown starts, new submissions
raise OutboundCommandBusClosedError; queued commands drain before the
WebSocket closes unless outbound_shutdown_timeout expires. A timed-out write
already in progress cannot be cancelled and may still complete while its caller
receives a shutdown error.
Concurrency contract
The runtime uses explicit thread ownership:
| Surface | Supported caller or owner |
|---|---|
configure_logging() and StreamDockPlugin.run() / stop() |
Application lifecycle thread; configure logging before run(), and call stop() after it returns |
WebSocket parsing and on_stream_dock_connected() |
WebSocket loop/reader thread |
on_stream_dock_event() and every Action callback |
Connection-owned inbound workers; callbacks are serial per context and may overlap across contexts, while lifecycle, broadcast, and unknown barriers run exclusively |
StreamDockSender.send() / send_async() and action command helpers |
Any application, service, or action-callback thread; overlapping calls are supported |
WebSocketStreamDockConnection.close() |
Any application or action-callback thread; calls are idempotent and may overlap |
set_listener() |
Lifecycle thread before run_forever() starts |
The outbound queue establishes FIFO order when it accepts commands. Calls that
do not overlap retain caller order; the relative order of simultaneous calls
is intentionally unspecified. Each send() waits only for its own accepted
submission (or the final coalesced write) and receives its serialization,
transport, overflow, or shutdown result. send_async() returns after
acceptance; the returned CommandFuture exposes the later result.
Scalar-only frozen command objects may be shared between threads.
Payload-bearing commands own mutable OwnedJsonPayload data: do not mutate a
command or its payload once any thread begins send() or send_async().
ValidatedJsonObject backing snapshots are safe to hand between threads after
construction, but every mutable COW view—event settings, Action.settings,
runtime.global_settings, and OwnedJsonPayload—allows only one accessing or
mutating thread at a time. Use update_global_settings() for serialized,
rollback-safe updates from background services; do not share a live mutable
view between threads.
Shutdown rejects new inbound events, drains the inbound dispatcher while
outbound commands are still accepted, rejects and drains outbound commands,
then closes the WebSocket. StreamDockPlugin.stop() subsequently releases
actions and stops services in reverse startup order. A background thread that
needs to interrupt run() should call connection.close() and leave final
plugin cleanup to the lifecycle thread.
Logging
SDK logging is disabled by default: it does not propagate to the application's
root logger and does not create a log file. Enable diagnostics explicitly before
calling run_plugin_cli():
from mirabox_sdk import configure_logging
configure_logging(level="INFO")
When enabled without a file, the destination is stderr. To write UTF-8 logs to a file, pass a path; missing parent directories are created automatically. File logging rotates at 5 MiB with three backups by default:
from pathlib import Path
from mirabox_sdk import LoggingOverflowPolicy, configure_logging
configure_logging(
level="DEBUG",
log_file=Path.home() / ".mirabox-counter" / "plugin.log",
max_bytes=5 * 1024 * 1024,
backup_count=3,
logging_queue_limit=1024,
logging_overflow_policy=LoggingOverflowPolicy.DROP_NEWEST,
)
Adjust max_bytes and backup_count for the plugin's needs. Set
max_bytes=0 only when intentionally requesting an unbounded file.
logging_queue_limit bounds the number of records waiting for the managed
listener; it must be positive. DROP_NEWEST preserves already queued records,
while DROP_OLDEST keeps the most recent records of the same priority.
include_payload=True adds the complete inbound and outbound protocol message
to DEBUG records. Payloads may contain tokens, settings, and other secrets, so
enable this option only temporarily in a trusted development environment. Omit
the option (its default is False) to return to redacted payloads while keeping
other diagnostics enabled.
configure_logging(
level="DEBUG",
log_file=Path.home() / ".mirabox-counter" / "plugin.log",
include_payload=True,
)
Repeated calls replace the handler previously installed by
configure_logging(), draining its queue first, so the level or destination can
be changed without duplicating messages. Return the SDK to its default silent
state and flush pending records with:
configure_logging(enabled=False)
INFO records cover connection lifecycle and operational status. Per-message
protocol direction, event, and context are emitted only at DEBUG. Message
payloads remain redacted unless include_payload=True is explicitly configured.
SDK records are handed to one managed logging thread, so stream and rotating
file I/O never runs in the WebSocket reader, inbound dispatcher, outbound
writer, or calling service thread. Handlers installed manually by the
application remain its responsibility and are outside that guarantee. The
managed queue is bounded and producers never wait for destination I/O. On
overflow, an ERROR or CRITICAL record displaces a lower-level record when
possible and is processed ahead of queued DEBUG through WARNING records.
Lower-level records never displace queued errors; within the same priority
class, the configured overflow policy is applied. dropped_log_records()
returns the process-wide, thread-safe count of records discarded by all managed
logging queues:
from mirabox_sdk import dropped_log_records
if dropped_log_records():
# The destination has not kept up with the configured log volume.
...
Project structure
MiraboxStreamDockSDK/
├── pyproject.toml # Package metadata and tool configuration
├── src/mirabox_sdk/
│ ├── action.py # Reusable action base class
│ ├── action_registry.py # Action UUID registry
│ ├── commands.py # Typed outbound commands
│ ├── events.py # Typed inbound event models
│ ├── inbound.py # Bounded inbound event dispatcher
│ ├── outbound.py # Bounded single-writer command bus
│ ├── parser.py # Strict wire-message parser
│ ├── stores.py # Action and global-settings state stores
│ ├── plugin.py # Runtime and lifecycle dispatcher
│ ├── connection.py # WebSocket transport
│ ├── logging_config.py # Isolated SDK logging configuration
│ └── property_inspector/ # Browser-side SDK resource
├── examples/counter_plugin/ # Complete buildable plugin
├── tests/ # SDK and release-tool tests
├── scripts/ # Version and distribution verification
└── .github/workflows/ # CI and Trusted Publishing release jobs
Development
Install the development dependencies, then run the same checks as CI:
python -m unittest discover -s tests -v
PYTHONPATH=examples/counter_plugin/src \
python -m unittest discover -s examples/counter_plugin/tests -v
python -m compileall -q src tests scripts examples
ruff check src tests scripts examples
ruff format --check src tests scripts examples
python -m build
python scripts/verify_distribution.py dist
python -m twine check dist/*
The test suite uses fake connections and protocol messages; it does not require a running Stream Dock instance. CI runs the SDK on Linux and Windows across all supported Python versions.
Contributions are welcome. Please read CONTRIBUTING.md before submitting a change, and include the Stream Dock version and a regression test when changing observed protocol behavior.
Releasing
Releases are built from version tags, published to PyPI through Trusted Publishing, and attached to a generated GitHub Release. The required one-time configuration and release checklist are documented in RELEASING.md.
License
Distributed under the MIT License.
Metadata
Release files for mirabox-stream-dock-sdk 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mirabox_stream_dock_sdk-0.4.0.tar.gz | 209.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mirabox_stream_dock_sdk-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 326.1 kB
Release files / mirabox_stream_dock_sdk-0.4.0.tar.gz
| Download URL | mirabox_stream_dock_sdk-0.4.0.tar.gz |
|---|---|
| Size | 209.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6733595a6fd7cecc199830b09767243216078872d93655175f78f82824d4fb19
|
|
BLAKE2b-256 checksum How to use checksums |
5458e467d5eaf6e40a8341efcffeb3ea44b1e12fb80a39092d339a0b8ccc61d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 27, 2026.
Transparency logRelease files / mirabox_stream_dock_sdk-0.4.0-py3-none-any.whl
| Download URL | mirabox_stream_dock_sdk-0.4.0-py3-none-any.whl |
|---|---|
| Size | 116.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5e9c6ca70aa12981aef510e53bbe89f51ef7193fcc8fb14fcaa44ae5b651b34a
|
|
BLAKE2b-256 checksum How to use checksums |
65334e2afb8e1acdfc36026f27c751c9029678bad087cfa3f08136b7bf9336f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 27, 2026.
Transparency log