Three bugs causing storage preview cache to be ineffective:
1. Cache keys included the `token` auth parameter, so requests using
resource tokens always generated unique keys and never hit cache.
Introduced `cache.params` label for routes to opt-in specific params
into the cache key; preview now declares only the transform params.
2. Cache hits never refreshed `accessedAt` in the DB or the filesystem
file mtime, because `$response->send()` in the init hook skips the
shutdown hook. After 30 days the maintenance job evicted still-active
cache entries, and after the original 30-day filesystem TTL the cache
file expired — causing periodic full re-renders. The cache-hit path
now updates both on the APP_CACHE_UPDATE (24h) interval.
3. `updateDocument` in the preview action passed the full file document
instead of a sparse one when updating `transformedAt`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SessionCreated event now carries only domain data (no isFirstSession)
- Mails listener uses ordered guard clauses, deferring the DB query
until cheaper checks pass
- Drop $user Document allocation in favour of direct array access
- Inline FileName validator and $smtpEnabled into their use sites
- Extract $isBranded to eliminate duplicate APP_BRANDED_EMAIL_BASE_TEMPLATE check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves session alert email side effect out of the account controller
into a dedicated `Mails` listener that reacts to a new `SessionCreated`
bus event. The event is now always dispatched on session creation; the
listener owns all conditional logic (first session, sessionAlerts flag,
email-link sessions, user email presence).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The subQueryPlatforms database filter loads platforms as a sub-attribute
when project documents are fetched. Old platform type values stored in
the database (e.g. flutter-android, flutter-ios) were not being mapped
to the new consolidated types before being included in the project
response sent to the frontend/console.
This adds Platform::mapDeprecatedType() to the filter so all platforms
returned as part of a project document have their types mapped
consistently, complementing the existing mapping in the dedicated
platform Get and List endpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Swap the order of createDocument('sessions') and purgeCachedDocument('users')
in the email/password session creation flow. Previously, the cache was purged
before the session was written, opening a race window in Swoole's async
environment where a concurrent account.get() could re-cache the user with no
sessions, causing sessionVerify to fail with a 401. This matches the correct
ordering already used by the token-based flows (magic URL, OTP, phone).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolve merge conflicts in app/init/resources.php and app/worker.php
caused by the DI container migration (Http::setResource/Server::setResource
to $container->set). Port separate-pool shared tables logic for
getDatabasesDB to the new file locations (request.php and message.php)
with the correct $databaseDSN->getParam('namespace') fix.
- Remove cors from inject chain; resolve via getResource() inside
try-catch so DB failures don't cascade when resolving the cors
resource dependency chain (cors -> allowedHostnames -> rule -> DB)
- Use override:true on addHeader to prevent duplicate CORS headers
when init() already set them before the exception was thrown
- Degrades gracefully: if cors resolution fails, error response is
sent without CORS headers (same behavior as before this PR)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Http::error() handler was missing CORS headers, causing browsers to
block error responses (e.g. 403 PROJECT_PAUSED) with a generic CORS
error instead of showing the actual error message. This injects the cors
resource into the error handler and adds CORS headers before sending the
error response, matching the pattern already used in Http::init().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>