Skip to content

v0.0.39

Choose a tag to compare

@github-actions github-actions released this 24 Oct 07:57
· 26 commits to main since this release
Immutable release. Only release title and notes can be modified.

Added

  • EventBus.publish_durable_or_inline(event, db): enqueue durably when a transport is
    installed, otherwise run the durable handlers inline in db's transaction (#583).

Changed

  • Frontend: every page that posts through the Inertia router now shows a toast on failure (sharing revoke, dashboard Doctor rerun included); useLeaveGuard lives in @simple-module-py/ui, the background-tasks outbox confirms through the shared dialog instead of window.confirm, and reportClientError() is the single hook the error boundary reports through (#601).
  • Users: lockout, registration and bulk-invite writes that must land before the request ends
    now commit through simple_module_db.independent_session (its own short-lived session)
    instead of committing the request session. Failed or unverified password logins now roll
    back the request session before the lockout bookkeeping is checkpointed. Lockout,
    invite and demo code moved into internal subpackages (#592).
  • Users login lockout raises LoginLockedError, mapped to the same 429 body and Retry-After
    by a registered exception handler; settings errors now share a SettingsError base (their
    HTTP mapping is unchanged). The convention is in
    docs/module-authoring.md and the module scaffold (#595).
  • Packaging: Behaviour change. Published packages now cap their third-party runtime
    dependencies (next major for 1.x+ libraries, next minor for 0.x ones such as sqlmodel), so
    an install can no longer resolve an untested major release (#600).
  • make migration now requires LABEL=<branch label> and autogenerates against
    <label>@head, instead of failing with "Multiple heads" (#598).
  • Release: a pre-flight job lists any package that is not yet on PyPI (needs a pending
    publisher) before anything is published, and publish legs skip versions that already exist,
    so a half-failed release can be re-run (#599).
  • make test-py / make test-py-pg now default to 4 pytest-xdist workers instead of
    -n auto, so concurrent runs on many-core machines don't exhaust memory;
    PYTEST_WORKERS=auto restores the old behaviour.
  • Hosting: one simple_module_hosting.public_access.is_public(app, method, path) answers
    "is this route public?" for AuthMiddleware, maintenance mode, rate limiting and the
    SM031 check, so they can no longer disagree. A legacy auth provider whose deprecated
    get_public_paths() raises is now logged everywhere instead of silently treated as not
    public in route access (#593).
  • Framework: fail-open error handlers in the setup gate, DB listeners, menu providers, plural
    rules and the invalidation decoder now log a WARNING (once) with the traceback instead of
    failing silently; outcomes are unchanged. The policy is in docs/framework-conventions.md.
    The test plugin resets the process-wide mail sender, lease backend and Sentry state per test. The
    register_event_handlers(app=None) default and the requires_framework=None bypass are
    tracked for removal in 0.1.0 (#594).

Fixed

  • Users: read-only demo mode now follows the resolved identity, not only the session cookie. Writes made with a bearer access token or personal API token of a demo account are refused (403 DEMO_READ_ONLY, or the Inertia 409 redirect) through the new AuthState.principal_guards hook, and demo accounts can no longer mint tokens via POST /api/users/auth/token or /token/refresh while demo_read_only is on (#611).
  • Users: the default user role is created at startup when missing, so an app scaffolded with
    smpy new (schema baseline, no data migrations) can register users (#600).
  • Tenants: deleting a tenant now tears down its data. TenantDeleted (now defined in
    simple_module_core.tenant_events, still importable from tenants.contracts.events) is
    published durably, and file_storage (files, upload sessions, then backend objects after
    commit), api_tokens, sharing, feature_flags and the framework's tenant-scoped settings
    overrides (including branding) purge that tenant's rows; audit history is kept. On multi-tenant
    installs, public files of a deleted tenant answer 404 at once (the existence check is cached
    60 s per worker and evicted on every worker by TENANT_DELETED_CHANNEL). Without background_tasks the handlers run inline in
    the deleting transaction. Rows orphaned by earlier deletions are not purged retroactively (#583).
  • File storage: a file whose backend is not the active backend is no longer read or deleted
    through the wrong store: downloads, public reads and thumbnails answer 409 with a translated
    message, and a delete soft-deletes the row but leaves the object alone (logged). Switching
    backends still needs a manual migration; see docs/modules/file_storage.md (#589).
  • Background tasks: enqueue_after_commit is documented as at-most-once (a broker outage after
    commit loses the task; use publish_durable for must-run work). file_storage gains an hourly
    file_storage.reconcile_checksums beat task that re-enqueues checksums for files left without
    one for 30 minutes, up to 500 per run (#590).

Removed

  • Frontend: @simple-module-py/ui no longer depends on react-hook-form/@hookform/resolvers, and the unused shadcn form component is removed; host/client_app drops the unused zod and date-fns (#601). Behaviour change for anyone importing @simple-module-py/ui/components/ui/form.