maildeno 2.0.0__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.
@@ -0,0 +1,55 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+
6
+ # Distribution / packaging
7
+ .Python
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ *.egg-info/
21
+ *.egg
22
+ MANIFEST
23
+ .pypirc
24
+
25
+ # Virtual environments
26
+ .venv/
27
+ venv/
28
+ env/
29
+ ENV/
30
+
31
+ # Testing / coverage
32
+ .pytest_cache/
33
+ .coverage
34
+ .coverage.*
35
+ htmlcov/
36
+ .tox/
37
+ coverage.xml
38
+ *.cover
39
+
40
+ # Type checkers
41
+ .mypy_cache/
42
+ .pyright/
43
+ .ruff_cache/
44
+
45
+ # IDE
46
+ .vscode/
47
+ .idea/
48
+ *.swp
49
+
50
+ # OS
51
+ .DS_Store
52
+
53
+ # Env files
54
+ .env
55
+ .env.local
@@ -0,0 +1,107 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ This project adheres to [Semantic Versioning](https://semver.org/).
5
+
6
+ ---
7
+
8
+ ## [2.0.0] - 2026-06-07
9
+
10
+ ### Changed — breaking
11
+
12
+ - **Rendering is now local.** The SDK no longer sends `dynamic_data` to the
13
+ Maildeno server. Template JSON is fetched once via
14
+ `GET /v1/sdk/template/{id}` and rendered in-process using the embedded
15
+ Wasm engine. Merge tags and visibility context never leave your server.
16
+ - `POST /v1/sdk/render` is no longer called. Existing direct HTTP integrations
17
+ continue to work until the endpoint is removed (see sunset date in the
18
+ `Deprecation` response header).
19
+ - `RenderResult` now has an optional `from_stale_cache: bool = False` field.
20
+ Code that accesses `.output`, `.target`, `.template_id` is unaffected.
21
+ - `invalidate(template_id)` is deprecated. Use `delete_cached(template_id)`.
22
+
23
+ ### Added
24
+
25
+ - **`wasmtime`** added as a runtime dependency — the Wasm engine that runs
26
+ the embedded renderer. Supports Linux, macOS, and Windows on Python 3.9+.
27
+ - **`engine.wasm`** shipped inside the `maildeno` package. Located via
28
+ `importlib.resources` — works correctly in wheels, editable installs,
29
+ virtualenvs, Lambda layers, and Docker containers.
30
+ - **In-process template cache.** Template JSON is cached after the first
31
+ fetch. Subsequent calls to the same `template_id` render with zero network
32
+ overhead.
33
+ - **Stale-on-error fallback.** If the cache TTL expires and the server cannot
34
+ be reached, the SDK renders from the last known-good cached copy and sets
35
+ `result.from_stale_cache = True`. Your send pipeline continues uninterrupted
36
+ during Maildeno downtime. Only throws when the server is unreachable *and*
37
+ no prior cached copy exists for that template.
38
+ - **`cache=` constructor parameter.** Controls the caching strategy — memory
39
+ (default, zero config) or disk (survives process restarts).
40
+
41
+ ```python
42
+ # Memory — default
43
+ client = MaildenoClient(api_key="...", cache={"ttl": 60_000})
44
+
45
+ # Disk — persists across restarts
46
+ client = MaildenoClient(
47
+ api_key="...",
48
+ cache={"type": "disk", "path": "/var/cache/maildeno", "ttl": 300_000},
49
+ )
50
+ ```
51
+
52
+ - **`list_cached()`** — return the IDs of all templates currently in the cache.
53
+ - **`delete_cached(template_id)`** — remove a single template from the cache
54
+ immediately, bypassing TTL. Replaces `invalidate()`.
55
+ - **`clear_cache()`** — wipe the entire cache.
56
+ - **`CacheConfig` TypedDict** exported from the package root.
57
+ - **`TemplateJson` TypedDict** exported from the package root — the shape of
58
+ the raw template payload returned by `GET /v1/sdk/template/{id}`.
59
+ - **Thread-safe Wasm singleton.** The Wasm engine instance is loaded lazily on
60
+ the first render call and reused for the process lifetime. A lock ensures
61
+ exactly-once initialisation even under concurrent startup.
62
+ - **Async Wasm via thread executor.** `AsyncMaildenoClient` dispatches Wasm
63
+ renders to `asyncio`'s default thread-pool executor so the event loop is
64
+ never blocked.
65
+
66
+ ### Migration from v1
67
+
68
+ ```python
69
+ # v1 — server rendered
70
+ result = client.render(
71
+ template_id="...",
72
+ target="html",
73
+ dynamic_data={"merge_tags": {"text": {"name": "Noruwa"}}},
74
+ )
75
+
76
+ # v2 — local render, identical call site
77
+ result = client.render(
78
+ template_id="...",
79
+ target="html",
80
+ dynamic_data={"merge_tags": {"text": {"name": "Noruwa"}}},
81
+ )
82
+
83
+ # Optional: check if rendered from stale cache
84
+ if result.from_stale_cache:
85
+ logger.warning("Stale cache used", extra={"template_id": result.template_id})
86
+ ```
87
+
88
+ No changes required to `render_html()`, `render_react()`, or `render_mjml()`.
89
+
90
+ ---
91
+
92
+ ## [1.0.0] - 2026-05-29
93
+
94
+ ### Added
95
+
96
+ - Initial public release
97
+ - `MaildenoClient` — synchronous client with `render()`, `render_html()`,
98
+ `render_react()`, `render_mjml()`
99
+ - `AsyncMaildenoClient` — async mirror of the sync client, fully `await`-able
100
+ - Both clients support context-manager usage (`with` / `async with`)
101
+ - Both clients accept an injected `httpx.Client` / `httpx.AsyncClient`
102
+ - `MaildenoError` with `code`, `message`, `status`, and `issues`
103
+ - Structured `ValidationIssue` list on `err.issues` for 422 pydantic errors
104
+ - Full type hints, PEP 561 `py.typed` marker
105
+ - `DynamicData` and `MergeTagGroup` as `TypedDict`s
106
+ - Single runtime dependency: `httpx>=0.28.1,<1.0`
107
+ - Python 3.9 – 3.13 support
maildeno-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maildeno
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.