edgesync 0.3.1__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. {edgesync-0.3.1 → edgesync-0.3.3}/CHANGELOG.md +25 -1
  2. {edgesync-0.3.1 → edgesync-0.3.3}/PKG-INFO +63 -3
  3. {edgesync-0.3.1 → edgesync-0.3.3}/README.md +61 -0
  4. edgesync-0.3.3/VERSION +1 -0
  5. {edgesync-0.3.1 → edgesync-0.3.3}/docs/getting-started.md +44 -20
  6. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/mqtt.py +2 -9
  7. {edgesync-0.3.1 → edgesync-0.3.3}/pyproject.toml +1 -3
  8. {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_mqtt_transport.py +44 -0
  9. {edgesync-0.3.1 → edgesync-0.3.3}/uv.lock +2 -7
  10. edgesync-0.3.1/VERSION +0 -1
  11. {edgesync-0.3.1 → edgesync-0.3.3}/.github/workflows/ci.yml +0 -0
  12. {edgesync-0.3.1 → edgesync-0.3.3}/.github/workflows/release.yml +0 -0
  13. {edgesync-0.3.1 → edgesync-0.3.3}/.gitignore +0 -0
  14. {edgesync-0.3.1 → edgesync-0.3.3}/CONTRIBUTING.md +0 -0
  15. {edgesync-0.3.1 → edgesync-0.3.3}/LICENSE +0 -0
  16. {edgesync-0.3.1 → edgesync-0.3.3}/SECURITY.md +0 -0
  17. {edgesync-0.3.1 → edgesync-0.3.3}/docs/integrations.md +0 -0
  18. {edgesync-0.3.1 → edgesync-0.3.3}/docs/reliability.md +0 -0
  19. {edgesync-0.3.1 → edgesync-0.3.3}/docs/storage.md +0 -0
  20. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/__init__.py +0 -0
  21. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/client.py +0 -0
  22. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/config.py +0 -0
  23. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/exceptions.py +0 -0
  24. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/logging.py +0 -0
  25. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/__init__.py +0 -0
  26. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/delivery.py +0 -0
  27. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/message.py +0 -0
  28. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/receipt.py +0 -0
  29. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/stats.py +0 -0
  30. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/py.typed +0 -0
  31. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/queue/__init__.py +0 -0
  32. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/queue/manager.py +0 -0
  33. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/retry/__init__.py +0 -0
  34. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/retry/backoff.py +0 -0
  35. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/retry/policy.py +0 -0
  36. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/__init__.py +0 -0
  37. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/base.py +0 -0
  38. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/migrations.py +0 -0
  39. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/sqlite.py +0 -0
  40. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/__init__.py +0 -0
  41. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/base.py +0 -0
  42. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/http.py +0 -0
  43. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/registry.py +0 -0
  44. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/utils/__init__.py +0 -0
  45. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/utils/clock.py +0 -0
  46. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/utils/ids.py +0 -0
  47. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/__init__.py +0 -0
  48. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/lifecycle.py +0 -0
  49. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/scheduler.py +0 -0
  50. {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/sync_worker.py +0 -0
  51. {edgesync-0.3.1 → edgesync-0.3.3}/tests/__init__.py +0 -0
  52. {edgesync-0.3.1 → edgesync-0.3.3}/tests/conftest.py +0 -0
  53. {edgesync-0.3.1 → edgesync-0.3.3}/tests/fixtures/__init__.py +0 -0
  54. {edgesync-0.3.1 → edgesync-0.3.3}/tests/fixtures/factories.py +0 -0
  55. {edgesync-0.3.1 → edgesync-0.3.3}/tests/fixtures/fake_transport.py +0 -0
  56. {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/__init__.py +0 -0
  57. {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_client.py +0 -0
  58. {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_http_transport.py +0 -0
  59. {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_sqlite_storage.py +0 -0
  60. {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_worker.py +0 -0
  61. {edgesync-0.3.1 → edgesync-0.3.3}/tests/reliability/__init__.py +0 -0
  62. {edgesync-0.3.1 → edgesync-0.3.3}/tests/reliability/test_reliability.py +0 -0
  63. {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/__init__.py +0 -0
  64. {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_backoff.py +0 -0
  65. {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_config.py +0 -0
  66. {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_models.py +0 -0
  67. {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_queue_manager.py +0 -0
  68. {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_retry_policy.py +0 -0
@@ -7,6 +7,28 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.3] - 2026-09-13
11
+
12
+ ### Changed
13
+
14
+ - `aiomqtt` is now a required dependency instead of an optional `mqtt` extra, so
15
+ `pip install edgesync` alone is enough to use `MQTTTransport`.
16
+
17
+ ## [0.3.2] - 2026-08-24
18
+
19
+ ### Added
20
+
21
+ - MQTT TLS documentation in `README.md` and `docs/getting-started.md`, covering
22
+ `tls_params`/`port` usage for TLS connections and client-certificate (mutual TLS) auth, plus
23
+ test coverage for the `aiomqtt.Client` construction path (both plaintext and TLS), which
24
+ wasn't previously exercised since existing tests injected a fake client directly.
25
+
26
+ ### Changed
27
+
28
+ - `README.md`'s Quickstart now includes a full MQTT usage section (previously it only linked
29
+ out to the getting-started guide), so the MQTT example renders directly on PyPI's project
30
+ page instead of requiring a click-through to GitHub.
31
+
10
32
  ## [0.3.1] - 2026-08-24
11
33
 
12
34
  ### Fixed
@@ -82,7 +104,9 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
82
104
  - Crash and restart recovery via expired-lease sweeps, safe across concurrent workers and
83
105
  processes sharing the same database file.
84
106
 
85
- [Unreleased]: https://github.com/adhuldas/EdgeSync/compare/v0.3.1...HEAD
107
+ [Unreleased]: https://github.com/adhuldas/EdgeSync/compare/v0.3.3...HEAD
108
+ [0.3.3]: https://github.com/adhuldas/EdgeSync/compare/v0.3.2...v0.3.3
109
+ [0.3.2]: https://github.com/adhuldas/EdgeSync/compare/v0.3.1...v0.3.2
86
110
  [0.3.1]: https://github.com/adhuldas/EdgeSync/compare/v0.3.0...v0.3.1
87
111
  [0.3.0]: https://github.com/adhuldas/EdgeSync/compare/v0.2.1...v0.3.0
88
112
  [0.2.1]: https://github.com/adhuldas/EdgeSync/compare/v0.2.0...v0.2.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: edgesync
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Reliable data delivery for unreliable networks.
5
5
  Project-URL: Homepage, https://github.com/adhuldas/EdgeSync
6
6
  Project-URL: Repository, https://github.com/adhuldas/EdgeSync
@@ -25,10 +25,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
25
  Classifier: Topic :: System :: Distributed Computing
26
26
  Classifier: Typing :: Typed
27
27
  Requires-Python: >=3.10
28
+ Requires-Dist: aiomqtt<3,>=2.5
28
29
  Requires-Dist: aiosqlite>=0.20
29
30
  Requires-Dist: httpx>=0.27
30
- Provides-Extra: mqtt
31
- Requires-Dist: aiomqtt<3,>=2.5; extra == 'mqtt'
32
31
  Description-Content-Type: text/markdown
33
32
 
34
33
  # EdgeSync
@@ -94,6 +93,67 @@ That's it: `publish()` durably persists the message and returns as soon as it's
94
93
  background worker delivers it, retrying with exponential backoff on failure, without the
95
94
  caller needing to stay connected or wait for the network.
96
95
 
96
+ ## MQTT
97
+
98
+ Publishing to MQTT instead of HTTP is the same pattern with a different transport:
99
+
100
+ ```python
101
+ import asyncio
102
+ from edgesync import EdgeSync
103
+ from edgesync.transports.mqtt import MQTTTransport
104
+
105
+
106
+ async def main():
107
+ async with EdgeSync(
108
+ database="edgesync.db",
109
+ destinations={
110
+ "telemetry": MQTTTransport(
111
+ "broker.example.com",
112
+ "devices/device-001/telemetry",
113
+ qos=1,
114
+ username="device-001",
115
+ password="...",
116
+ ),
117
+ },
118
+ default_destination="telemetry",
119
+ ) as sync:
120
+ await sync.publish({"temperature": 28.5})
121
+
122
+
123
+ asyncio.run(main())
124
+ ```
125
+
126
+ `MQTTTransport` only accepts QoS 1 or 2 — QoS 0 publishes are never acknowledged by the
127
+ broker, so there'd be no way to tell a successful delivery from a lost one, which would break
128
+ EdgeSync's at-least-once guarantee. Unlike `HTTPTransport`, MQTT holds a persistent broker
129
+ connection: `EdgeSync.start()` still won't raise if the broker is unreachable (data keeps
130
+ queuing locally either way), and the transport automatically reconnects on the next delivery
131
+ attempt after a dropped connection or failed publish.
132
+
133
+ **TLS**: by default `MQTTTransport` connects in plaintext on port `1883`. To connect over
134
+ TLS, pass `tls_params` (an `aiomqtt.TLSParameters`) and switch to the broker's TLS port,
135
+ conventionally `8883`:
136
+
137
+ ```python
138
+ import aiomqtt
139
+ from edgesync.transports.mqtt import MQTTTransport
140
+
141
+ MQTTTransport(
142
+ "broker.example.com",
143
+ "devices/device-001/telemetry",
144
+ port=8883,
145
+ tls_params=aiomqtt.TLSParameters(
146
+ ca_certs="/etc/ssl/certs/ca-certificates.crt",
147
+ ),
148
+ )
149
+ ```
150
+
151
+ `TLSParameters` also accepts `certfile` / `keyfile` for client-certificate (mutual TLS)
152
+ authentication. Omit `tls_params` entirely for an unencrypted connection, e.g. a broker on a
153
+ trusted local network or a local development/test setup. See the
154
+ [MQTT section of the getting-started guide](https://github.com/adhuldas/EdgeSync/blob/main/docs/getting-started.md#mqtt)
155
+ for further detail.
156
+
97
157
  ## Usage with FastAPI, Flask, and plain asyncio
98
158
 
99
159
  EdgeSync is async-native, so it's most at home in an `asyncio` app or an async framework like
@@ -61,6 +61,67 @@ That's it: `publish()` durably persists the message and returns as soon as it's
61
61
  background worker delivers it, retrying with exponential backoff on failure, without the
62
62
  caller needing to stay connected or wait for the network.
63
63
 
64
+ ## MQTT
65
+
66
+ Publishing to MQTT instead of HTTP is the same pattern with a different transport:
67
+
68
+ ```python
69
+ import asyncio
70
+ from edgesync import EdgeSync
71
+ from edgesync.transports.mqtt import MQTTTransport
72
+
73
+
74
+ async def main():
75
+ async with EdgeSync(
76
+ database="edgesync.db",
77
+ destinations={
78
+ "telemetry": MQTTTransport(
79
+ "broker.example.com",
80
+ "devices/device-001/telemetry",
81
+ qos=1,
82
+ username="device-001",
83
+ password="...",
84
+ ),
85
+ },
86
+ default_destination="telemetry",
87
+ ) as sync:
88
+ await sync.publish({"temperature": 28.5})
89
+
90
+
91
+ asyncio.run(main())
92
+ ```
93
+
94
+ `MQTTTransport` only accepts QoS 1 or 2 — QoS 0 publishes are never acknowledged by the
95
+ broker, so there'd be no way to tell a successful delivery from a lost one, which would break
96
+ EdgeSync's at-least-once guarantee. Unlike `HTTPTransport`, MQTT holds a persistent broker
97
+ connection: `EdgeSync.start()` still won't raise if the broker is unreachable (data keeps
98
+ queuing locally either way), and the transport automatically reconnects on the next delivery
99
+ attempt after a dropped connection or failed publish.
100
+
101
+ **TLS**: by default `MQTTTransport` connects in plaintext on port `1883`. To connect over
102
+ TLS, pass `tls_params` (an `aiomqtt.TLSParameters`) and switch to the broker's TLS port,
103
+ conventionally `8883`:
104
+
105
+ ```python
106
+ import aiomqtt
107
+ from edgesync.transports.mqtt import MQTTTransport
108
+
109
+ MQTTTransport(
110
+ "broker.example.com",
111
+ "devices/device-001/telemetry",
112
+ port=8883,
113
+ tls_params=aiomqtt.TLSParameters(
114
+ ca_certs="/etc/ssl/certs/ca-certificates.crt",
115
+ ),
116
+ )
117
+ ```
118
+
119
+ `TLSParameters` also accepts `certfile` / `keyfile` for client-certificate (mutual TLS)
120
+ authentication. Omit `tls_params` entirely for an unencrypted connection, e.g. a broker on a
121
+ trusted local network or a local development/test setup. See the
122
+ [MQTT section of the getting-started guide](https://github.com/adhuldas/EdgeSync/blob/main/docs/getting-started.md#mqtt)
123
+ for further detail.
124
+
64
125
  ## Usage with FastAPI, Flask, and plain asyncio
65
126
 
66
127
  EdgeSync is async-native, so it's most at home in an `asyncio` app or an async framework like
edgesync-0.3.3/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.3
@@ -126,31 +126,30 @@ than HTTP.
126
126
 
127
127
  ## MQTT
128
128
 
129
- Install the optional extra first:
130
-
131
- ```bash
132
- pip install edgesync[mqtt]
133
- ```
134
-
135
129
  ```python
130
+ import asyncio
136
131
  from edgesync import EdgeSync
137
132
  from edgesync.transports.mqtt import MQTTTransport
138
133
 
139
- sync = EdgeSync(
140
- database="edgesync.db",
141
- destinations={
142
- "telemetry": MQTTTransport(
143
- "broker.example.com",
144
- "devices/device-001/telemetry",
145
- qos=1,
146
- username="device-001",
147
- password="...",
148
- ),
149
- },
150
- default_destination="telemetry",
151
- )
152
134
 
153
- await sync.publish({"temperature": 28.5})
135
+ async def main():
136
+ async with EdgeSync(
137
+ database="edgesync.db",
138
+ destinations={
139
+ "telemetry": MQTTTransport(
140
+ "broker.example.com",
141
+ "devices/device-001/telemetry",
142
+ qos=1,
143
+ username="device-001",
144
+ password="...",
145
+ ),
146
+ },
147
+ default_destination="telemetry",
148
+ ) as sync:
149
+ await sync.publish({"temperature": 28.5})
150
+
151
+
152
+ asyncio.run(main())
154
153
  ```
155
154
 
156
155
  `MQTTTransport` only accepts QoS 1 or 2 — QoS 0 publishes are never acknowledged by the
@@ -160,6 +159,31 @@ connection: `EdgeSync.start()` still won't raise if the broker is unreachable (d
160
159
  queuing locally either way), and the transport automatically reconnects on the next delivery
161
160
  attempt after a dropped connection or failed publish.
162
161
 
162
+ ### TLS
163
+
164
+ By default `MQTTTransport` connects in plaintext on port `1883`. To connect over TLS, pass
165
+ `tls_params` (an `aiomqtt.TLSParameters`, re-exported from the underlying `paho-mqtt` client)
166
+ and switch to the broker's TLS port, conventionally `8883`:
167
+
168
+ ```python
169
+ import aiomqtt
170
+ from edgesync.transports.mqtt import MQTTTransport
171
+
172
+ MQTTTransport(
173
+ "broker.example.com",
174
+ "devices/device-001/telemetry",
175
+ port=8883,
176
+ tls_params=aiomqtt.TLSParameters(
177
+ ca_certs="/etc/ssl/certs/ca-certificates.crt",
178
+ ),
179
+ )
180
+ ```
181
+
182
+ `TLSParameters` also accepts `certfile` / `keyfile` for client-certificate (mutual TLS)
183
+ authentication — see [aiomqtt's documentation](https://aiomqtt.bo3hm.com) for the full set of
184
+ options. Omit `tls_params` entirely for an unencrypted connection, e.g. when talking to a
185
+ broker on a trusted local network or in a local development/test setup.
186
+
163
187
  ## Inspecting the queue
164
188
 
165
189
  ```python
@@ -1,7 +1,5 @@
1
1
  """MQTT transport backed by ``aiomqtt``.
2
2
 
3
- Requires the optional ``aiomqtt`` dependency: ``pip install edgesync[mqtt]``.
4
-
5
3
  Unlike :class:`~edgesync.transports.http.HTTPTransport`, MQTT is a stateful,
6
4
  persistent connection rather than a per-request protocol, which shapes two
7
5
  design decisions here:
@@ -22,18 +20,13 @@ from __future__ import annotations
22
20
  import contextlib
23
21
  import json
24
22
 
23
+ import aiomqtt
24
+
25
25
  from edgesync.logging import logger
26
26
  from edgesync.models.delivery import DeliveryResult
27
27
  from edgesync.models.message import Message
28
28
  from edgesync.transports.base import Transport
29
29
 
30
- try:
31
- import aiomqtt
32
- except ImportError as exc: # pragma: no cover - exercised only without the extra installed
33
- raise ImportError(
34
- "MQTTTransport requires the 'aiomqtt' package. Install it with: pip install edgesync[mqtt]"
35
- ) from exc
36
-
37
30
 
38
31
  class MQTTTransport(Transport):
39
32
  """Publish messages as JSON payloads to a fixed MQTT topic.
@@ -23,11 +23,9 @@ classifiers = [
23
23
  dependencies = [
24
24
  "httpx>=0.27",
25
25
  "aiosqlite>=0.20",
26
+ "aiomqtt>=2.5,<3",
26
27
  ]
27
28
 
28
- [project.optional-dependencies]
29
- mqtt = ["aiomqtt>=2.5,<3"]
30
-
31
29
  [project.urls]
32
30
  Homepage = "https://github.com/adhuldas/EdgeSync"
33
31
  Repository = "https://github.com/adhuldas/EdgeSync"
@@ -149,3 +149,47 @@ async def test_close_after_failed_start_does_not_disconnect() -> None:
149
149
  await transport.start()
150
150
  await transport.close()
151
151
  assert fake.disconnect_calls == 0
152
+
153
+
154
+ async def test_start_without_tls_params_constructs_plaintext_client(
155
+ monkeypatch: pytest.MonkeyPatch,
156
+ ) -> None:
157
+ captured: dict[str, object] = {}
158
+
159
+ class RecordingClient(FakeMQTTClient):
160
+ def __init__(self, hostname: str, port: int, **kwargs: object) -> None:
161
+ super().__init__()
162
+ captured["hostname"] = hostname
163
+ captured["port"] = port
164
+ captured.update(kwargs)
165
+
166
+ monkeypatch.setattr(aiomqtt, "Client", RecordingClient)
167
+
168
+ transport = MQTTTransport("broker.invalid", "telemetry")
169
+ await transport.start()
170
+
171
+ assert captured["hostname"] == "broker.invalid"
172
+ assert captured["port"] == 1883
173
+ assert captured["tls_params"] is None
174
+
175
+
176
+ async def test_start_with_tls_params_constructs_tls_client(
177
+ monkeypatch: pytest.MonkeyPatch,
178
+ ) -> None:
179
+ captured: dict[str, object] = {}
180
+
181
+ class RecordingClient(FakeMQTTClient):
182
+ def __init__(self, hostname: str, port: int, **kwargs: object) -> None:
183
+ super().__init__()
184
+ captured["hostname"] = hostname
185
+ captured["port"] = port
186
+ captured.update(kwargs)
187
+
188
+ monkeypatch.setattr(aiomqtt, "Client", RecordingClient)
189
+
190
+ tls_params = aiomqtt.TLSParameters(ca_certs="/etc/ssl/certs/ca-certificates.crt")
191
+ transport = MQTTTransport("broker.invalid", "telemetry", port=8883, tls_params=tls_params)
192
+ await transport.start()
193
+
194
+ assert captured["port"] == 8883
195
+ assert captured["tls_params"] is tls_params
@@ -270,15 +270,11 @@ toml = [
270
270
  name = "edgesync"
271
271
  source = { editable = "." }
272
272
  dependencies = [
273
+ { name = "aiomqtt" },
273
274
  { name = "aiosqlite" },
274
275
  { name = "httpx" },
275
276
  ]
276
277
 
277
- [package.optional-dependencies]
278
- mqtt = [
279
- { name = "aiomqtt" },
280
- ]
281
-
282
278
  [package.dev-dependencies]
283
279
  dev = [
284
280
  { name = "mypy" },
@@ -291,11 +287,10 @@ dev = [
291
287
 
292
288
  [package.metadata]
293
289
  requires-dist = [
294
- { name = "aiomqtt", marker = "extra == 'mqtt'", specifier = ">=2.5,<3" },
290
+ { name = "aiomqtt", specifier = ">=2.5,<3" },
295
291
  { name = "aiosqlite", specifier = ">=0.20" },
296
292
  { name = "httpx", specifier = ">=0.27" },
297
293
  ]
298
- provides-extras = ["mqtt"]
299
294
 
300
295
  [package.metadata.requires-dev]
301
296
  dev = [
edgesync-0.3.1/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.3.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes