Releases: pyxle-dev/pyxle-plugins
pyxle-mail 0.1.0
First release. One mail.service over a swappable MailProvider contract.
Providers: console (default — logs, sends nothing), SMTP (stdlib, no extra deps), Resend (pyxle-mail[resend] extra).
MailService.send(...) with sender defaults, EmailMessage/SendResult models, fail-loud config validation, get_mail_service() shortcut.
Install: pip install pyxle-mail (with Resend: pip install pyxle-mail[resend])
pyxle-db 0.2.0
Changed (BREAKING)
Database.transaction()now yields a transaction whose methods are
coroutines:await tx.execute(...),await tx.fetchone(...), etc.
In 0.1 these calls were synchronous inside the async context manager.Database.close()andDatabase.sync_transaction()are SQLite-only
and raiseUnsupportedOperationErroron server backends. Use
await db.aclose()andasync with db.transaction()— both work on
every backend.- Mapping (named) parameters are SQLite-only; portable SQL uses
positional?parameters.
Added
-
PostgreSQL backend via
asyncpg(pip install 'pyxle-db[postgres]')
and MySQL backend viaasyncmy(pip install 'pyxle-db[mysql]').
The base install remains SQLite-only with zero extra dependencies. -
Database URLs:
Database(...)/connect(...)accept
sqlite:///...,postgresql://..., andmysql://...connection
strings alongside the 0.1 bare SQLite path.DatabaseConfigand
parse_database_urlare exported for programmatic use. -
Portable placeholders: qmark (
?) SQL is translated per backend
($1for PostgreSQL,%sfor MySQL) with a literal-aware rewriter;
??escapes a literal question mark for PostgreSQL JSON operators. -
Backend-neutral
Rowresult type (index + name access) andDialect
metadata, both exported frompyxle_db. -
New error types:
OperationalError(retryable connection/timeout
family),ConfigurationError, andUnsupportedOperationError.
Driver exceptions are translated on every backend — application code
never handlessqlite3/asyncpg/asyncmyexceptions. -
Datetimes come back timezone-aware UTC on every backend; naive values
stored in the database are assumed UTC and tagged. -
Plugin: new
urlsetting that takes precedence overpath, with
env:VAR_NAMEindirection so credentials stay out of the committed
pyxle.config.json(startup raisesConfigurationErrorwhen the
variable is unset). The plugin now also registersdb.url, a
password-redacted connection string for logging. -
Migrations: backend-specific override files
(0003-fulltext-index.postgresql.sqlnext to
0003-fulltext-index.sql) for migrations that need per-dialect DDL. -
DatabaseLike/TransactionLikeprotocols (pyxle_db.contract,
exported at top level): the structural contract third-party database
layers implement to back plugins like pyxle-auth.Databaseis the
reference implementation; both protocols areruntime_checkableand
the conformance is regression-tested.
Fixed
- Plugin shutdown awaits
Database.aclose(), releasing async pools
cleanly instead of relying on the SQLite-only synchronous close. - Aware datetimes now bind on every backend (found by the live-server
suites). PostgreSQL and MySQL pass parameters through
utc_naive_params(): an aware datetime is converted to UTC and bound
naive, matching the SQLite adapter and the read-side "naive equals
UTC" rule. Previously asyncpg rejected aware datetimes forTIMESTAMP
columns and asyncmy silently serialised the foreign wall clock. - The MySQL pool pins each session to UTC (
SET time_zone = '+00:00'),
soTIMESTAMPcolumns andNOW()are no longer shifted through the
server's system time zone on read. - The
mysqlextra now includescryptography: MySQL 8's default
caching_sha2_passwordauth fails at connect without it. - Dependency floor corrected to
pyxle-framework>=0.4.0— the
pyxle.pluginsAPI first shipped in 0.4.0, so older resolutions
could not import.
Install: pip install pyxle-db · extras: [postgres], [mysql]
Docs: https://pyxle.dev/docs/plugins/pyxle-db
pyxle-auth 0.2.0
Changed (BREAKING)
- Requires
pyxle-db>=0.2.0. Its transaction methods became
coroutines (await tx.execute(...)), and all pyxle-auth SQL is now
written in portable qmark style — the plugin works unchanged on
SQLite, PostgreSQL, and MySQL (DML fully portable; shipped DDL targets
SQLite/PostgreSQL — MySQL schema needs a dialect override, see README).
Upgraders from 0.1: theratelimit_buckets.keycolumn is now
bucket_key(KEY is reserved in MySQL); drop the old table — bucket
data is ephemeral hourly counters and recreates itself. - The plugin now hard-requires the
pyxle-dbplugin to have run
first. List"pyxle-db"before"pyxle-auth"in
pyxle.config.json::plugins; startup aborts with an actionable
error otherwise. - The
ensureSchemaplugin setting is removed. The plugin always
applies its bundled migrations and then runs each service's
idempotentensure_schema()— both are no-ops on an up-to-date
database, so there is nothing left to opt out of.
Added
- Password reset and email verification flows, powered by
TokenService: single-use, purpose-scoped, expiring tokens with
only the SHA-256 stored at rest. The library never sends email —
your app delivers the token through its own mailer. RoleService(RBAC): roles, permissions, and per-user grants,
registered asauth.rbac.ApiTokenService: long-livedpyxle_pat_personal access tokens
with scopes, per-user caps enforced atomically, and revocation.
Registered asauth.api_tokens.- Request guards:
current_user,require_user_page,
require_user_action,require_permission_page,
require_permission_action, andbearer_token, re-exported from
the package root. - New settings:
password_reset_ttl_seconds(default 1800),
email_verify_ttl_seconds(default 86400), and
rate_limit_password_reset_per_hour(default 3), each with a
PYXLE_AUTH_*environment variable and a camelCase plugin key. - Settings precedence: plugin
settingsinpyxle.config.json
overridePYXLE_AUTH_*environment variables, which override the
built-in defaults.AuthSettings.from_envgrew anoverrides
parameter to express this. - Bundled migrations (
pyxle_auth/migrations) applied through
pyxle_db.Migratorat startup, withensure_schema()as
belt-and-braces after. - New exports:
SessionInfo,InvalidToken,TokenClaim,
TokenService,ApiToken,ApiTokenService,TokenLimitReached,
TOKEN_PREFIX, andRoleService. - Live-backend test suite (
tests/test_live_backends.py) running the
real plugin schema path and a full account lifecycle against
PostgreSQL and MySQL (gated onPYXLE_DB_TEST_POSTGRES_URL/
PYXLE_DB_TEST_MYSQL_URL, shared with pyxle-db's suites). PYXLE_AUTH_STRICTenvironment variable:strictnow resolves
config > env > secure-default(True), so a committed config can stay
production-safe (strict + Secure cookies) while local HTTP dev
relaxes via the environment.- Bring your own database. Services and the plugin now bind to the
pyxle_db.DatabaseLikeprotocol instead of the concreteDatabase
class, and the plugin's requirement is thedb.databaseservice
name — any plugin registering a protocol-satisfying object can back
pyxle-auth (pyxle-db remains the reference provider and a hard
dependency for the error types and migrator). The contract (surface,
IntegrityErrortranslation, dialect, datetimes) is documented in the
README and enforced bytests/test_database_contract.py, which runs
the full lifecycle against a deliberately foreign database object.
Fixed
- Schema is now genuinely portable (found by the live-server
suites). Key and indexed columns areVARCHAR(n)instead ofTEXT
(MySQL cannot index bareTEXT), a0001-pyxle-auth-core.mysql.sql
override usesDATETIME(6)(MySQLTIMESTAMPis 2038-capped,
second-rounded, and session-time-zone converted), and
ensure_schema()creates indexes through aninformation_schema
probe on MySQL, which has noCREATE INDEX IF NOT EXISTS. - Dependency floor corrected to
pyxle-framework>=0.4.0— the
pyxle.pluginsAPI first shipped in 0.4.0.
Install: pip install pyxle-auth
Docs: https://pyxle.dev/docs/plugins/pyxle-auth