Conversation
|
Warning Rate limit exceeded@abnegate has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 47 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (4)
WalkthroughThis update introduces extensive enhancements and refactoring across the platform. Major changes include the addition of new features for "Sites" (static site hosting and deployment), new configuration files for frameworks and templates, expanded environment variable support, and significant schema changes in collections to support new resource types and tokens. The routing, storage, and deployment logic have been unified and generalized for both functions and sites. The update also adds new error views, improved branding, and support for resource tokens, while modernizing workflows and dependencies. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Router
participant DB
participant Auth
participant Executor
participant Storage
participant Sites
participant Functions
User->>Router: HTTP request (site/function)
Router->>DB: Lookup rule/domain/resource
alt Site resource
Router->>Auth: Check preview JWT (if preview)
Auth-->>Router: Authorized/Unauthorized
Router->>Sites: Serve static/SSR site or preview
Sites-->>Router: Site response
else Function resource
Router->>Auth: Check permissions
Auth-->>Router: Authorized/Unauthorized
Router->>Executor: Run function with runtime/spec
Executor-->>Router: Function response
end
Router->>Storage: (Optional) Serve file/resource
Storage-->>Router: File/Resource
Router->>User: Response (with error/404 views if needed)
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
commit: |
✨ Benchmark results
⚡ Benchmark Comparison
|
Fix deployment and executions deletion
Add `resourceId`
Feat sites
Update: specs
Fix class name
Update version
fix: remove builds
There was a problem hiding this comment.
Actionable comments posted: 23
🔭 Outside diff range comments (4)
app/cli.php (1)
296-302:⚠️ Potential issueFatal syntax & coroutine misuse
run($cli->run(...));is syntactically invalid (...needs a variadic argument) and passes the result of$cli->run()instead of a callable toSwoole\Coroutine\run().This prevents the CLI from starting.
Suggested fix:
- run($cli->run(...)); +run(static function () use ($cli, $args) { + // Swoole coroutine context; propagate original argv + $cli->run(...$args); +});Also ensure
$argsis defined in that scope (addglobal/use).composer.json (1)
47-77: 💡 Verification agent🧩 Analysis chain
Package dependency updates improve framework capabilities.
Multiple package dependencies have been updated, including the addition of
utopia-php/detector. These updates likely provide bug fixes, new features, and improved compatibility with PHP 8.3.
🏁 Script executed:
#!/bin/bash # Check if there are breaking changes in the major dependency updates grep "utopia-php/" composer.json | awk -F':' '{print $1}' | tr -d ' ",' | xargs -I{} sh -c 'echo "Checking {}"; curl -s "https://api.github.com/repos/{}/releases" | grep -E "tag_name|body" | head -n 10'Length of output: 29575
Attention: Breaking changes introduced by some updated dependencies
While most of the updated packages include minor fixes or new features, a couple require code adjustments in consumers:
utopia-php/locale (v0.6.0)
- Placeholder syntax in
Locale::getText()has changed from{name}to{{name}}. You’ll need to update any calls or fixture data using the old syntax.- See full breaking-change notes in the release body.
utopia-php/orchestration (v0.16.0)
getStats()no longer throws on missing container stats; it returns an empty array (or partial results). Update any exception-handling or error-path logic that expected an exception.Please review your codebase for usages of these methods and adjust accordingly before merging.
app/controllers/api/teams.php (1)
458-470: 🛠️ Refactor suggestion
urlparameter validation – possible open redirect in dev mode
The dynamic validator selection is great, but whendevKeyis provided the code falls back tonew URL()which permits all hosts and schemes. In practice this means a malicious client can craft an invite link that redirects unsuspecting users anywhere.->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), ... )Recommendation:
- return $devKey->isEmpty() ? new Host($clients) : new URL(); + return $devKey->isEmpty() + ? new Host($clients) + : new URL(['https', 'http']); // restrict schemesAlso consider emitting a log entry when
URLmode is used so it’s visible in audit logs.
[security]app/controllers/api/vcs.php (1)
1545-1549:⚠️ Potential issueFatal bug: argument count mismatch when calling
$createGitDeployments
$createGitDeployments()expects 19 parameters; this call supplies only 11 – PHP will throw ArgumentCountError and break the authorize flow.- $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerCommitHash, $providerPullRequestId, true, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); + $createGitDeployments( + $github, + $providerInstallationId, + $repositories, + $providerBranch, + '', // $providerBranchUrl + $repositoryName, // $providerRepositoryName + '', // $providerRepositoryUrl + $owner, // $providerRepositoryOwner + $providerCommitHash, + $commitDetails['commitAuthor'] ?? '', + $commitDetails['authorUrl'] ?? '', + $commitDetails['commitMessage'] ?? '', + $providerCommitUrl, + $providerPullRequestId, + true, // external + $dbForPlatform, + $queueForBuilds, + $getProjectDB, + $request + );Alternatively, refactor the helper to accept a
DeploymentContextobject to stop this brittleness.
🧹 Nitpick comments (39)
.coderabbit.yaml (1)
11-11: Add newline at end of file.
YAMLlint reports a missing newline character at EOF. Please ensure the file ends with a newline to satisfy POSIX conventions.🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
app/init/registers.php (1)
220-224: Fully qualify global PDO attribute constants
Using\PDO::ATTR_*avoids namespace collisions. To reduce duplication and ensure consistency across the codebase, consider usingSQL::getPDOAttributes()here instead of hardcoding the attribute array.- return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( - \PDO::ATTR_TIMEOUT => 3, - \PDO::ATTR_PERSISTENT => false, - \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, - \PDO::ATTR_EMULATE_PREPARES => true, - \PDO::ATTR_STRINGIFY_FETCHES => true - )); + return new PDO( + "mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", + $dsnUser, + $dsnPass, + SQL::getPDOAttributes() + );bin/screenshot (1)
1-3: Useexecand properly quote arguments in wrapper
To forward signals correctly and handle arguments with spaces safely, update the script as follows:- #!/bin/sh - php /usr/src/code/app/cli.php screenshot $@ + #!/bin/sh + exec php /usr/src/code/app/cli.php screenshot "$@"app/config/template-runtimes.php (1)
3-5: TODO comment needs a timeline or tracking issueThe TODO comment indicates this is a temporary solution that should be replaced with direct usage of
runtimes.php, but doesn't specify when this should happen or reference a tracking issue.Consider adding a reference to an issue tracking this technical debt or providing a more specific timeline:
-// TODO: Remove, replace with runtimes.php directly +// TODO: Remove, replace with runtimes.php directly (Issue #XXXX) // Used in function templates and site frameworks.github/workflows/static-analysis.yml (1)
1-16: New static analysis workflow provides additional code quality checksThe workflow runs PHPStan (via Composer's check command) inside a Docker container, adding an important static analysis pipeline to improve code quality assurance. This complements the other CI workflows and ensures code quality is validated on pull requests.
Add a newline at the end of the file to fix the YAML linting error:
docker run --rm -v $PWD:/app composer:2.6 sh -c \ "composer install --profile --ignore-platform-reqs && composer check" +🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 16-16: no new line character at the end of file
(new-line-at-end-of-file)
app/config/services.php (1)
173-177: Subtitle grammar / clarityMissing infinitive “to” and a small readability tweak:
- 'subtitle' => 'The Sites Service allows you view, create and manage your web applications.', + 'subtitle' => 'The Sites service allows you to view, create, and manage your web applications.',app/views/general/404.phtml (3)
9-15: Remote font import can block first paintUsing
@import url(https://fonts.bunny.net/…)inside<style>forces the browser to wait for the CSS download before rendering, which delays the 404 page (often the first thing crawlers/users see).Two lightweight options:
- @import url(https://fonts.bunny.net/css?family=fira-code:400|inter:400); + /* Self-host or defer fonts to avoid blocking render. */ + /* @import url('…'); */Or move the import to a separate
<link rel="preload">/<link rel="stylesheet">in the<head>.
157-182: Add accessible labelling for decorative SVG logosThe two
<svg>logos are purely decorative but don’t declare their intent. Screen readers will attempt to parse every path.Add either
aria-hidden="true"or a descriptive label/role:-<svg class="logo-dark" width="110" height="20" …> +<svg class="logo-dark" width="110" height="20" role="img" aria-label="Appwrite logo" …>Repeat for the light variant.
This keeps the page WCAG-friendly with near-zero cost.
4-6: Consider no-index meta tagA 404 page is not useful to search engines and can pollute the index if users link to invalid URLs. You can signal this directly:
<meta name="robots" content="noindex">Place it alongside the viewport meta tag.
CONTRIBUTING.md (2)
166-187: Well-structured module documentation improves architecture guidance.The new Modules section provides clear guidance on the modern architectural approach for organizing service endpoints, moving away from large controller files to a more maintainable and RESTful structure. The examples and organization rules will help contributors follow consistent patterns.
There are a few minor grammatical issues that could be improved:
- Line 168: Add "the" before "approach" → "we noticed the approach of having"
- Line 168: Fix verb agreement in "Not only it creates" → "Not only does it create"
- Line 168: Add "the" before "product's" → "all the product's features"
- Line 172: Add "the" before "below" → "follows the below structure"
- Line 180: Add "a" before "resource" → "doesn't have a resource"
🧰 Tools
🪛 LanguageTool
[uncategorized] ~168-~168: You might be missing the article “the” here.
Context: ... Modules As Appwrite grows, we noticed approach of having all service endpoints in `app...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~168-~168: This verb does not appear to agree with the subject. Consider using a different form.
Context: ...].php` is not maintainable. Not only it creates massive files, it also doesnt contain a...(AI_EN_LECTOR_REPLACEMENT_VERB_AGREEMENT)
[uncategorized] ~168-~168: You might be missing the article “the” here.
Context: ...ssive files, it also doesnt contain all product's features such as workers or tasks. Wh...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~172-~172: You might be missing the article “the” here.
Context: ... Endpoints Every endpoint file follows below structure, making it consistent with HT...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~180-~180: You might be missing the article “the” here.
Context: ...ction].php ``` Tips and tricks: 1. If endpoint doesn't have resource, use service name...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~180-~180: You might be missing the article “a” here.
Context: ...sn't have resource, use service name as resource name too > Example: `Modules/Sites/Http...(AI_EN_LECTOR_MISSING_DETERMINER_A)
🪛 markdownlint-cli2 (0.17.2)
174-174: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
174-176: Add language identifier to fenced code block.For better syntax highlighting and documentation standards, specify a language for the code block.
-``` +```php src/Appwrite/Platform/Modules/[service]/Http/[resource]/[action].php🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
174-174: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
app/worker.php (1)
338-339:telemetryresource hard-codesNoTelemetry
Returningnew NoTelemetry()disables telemetry for all workers, regardless of the project’s configuration or any future feature flags. If disable-telemetry is the desired default, consider reading an env var (e.g._APP_TELEMETRY_DISABLED) so that operators can opt-in later without code changes.app/config/frameworks.php (1)
18-312: High duplication across adapter definitions
Most framework entries repeat the same keys (buildRuntime,runtimes, identicalstaticadapter definitions, etc.). Consider extracting shared defaults:$defaults = [ 'screenshotSleep' => 3000, 'buildRuntime' => 'node-22', 'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'), ]; return [ 'react' + $defaults + [...], ... ];This reduces maintenance burden when build commands change.
app/controllers/api/proxy.php (1)
245-253: Minor: optimise diagnostics aggregation
$validator->getLogs()already returns a concatenated string; wrapping it inside an array andimplode()may print “Array” or duplicate line-breaks.
You can simplify:- foreach ($validators as $validator) { - if (!empty($validator->getLogs())) { - $errors[] = $validator->getLogs(); - } - } - $error = \implode("\n", $errors); + foreach ($validators as $validator) { + $logs = $validator->getLogs(); + if (!empty($logs)) { + $errors[] = $logs; + } + } + $error = \implode("\n", $errors);Very small gain, but keeps the log payload predictable.
app/config/collections/common.php (1)
1105-1125:scopes/expireattribute sizes & missing index
Database::LENGTH_KEYis typically 128 chars; several scopes (storage.files.read,databases.collections.documents.read, …) already exceed that.
Consider increasing to 255 or use 0 (unlimited) if there is no DB limitation.Access patterns for identities frequently query by expiry (
expire < now()). Adding a simple index speeds up clean-up jobs:+ [ + '$id' => ID::custom('_key_expire'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['expire'], + 'lengths' => [], + 'orders' => [Database::ORDER_ASC], + ],.github/workflows/benchmark.yml (1)
61-67: Replace custom APT repo with a pinned static binary foroha
Adding external repositories increases build time and occasionally fails due to key-server / mirror issues.
ohaprovides pre-built static binaries that can be fetched in one line:- echo "deb [signed-by=/usr/share/keyrings/azlux-archive-keyring.gpg] http://packages.azlux.fr/debian/ stable main" | sudo tee /etc/apt/sources.list.d/azlux.list - sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg https://azlux.fr/repo.gpg - sudo apt update - sudo apt install oha + curl -Lo /usr/local/bin/oha \ + https://github.com/hatoo/oha/releases/download/v0.6.4/oha-linux-amd64 \ + && chmod +x /usr/local/bin/ohaBenefits: faster, no root privileges, fewer moving parts, and deterministic versioning.
app/views/general/error.phtml (1)
43-44: Typo: “occured” → “occurred”
Minor copy-editing fix to maintain a professional UI.- $message = $code >= 500 ? 'An unexpected server error occured.' : 'An unexpected client error occured.'; + $message = $code >= 500 ? 'An unexpected server error occurred.' : 'An unexpected client error occurred.';app/config/errors.php (2)
491-506: Token messages reference “file token” but cover generic resource tokens
Descriptions forTOKEN_NOT_FOUND& friends mention “file token”, yet the new token system is generic (APIs, storage, etc.).
Updating wording avoids confusion:- 'description' => 'The requested file token could not be found.', + 'description' => 'The requested resource token could not be found.', - 'description' => 'The requested file token has expired.', + 'description' => 'The requested resource token has expired.',
605-614: Code 400 forBUILD_FAILED&BU B94A ILD_CANCELEDmay hide server errors
A build failure often implies an internal error (dependency fetch, build pipeline, etc.).
Returning 5xx (e.g., 502/500) helps clients distinguish user input problems (4xx) from server-side issues.Consider:
- 'code' => 400, + 'code' => 500,for one or both errors, or at least document the rationale.
.github/workflows/tests.yml (2)
125-132: Busy-wait loop may consume runner time + logsThe tight
while ! grep …; do sleep 1; doneloop polls Docker logs every second.
Consider:
- Adding
set -eo pipefailso the step fails on pipe errors.- Increasing
sleep 2-3or using--tail 1 -fto reduce log spam.- Bailing out early when the container exits unexpectedly.
Example:
-while ! docker compose logs openruntimes-executor | grep -q "Executor is ready."; do - echo "Waiting for Executor to come online" - sleep 1 -done +set -eo pipefail +timeout 180 bash -c ' + until docker compose logs --tail 1 openruntimes-executor | grep -q "Executor is ready."; do + sleep 3 + done +'🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 125-125: trailing spaces
(trailing-spaces)
124-127: Trailing whitespace – YAMLLint errorsYAMLLint flags lines 125 and 276 for trailing spaces.
While harmless, they fail stricter CI linters – please trim them.Also applies to: 276-276
🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 125-125: trailing spaces
(trailing-spaces)
app/controllers/shared/api.php (2)
540-545: Listener registration duplicates nearly-identical callbacksEach
on(Database::EVENT_…)supplies an identical closure.
Reduce boilerplate and risk of missed events:foreach ([ Database::EVENT_DOCUMENT_CREATE, Database::EVENT_DOCUMENT_DELETE, Database::EVENT_DOCUMENTS_CREATE, Database::EVENT_DOCUMENTS_DELETE, Database::EVENT_DOCUMENTS_UPSERT, ] as $evt) { $dbForProject->on($evt, 'calculate-usage', fn ($e, $doc) => $usageDatabaseListener($e, $doc, $queueForStatsUsage) ); }This keeps the event list in one place and simplifies future maintenance.
95-109: Minor: clarify bulk-event value derivationUsing
$document->getAttribute('modified', 0)/'created'for bulk events is correct but non-obvious.
A short inline comment (e.g., “// contains count of affected docs”) would aid future readers.app/controllers/api/storage.php (4)
946-951: Documentation & validator disagree on allowed quality rangeThe validator now permits
-1..100, but the description still says “Pass an integer between 0 to 100”.- 'Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.' + 'Preview image quality. Pass -1 to keep the existing image quality, or an integer between 0 and 100 to override it.'Without the update, SDKs may generate the wrong docs and users will assume
-1is invalid.
976-983: Authorization flow: small optimisation opportunity
$isTokenis computed before$fileis fetched, but the later internal-ID
check ($resourceToken->getAttribute('fileInternalId')) is what finally
decides authorisation.
We always hit the database even when the token ultimately mismatches.Consider short-circuiting earlier:
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId() && $resourceToken->getAttribute('fileInternalId') === $fileInternalId /* param */) { $isToken = true; }Not critical, but would save an unnecessary DB read on invalid tokens.
1153-1160: Repeated token-authorisation logic – extract to helper for consistencyThe tri-state check (
$fileSecurity, bucket perms, token validity) is duplicated
acrosspreview,download, andview. Centralising it (e.g. a
TokenAuthorizer::canAccess($bucket, $file, $resourceToken)) would:
- Reduce chances of divergent logic in future edits.
- Make unit-testing the edge-cases (expired token, wrong bucket, etc.) easier.
Not a blocker for this PR, but worth considering.
Also applies to: 1310-1315
1810-1811: Great to see usage endpoint comment – please keep doc-block style consistentFor in-file navigation tools it helps if section headers follow the project’s
PHPDoc style (/** … */). Minor consistency nit.app/init/resources.php (1)
508-510: Unused injected dependency
Telemetry $telemetryis injected intodeviceForLocalbut never referenced.
If the intention is just to ensure thetelemetryresource is initialised, add a clarifying comment. Otherwise drop the parameter to avoid confusion.app/config/variables.php (1)
109-117: Deprecated variable still marked as required
_APP_DOMAIN_TARGETis flagged “Deprecated since 1.7.0” yetrequired => true.
This forces users to set a value that the code path no longer consumes.Consider switching
requiredtofalse(or removing it on the next major) to avoid confusion.app/config/templates/site.php (1)
169-173: Fail fast when an unknown framework enum is supplied
getFramework()will raise a PHP warning (undefined index) and return null if the caller passes an invalid$frameworkEnum.
Making the failure explicit reduces debugging time:-function getFramework(string $frameworkEnum, array $overrides) -{ - $settings = \array_merge(TEMPLATE_FRAMEWORKS[$frameworkEnum], $overrides); - return $settings; +function getFramework(string $frameworkEnum, array $overrides): array +{ + if (!\array_key_exists($frameworkEnum, TEMPLATE_FRAMEWORKS)) { + throw new \InvalidArgumentException("Unknown framework '$frameworkEnum'"); + } + + return \array_merge(TEMPLATE_FRAMEWORKS[$frameworkEnum], $overrides); }app/init/constants.php (2)
33-38: New batch-limit & token expiry constants – double-check configurability
APP_LIMIT_DATABASE_BATCHandAPP_RESOURCE_TOKEN_ACCESSare hard-coded.
Consider wiring them to env vars (with sane defaults) to avoid recompiling when scaling large imports or rotating tokens faster.
194-255: Metric namespace explosion – recommend groupingDozens of new metric patterns are added for sites & generic resources.
Long, copy-pasted constant names are error-prone and inflate opcode cache.Suggestion: expose a single helper like
metric("sites", "requests", $siteId)to build strings on-demand, drop the static constants, and cut maintenance cost by ~200 lines.app/controllers/api/vcs.php (2)
212-221: Repeated string concatenation – considerimplodeonce
$commands[]thenimplode(' && ', $commands)works, but for long lists usearray_filterfirst to skip empties instead of multipleif (!empty())guards.$commands = \array_filter([ $resource->getAttribute('installCommand', ''), $resource->getAttribute('buildCommand', ''), $resource->getAttribute('commands', ''), ]); $buildCommands = implode(' && ', $commands);
266-356: Preview-rule creation is duplicated three timesBranch, commit and generic preview rules share ~95 % identical code.
Extract into a smallcreateRule($domain, array $extras)helper to remove ~60 lines and centralise error handling.app/config/collections/platform.php (1)
731-830:devKeyscollection: missing uniqueness & retention guaranteesNice addition 👍, yet a few gaps:
nameshould be UNIQUE per project to avoid ambiguous keys.secretis encrypted but still queryable; addlengths= [512] to_key_projectif you intend to query by secret hash.- Consider a TTL index on
expireto auto-purge expired dev-keys (supported in both MariaDB & Mongo back-end).Example diff for uniqueness:
+[ + '$id' => ID::custom('_key_project_name'), + 'type' => Database::INDEX_UNIQUE, + 'attributes' => ['projectInternalId', 'name'], + 'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY], + 'orders' => [Database::ORDER_ASC , Database::ORDER_ASC], +],app/controllers/general.php (3)
296-303: Variable shadowing:$versionoverwritten
$versionis set at L296 and then re-declared inside thetryblock at L489-497.
While PHP allows this, it harms readability and makes later maintenance error-prone (which version is it now?).Rename the inner variable or re-use the original:
- $version = match ($type) { + $execVersion = match ($type) {Then pass
$execVersionto the executor.
489-525: Duplicate computation of$entrypoint&$runtimeEntrypoint
$entrypointis defined twice (L493-497 and L519-523) with identical logic. This can drift out of sync.Extract a helper:
$entrypoint = ($type === 'function') ? $deployment->getAttribute('entrypoint', '') : '';and reuse.
1102-1105: Duplicate header injection
Access-Control-Allow-Origin: *is added again in the OPTIONS handler. If the earlier GET/POST handler already injected it, this leads to duplicate headers (harmless but noisy).Move the wildcard logic into a small helper that guarantees single injection.
app/config/collections/projects.php (1)
846-851: Emptylengthsin single-column indexes – safe but inconsistentSeveral new single-column indexes omit the
lengthsarray altogether. While allowed, other parts of the file specify explicit lengths, so the style is inconsistent.Consider setting the length explicitly (or omitting it everywhere) for maintainability.
Also applies to: 1281-1286, 1758-1769, 1785-1790
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
⛔ Files ignored due to path filters (235)
app/config/specs/open-api3-1.5.x-client.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.5.x-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.5.x-server.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.6.x-client.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.6.x-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.6.x-server.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.7.x-client.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.7.x-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-1.7.x-server.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-latest-client.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-latest-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.5.x-client.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.5.x-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.5.x-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.6.x-client.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.6.x-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.6.x-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.7.x-client.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.7.x-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-1.7.x-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-client.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-server.jsonis excluded by!app/config/specs/**composer.lockis excluded by!**/*.lockdocs/examples/1.6.x/server-dart/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dart/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dart/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dart/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-deno/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-deno/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-deno/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-deno/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dotnet/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dotnet/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dotnet/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-dotnet/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-go/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-go/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-go/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-go/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-graphql/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-graphql/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-graphql/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-graphql/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/java/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/java/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/java/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/java/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/kotlin/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/kotlin/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/kotlin/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-kotlin/kotlin/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-nodejs/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-nodejs/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-nodejs/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-nodejs/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-php/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-php/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-php/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-php/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-python/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-python/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-python/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-python/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-rest/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-rest/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-rest/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-rest/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-ruby/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-ruby/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-ruby/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-ruby/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-swift/examples/databases/create-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-swift/examples/databases/delete-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-swift/examples/databases/update-documents.mdis excluded by!docs/examples/**docs/examples/1.6.x/server-swift/examples/databases/upsert-documents.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-anonymous-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-email-password-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-email-token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-j-w-t.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-magic-u-r-l-token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-mfa-authenticator.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-mfa-challenge.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-mfa-recovery-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-o-auth2session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-o-auth2token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-phone-token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-phone-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-push-target.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-recovery.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/create.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/delete-identity.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/delete-mfa-authenticator.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/delete-push-target.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/delete-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/delete-sessions.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/get-mfa-recovery-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/get-prefs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/get-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/get.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/list-identities.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/list-logs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/list-mfa-factors.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/list-sessions.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-email.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-m-f-a.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-magic-u-r-l-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-mfa-authenticator.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-mfa-challenge.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-mfa-recovery-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-name.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-password.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-phone-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-phone-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-phone.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-prefs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-push-target.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-recovery.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-status.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/account/update-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-browser.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-credit-card.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-favicon.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-flag.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-image.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-initials.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/avatars/get-q-r.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/databases/create-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/databases/delete-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/databases/get-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/databases/list-documents.mdis excluded by!docs/examples/**- <
5276
code class="notranslate">docs/examples/1.7.x/client-android/java/databases/update-document.md is excluded by
!docs/examples/** docs/examples/1.7.x/client-android/java/functions/create-execution.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/functions/get-execution.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/functions/list-executions.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/graphql/mutation.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/graphql/query.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/get.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-continents.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-countries-e-u.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-countries-phones.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-countries.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-currencies.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/locale/list-languages.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/messaging/create-subscriber.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/messaging/delete-subscriber.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/create-file.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/delete-file.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/get-file-download.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/get-file-preview.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/get-file-view.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/get-file.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/list-files.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/storage/update-file.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/create-membership.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/create.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/delete-membership.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/delete.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/get-membership.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/get-prefs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/get.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/list-memberships.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/list.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/update-membership-status.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/update-membership.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/update-name.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/java/teams/update-prefs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-anonymous-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-email-password-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-email-token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-j-w-t.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-magic-u-r-l-token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-mfa-authenticator.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-mfa-challenge.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-mfa-recovery-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-o-auth2session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-o-auth2token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-phone-token.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-phone-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-push-target.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-recovery.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/create.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/delete-identity.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/delete-mfa-authenticator.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/delete-push-target.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/delete-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/delete-sessions.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/get-mfa-recovery-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/get-prefs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/get-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/get.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/list-identities.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/list-logs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/list-mfa-factors.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/list-sessions.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-email.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-m-f-a.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-magic-u-r-l-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-mfa-authenticator.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-mfa-challenge.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-mfa-recovery-codes.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-name.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-password.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-phone-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-phone-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-phone.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-prefs.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-push-target.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-recovery.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-session.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-status.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/account/update-verification.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-browser.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-credit-card.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-favicon.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-flag.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-image.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-initials.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/avatars/get-q-r.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/databases/create-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/databases/delete-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/databases/get-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/databases/list-documents.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/databases/update-document.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/functions/create-execution.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/functions/get-execution.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/functions/list-executions.mdis excluded by!docs/examples/**docs/examples/1.7.x/client-android/kotlin/graphql/mutation.mdis excluded by!docs/examples/**
📒 Files selected for processing (63)
.coderabbit.yaml(1 hunks).env(2 hunks).github/workflows/benchmark.yml(1 hunks).github/workflows/cleanup-cache.yml(1 hunks).github/workflows/codeql-analysis.yml(1 hunks).github/workflows/linter.yml(1 hunks).github/workflows/publish.yml(1 hunks).github/workflows/release.yml(1 hunks).github/workflows/static-analysis.yml(1 hunks).github/workflows/tests.yml(8 hunks).gitignore(1 hunks)CONTRIBUTING.md(1 hunks)Dockerfile(2 hunks)README-CN.md(3 hunks)README.md(3 hunks)app/cli.php(5 hunks)app/config/collections/common.php(3 hunks)app/config/collections/platform.php(13 hunks)app/config/collections/projects.php(21 hunks)app/config/errors.php(9 hunks)app/config/events.php(1 hunks)app/config/frameworks.php(1 hunks)app/config/locale/templates/email-base-styled.tpl(6 hunks)app/config/oAuthProviders.php(42 hunks)app/config/platforms.php(16 hunks)app/config/roles.php(3 hunks)app/config/runtimes.php(1 hunks)app/config/scopes.php(2 hunks)app/config/services.php(1 hunks)app/config/specifications.php(1 hunks)app/config/storage/inputs.php(0 hunks)app/config/storage/outputs.php(0 hunks)app/config/template-runtimes.php(1 hunks)app/config/templates/function.php(78 hunks)app/config/templates/site.php(1 hunks)app/config/variables.php(9 hunks)app/controllers/api/account.php(16 hunks)app/controllers/api/avatars.php(5 hunks)app/controllers/api/console.php(3 hunks)app/controllers/api/health.php(1 hunks)app/controllers/api/migrations.php(3 hunks)app/controllers/api/project.php(10 hunks)app/controllers/api/projects.php(2 hunks)app/controllers/api/proxy.php(3 hunks)app/controllers/api/storage.php(10 hunks)app/controllers/api/teams.php(4 hunks)app/controllers/api/users.php(5 hunks)app/controllers/api/vcs.php(17 hunks)app/controllers/general.php(33 hunks)app/controllers/shared/api.php(14 hunks)app/http.php(6 hunks)app/init/configs.php(3 hunks)app/init/constants.php(8 hunks)app/init/database/filters.php(2 hunks)app/init/registers.php(2 hunks)app/init/resources.php(8 hunks)app/views/general/404.phtml(1 hunks)app/views/general/error.phtml(2 hunks)app/views/install/compose.phtml(15 hunks)app/worker.php(5 hunks)bin/screenshot(1 hunks)composer.json(6 hunks)docker-compose.yml(17 hunks)
💤 Files with no reviewable changes (2)
- app/config/storage/inputs.php
- app/config/storage/outputs.php
🧰 Additional context used
🧬 Code Graph Analysis (5)
app/config/errors.php (1)
src/Appwrite/Extend/Exception.php (1)
Exception(7-406)
app/controllers/api/account.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(253-349)src/Appwrite/Vcs/Comment.php (1)
isEmpty(26-29)
app/init/resources.php (3)
src/Appwrite/Utopia/Request.php (2)
Request(13-236)getHeader(195-199)src/Appwrite/Auth/Key.php (3)
Key(13-200)getHostnameOverride(67-70)decode(102-199)src/Appwrite/Extend/Exception.php (1)
Exception(7-406)
app/init/constants.php (1)
src/Appwrite/Platform/Appwrite.php (1)
Appwrite(14-26)
app/controllers/api/storage.php (4)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(253-349)src/Appwrite/Utopia/Response.php (3)
output(658-740)Response(135-905)file(751-758)src/Appwrite/Extend/Exception.php (1)
Exception(7-406)src/Appwrite/Utopia/Request.php (1)
Request(13-236)
🪛 YAMLlint (1.37.1)
.coderabbit.yaml
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
.github/workflows/static-analysis.yml
[error] 16-16: no new line character at the end of file
(new-line-at-end-of-file)
.github/workflows/tests.yml
[error] 125-125: trailing spaces
(trailing-spaces)
[error] 276-276: trailing spaces
(trailing-spaces)
🪛 LanguageTool
CONTRIBUTING.md
[uncategorized] ~168-~168: You might be missing the article “the” here.
Context: ... Modules As Appwrite grows, we noticed approach of having all service endpoints in `app...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~168-~168: This verb does not appear to agree with the subject. Consider using a different form.
Context: ...].php` is not maintainable. Not only it creates massive files, it also doesnt contain a...
(AI_EN_LECTOR_REPLACEMENT_VERB_AGREEMENT)
[uncategorized] ~168-~168: You might be missing the article “the” here.
Context: ...ssive files, it also doesnt contain all product's features such as workers or tasks. Wh...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~172-~172: You might be missing the article “the” here.
Context: ... Endpoints Every endpoint file follows below structure, making it consistent with HT...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~180-~180: You might be missing the article “the” here.
Context: ...ction].php ``` Tips and tricks: 1. If endpoint doesn't have resource, use service name...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~180-~180: You might be missing the article “a” here.
Context: ...sn't have resource, use service name as resource name too > Example: `Modules/Sites/Http...
(AI_EN_LECTOR_MISSING_DETERMINER_A)
🪛 markdownlint-cli2 (0.17.2)
CONTRIBUTING.md
174-174: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🪛 actionlint (1.7.7)
.github/workflows/tests.yml
306-306: property "tables-mode" is not defined in object type {}
(expression)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: E2E Shared Mode Service Test (Realtime, Shared V2)
- GitHub Check: E2E Shared Mode Service Test (Teams, Shared V2)
🔇 Additional comments (93)
.coderabbit.yaml (2)
2-6: Path filters look correct.
The glob patterns correctly exclude generated specs and docs directories from reviews, focusing attention on source code changes.
8-11: Verify target branches for auto-review.
You’ve included1.6.xand1.7.xalongsidemainas base branches. Since this PR is intended to be retargeted tomainbefore merge, please confirm whether those legacy branches should remain or be pruned.🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
.github/workflows/release.yml (1)
14-14: Upgradeactions/checkoutto v4 is appropriate.
Aligns with other workflows and ensures compatibility with the latest features and performance improvements..github/workflows/cleanup-cache.yml (1)
13-13: Upgradeactions/checkoutto v4 is consistent.
Standardizes the checkout step across all CI workflows. No logic changes required.app/config/specifications.php (1)
3-3: Namespace import updated correctly.
Switching toAppwrite\Platform\Modules\Compute\Specificationaligns with the new modular architecture.README-CN.md (1)
75-75: Bumped Docker image tag to1.7.0.
The updated version in all three code blocks matches the new release. No additional examples appear to require updating.Also applies to: 87-87, 97-97
README.md (3)
81-81: Approve version bump for Unix install command
The Docker image tag has been correctly updated toappwrite/appwrite:1.7.0.
Please verify that the1.7.0image is published and available on Docker Hub.
93-93: Approve version bump for Windows CMD install
Theappwrite/appwriteimage version has been updated to1.7.0, matching the Unix command above.
103-103: Approve version bump for Windows PowerShell install
Consistent update of the image tag to1.7.0. Good to go.app/config/runtimes.php (1)
9-9: Approve runtime version upgrade to v5
TheRuntimesconstructor argument has been updated from'v4'to'v5', aligning with executor changes.
Ensure that theRuntimesclass and all downstream logic fully support the new'v5'environment..github/workflows/codeql-analysis.yml (1)
37-37: Approve checkout action upgrade to v4
Updatedactions/checkout@v3to@v4for consistency across CI workflows..gitignore (1)
6-6: Approve ignore rule for site archive files
Added/tests/resources/sites/**/code.tar.gzto prevent committed build artifacts for sites..github/workflows/publish.yml (1)
15-15: Approve checkout action upgrade to v4
Aligned with other workflows by bumpingactions/checkoutto version 4..github/workflows/linter.yml (1)
15-15: Upgradeactions/checkoutto v4
The workflow now usesactions/checkout@v4, aligning with other CI updates in this PR. Ensure there are no regressions related to shallow cloning or caching.app/init/registers.php (1)
18-18: ImportUtopia\Database\PDOadded
Good catch—adding this import ensures thatnew PDO(...)refers to the Utopia adapter rather than the global\PDOclass.Dockerfile (2)
47-55: Add/storage/importsdirectory with proper permissions
The new imports storage directory is created and its ownership/permissions match existing storage paths. Ensure the corresponding volume is mapped in yourdocker-compose.yml.
73-73: Grant execute permission for thescreenshotscript
Adding execute rights for/usr/local/bin/screenshotis necessary to support the new wrapper script.app/config/oAuthProviders.php (1)
14-464: Standardize OAuth provider class resolution
The addition of the'class'key for each OAuth provider centralizes the fully qualified class names and decouples provider logic from hardcoded namespaces. Confirm that all controllers now retrieve the provider class from this configuration and that providers commented out or missing a'class'entry are handled gracefully.app/init/database/filters.php (2)
136-148: Well-structured new database filter for development keysThe new
subQueryDevKeysfilter follows the established pattern of other subquery filters in the file and correctly implements the necessary queries to fetch development keys associated with a project.
242-242: Appropriate extension of resource types to include sitesThe modification to include 'site' alongside 'function' in the resourceType condition correctly supports the expansion of resource types in the platform.
app/config/locale/templates/email-base-styled.tpl (4)
82-82: Good parameterization of button stylingReplacing hardcoded colors with the dynamic
{{accentColor}}variable enables consistent branding across emails that can be configured at runtime.Also applies to: 91-91
129-129: Appropriately parameterized logo URLUsing
{{logoUrl}}instead of a hardcoded path allows for dynamic logo configuration in emails.
167-167: Well-implemented social media link parameterizationThe social media links are now properly templated using variables for Twitter, Discord, and GitHub URLs, allowing for easier configuration and maintenance.
Also applies to: 176-176, 184-184
194-194: Improved footer link configurabilityThe Terms and Privacy links are now parameterized with
{{termsUrl}}and{{privacyUrl}}, supporting custom landing pages per installation.Also applies to: 198-198
app/config/template-runtimes.php (1)
6-43:Details
❓ Verification inconclusive
Comprehensive runtime version configuration
The runtime configuration provides a well-structured mapping of runtime environments to their supported versions. This supports both function templates and site frameworks as noted in the comments.
Run the following to verify that the runtime versions listed are consistent with what's supported in the runtime services:
🏁 Script executed:
#!/bin/bash # Check if these runtime configs match the actual runtimes.php file cat app/config/runtimes.php | grep -A 5 "versions"Length of output: 50
🏁 Script executed:
#!/bin/bash # Verify the runtime versions block in the correct file grep -n "versions" app/config/template-runtimes.php -A5Length of output: 1055
Verify runtime version mappings in template-runtimes.php
I’ve confirmed that the
versionsarrays inapp/config/template-runtimes.php(lines 9–41) match the submitted snippet. Before merging, please cross-check each runtime’s version list against your official supported-runtimes source to ensure they’re up to date.• File: app/config/template-runtimes.php (lines 9–41)
app/config/roles.php (2)
29-29: Permission scope addition to member roleAdding the
rules.readpermission to the member role is appropriate for allowing users to read rule configurations.
62-65: Additional permissions for admin role reflect new platform featuresThe new permissions for sites, logs, and tokens properly expand the admin role capabilities to support the new features being introduced in the platform.
I see these changes align with the introduction of the sites service and token management features mentioned in the PR summary.
Also applies to: 84-85
app/init/configs.php (3)
5-5: Config loading order adjustment introduces template-runtimes configThis adds a new configuration file for template runtimes at the beginning of the loading sequence, which is consistent with the expanded site support features introduced in this update.
14-14: New frameworks configuration addedAdding the frameworks configuration expands the platform's capability to support different web frameworks for both function and site deployments.
38-40: Reorganized configuration loading for specifications and templatesThese changes consolidate what were likely separate configuration files into a more structured approach, separating function and site templates while maintaining a unified specifications file. This reorganization aligns with the new site hosting capabilities.
app/controllers/api/health.php (1)
848-848: Extended health checks to include sites storage deviceThe health storage endpoint now properly includes the new sites storage device in its health checks, ensuring comprehensive coverage of all storage components. This is a necessary addition given the new sites functionality being introduced.
Also applies to: 850-851
app/config/platforms.php (1)
14-14:Details
❓ Verification inconclusive
Updated SDK versions across all platforms
All SDK versions have been incremented to support the new platform capabilities, particularly the sites functionality. This coordinated version bump ensures consistent API support across all client, console, and server SDKs.
Let's check if the version increments are aligned with semantic versioning principles based on the magnitude of changes:
Also applies to: 62-62, 80-80, 115-115, 137-137, 202-202, 248-248, 266-266, 284-284, 302-302, 320-320, 338-338, 356-356, 374-374, 392-392, 414-414
🌐 Web query:
What changes are typically included in major version updates for SDKs in terms of backward compatibility?💡 Result:
Major version updates for SDKs typically introduce backward incompatible changes that require developers to modify their existing code. These updates represent significant shifts in the SDK's functionality and structure.
Breaking Changes in Major Version Updates
Major version updates (changing the X in X.Y.Z semantic versioning) indicate substantial modifications that aren't backward compatible with previous versions. These changes often require careful consideration before upgrading.
API Incompatibilities
Major updates frequently include incompatible API changes such as:
- Removing or renaming functions, methods, or classes[9]
- Changing parameter types or return values[5]
- Adding required parameters to existing methods[5]
- Altering the behavior of existing functionality in ways that could break dependent code[1]
Structural Changes
Major versions may also introduce:
- New product directions or significant architectural modifications[3]
- Changes to underlying dependencies or requirements[8]
- Complete refactoring to support new idioms and patterns in the programming language[8]
Support Implications
When a major version is released:
- All version numbers are typically reset (e.g., from 2.0.4 to 3.0.0)[6]
- Previously stable APIs may be removed entirely if they were appropriately deprecated in earlier versions[7]
- New features and bug fixes are generally only released for the latest major version, encouraging migration[5]
Impact on Developers
Major version updates require careful planning because they:
- Force developers to modify their existing code to maintain compatibility[5]
- May prevent downgrading to previous versions once adopted[10]
- Could require significant testing to ensure application stability after migration[1]
SDK providers typically maintain clear documentation about these breaking changes and often provide migration guides to help developers transition between major versions. For many enterprise applications, it's considered best practice to thoroughly test major version updates in staging environments before deploying to production[1].
Citations:
- 1: https://www.files.com/docs/sdk-and-apis/sdk-versioning-and-updates
- 2: https://developer.paypal.com/braintree/docs/reference/general/server-sdk-deprecation-policy/
- 3: https://learn.microsoft.com/en-us/dotnet/core/versions/
- 4: https://community.adobe.com/t5/indesign-discussions/changing-sdk-version/m-p/11601161
- 5: https://docs.stripe.com/sdks/versioning
- 6: https://announcekit.app/blog/changelog-versioning/
- 7: https://docs.nvidia.com/doca/sdk/DOCA+Backward+Compatibility+Policy/index.html
- 8: https://amplitude.com/docs/sdks/sdk-maintenance-and-support
- 9: https://workos.com/blog/software-versioning-guide
- 10: https://www.infoq.com/articles/breaking-changes-are-broken-semver/
Validate Major Version Bump for SDKs
Please confirm that the jump to
18.0.0(and the corresponding bumps at lines 62, 80, 115, 137, 202, 248, 266, 284, 302, 320, 338, 356, 374, 392, and 414) truly introduces breaking changes in line with semantic-versioning rules. Major version updates must reflect backward-incompatible API or structural changes.• Review each SDK’s changelog or migration guide to identify and document any removed/renamed methods, altered behaviors, changed parameters, or architectural shifts in 18.0.0.
• Ensure all dependent code (client, console, server) has been updated to accommodate these changes.
• Update your release notes or add a migration section in documentation to clearly list these breaking changes and provide upgrade instructions.app/config/services.php (1)
178-183: Double-check controller routing for empty stringBoth the new
sitesand the updatedfunctionsentries set'controller' => ''with the comment “Uses modules”.
Please verify that:
- The HTTP router treats an empty string as “module handled” and does not try to load a PHP file.
- No older code paths still expect a non-empty path (e.g. for CLI tooling or Swagger generation).
If any call sites still assume a file path, runtime errors will surface only at request time.
app/cli.php (2)
31-35: Runtime version hard-coded to v5
new Runtimes('v5')assumes that every deployment already ships runtime definitions for v5. If someone back-ports this branch onto an environment that only has up to v4, tasks will fatal at bootstrap.Gracefully fall back, e.g.:
$version = Config::getParam('_APP_RUNTIME_VERSION', 'v5'); Config::setParam('runtimes', (new Runtimes($version))->getAll(supported: false));Or catch
InvalidArgumentExceptionfromRuntimes.
296-299: Timer cleanup outside coroutine context
Timer::clearAll()is called both inside the error handler and in a shutdown hook. That’s good, but remember that if therun()wrapper is fixed to execute inside a coroutine, the shutdown callback must still run inside the same context or you’ll see “Timer::clearAll(): no reactor” notices when the event loop has already exited.Keep an eye on this once the coroutine wrapper is corrected.
app/config/scopes.php (3)
67-72: Addition of site-related access scopes aligns with new static site functionality.The new
sites.readandsites.writescopes properly follow Appwrite's established permissions pattern for granular control over the new sites feature. This maintains consistency with the existing permission structure.
73-78: Log access scopes provide proper granular permissions for site logs.The addition of
log.readandlog.writescopes creates a clear separation of concerns for accessing and managing site logs, consistent with Appwrite's permission architecture.
145-150: Token management scopes appropriately established.The
tokens.readandtokens.writescopes correctly implement the permission structure needed for the new token management functionality, maintaining consistency with other resource types.app/config/templates/function.php (3)
3-5: Good refactoring to use dynamic runtime configuration.Replacing hardcoded runtimes with dynamic configuration from
Config::getParam('template-runtimes')improves maintainability and centralization of runtime definitions, making it easier to add or modify runtime environments without code changes.
26-26: Template scoring system enhances template selection.The addition of the
scoreattribute to function templates implements a numerical ranking system that facilitates better template organization and prioritization. This will improve template discovery and selection in the UI.Also applies to: 111-111, 155-155, 207-207, 245-245, 314-314, 376-376, 440-440, 525-525, 592-592, 676-676, 725-725, 773-773, 820-820, 908-908, 965-965, 1047-1047, 1090-1090, 1148-1148, 1218-1218, 1276-1276, 1336-1336, 1395-1395, 1454-1454, 1532-1532, 1574-1574, 1611-1611, 1674-1674, 1739-1739, 1795-1795, 1837-1837, 1879-1879, 1921-1921, 1958-1958, 2014-2014
35-53: Runtime references properly updated to use dynamic configuration.The change to use
$templateRuntimesinstead of hardcoded constants throughout the file ensures consistency and centralizes runtime management. This is a positive architectural improvement.composer.json (3)
18-18: Static analysis integration through PHPStan.The addition of the
checkscript command provides a standardized way to run static analysis, which will help maintain code quality and catch potential issues earlier in development.
92-92: PHPStan addition enables static code analysis.Adding PHPStan as a development dependency is a good practice for implementing static code analysis, which can help identify potential bugs, type errors, and other issues before they reach production.
105-107: Plugin configuration updated for new dependencies.The allow-plugins configuration has been updated to enable
php-http/discoveryandtbachert/spiplugins, which are likely required by the updated dependencies.app/controllers/api/projects.php (2)
2142-2143: Dependency Injection ImprovementThe code now injects a
planarray as a dependency in the SMTP test email endpoint, enhancing the function signature to make branding and configuration more flexible.
2156-2163: Enhanced Email Template CustomizationThe code now uses the injected
planconfiguration to dynamically populate email template parameters, with fallbacks to global constants. This allows for customizable branding and legal/social links in test emails.This is a good implementation of the template parameter system that maintains backward compatibility through fallback values while enabling customization.
app/http.php (5)
16-16: Added Compression ImportAdded the Compression class import which is used for the new screenshots bucket configuration.
32-32: Static File Loading EnhancementAdded static file loading from the public directory at startup, which enables efficient serving of static assets.
314-360: New Screenshots Bucket ImplementationAdded a dedicated screenshots bucket with specific configurations tailored for image storage, including size limits, format restrictions, and optimization settings.
The code creates a specialized bucket for screenshots with these key features:
- 20MB file size limit
- PNG format restriction for consistency and security
- Gzip compression enabled for storage efficiency
- Authorization.skip() used appropriately to perform system-level operations
- Reuses existing file collection configuration for consistency
This implementation aligns with the platform's evolution to support new resource types while maintaining security and performance considerations.
549-549: Updated Event Constant UsageThe code now uses the standardized
Constant::EVENT_TASKinstead of a string literal, improving maintainability.
583-584: Enhanced Domain Filtering LogicUpdated domain filtering to exclude domains ending with either functions domain or sites domain environment variables, supporting the expanded platform features.
This change accommodates the new "sites" functionality being added to the platform, ensuring proper domain routing and security checks for both functions and sites resources.
app/controllers/api/migrations.php (1)
309-432: New endpoint for CSV migrations integrates well with existing patternsThis implementation adds a new endpoint for importing documents from CSV files as a migration source. The code follows the established patterns from other migration types and includes proper authorization, file processing, and queuing mechanics.
I noticed that unlike other migration endpoints (lines 96-98), the CSV migration doesn't set the user when triggering the migration (lines 424-427). Was this omission intentional?
$queueForMigrations ->setMigration($migration) ->setProject($project) + ->setUser($user) ->trigger();app/controllers/api/avatars.php (5)
190-190: Parameter default change affects quality handling behaviorThe default value for the quality parameter has been changed from 100 to -1, with the description updated to indicate it will "keep existing image quality" rather than use maximum quality.
This change in default behavior might affect existing clients. Please confirm that this change is compatible with all client implementations and update documentation accordingly.
218-218: Consistent quality parameter change for browser iconsThis change mirrors the quality parameter change in the credit card endpoint.
246-246: Consistent quality parameter change for flag iconsThis change mirrors the quality parameter changes in other avatar endpoints.
505-506: QR code scale addition improves readabilityAdding a scale option to the QR code generation will produce larger QR code patterns within the image.
520-520: Substantial QR code quality improvementThe PNG output quality for QR codes has been significantly increased from the default (likely 9) to 90.
This will result in much higher quality QR code images, though with larger file sizes. The change makes sense for ensuring QR codes are readable in all scenarios.
app/controllers/api/console.php (2)
46-60: Enhanced domain validation improves security and reliabilityThe previous simple validation has been replaced with more robust validation using
DomainandIPvalidators. The new implementation properly checks for known non-test domains and validates IPv4/IPv6 addresses.The domain is now considered enabled when:
_APP_DOMAINis a valid, known, non-test domain, AND- At least one of the target records (CNAME, A, or AAAA) is valid
This provides more flexibility while maintaining security standards.
71-83: Environment variable structure updated for broader architecture supportThe response structure has been updated to reflect architectural changes in the platform:
_APP_DOMAIN_TARGEThas been replaced by separate CNAME, A, and AAAA record variables_APP_FUNCTIONS_SIZE_LIMITrenamed to_APP_COMPUTE_SIZE_LIMIT- New variables added for sites, functions domains, and HTTPS options
This change suggests a shift from function-specific architecture to a broader compute model that also supports sites, aligning with the AI summary's mention of "support for sites alongside functions."
app/controllers/api/teams.php (2)
322-327:requestTimestampis now injected but never used
requestTimestampis still injected (line 310) but the new implementation removed thewithRequestTimestamp()wrapper and simply calls:$team = $dbForProject->updateDocument('teams', $team->getId(), $team);Any optimistic-locking or concurrency protection that relied on the original timestamp is now bypassed. Please verify that this change is intentional; otherwise, stale writes could silently overwrite newer data.
1091-1105: Efficient owner-count query – looks good
Scoping therolesquery withteamInternalId(lines 1093-1096) prevents miscounting owners across organisations. Nice catch and minimal performance impact with the hardmax: 2limit.app/worker.php (2)
369-371:planresource returns an empty array – double-check downstream expectations
Several controllers injectplanand immediately index into it ($plan['authPhone'], etc.). Returning[]will raiseUndefined indexnotices in PHP 8.2+. If the intention is “no plan”, consider returning a typedDocumentwith sensible defaults or at least:return ['features' => [], 'limits' => []];
383-406: Null-safe iteration on$extras– nice improvement
Wrapping theforeachwith($extras ?? [])preventsTypeErrorwhen nothing is supplied.app/config/events.php (1)
220-247: Good addition of the newsitesevent category.The new event structure follows the same pattern as existing resources like
functions, with proper model references, resource flags, and standardized event triggers (create, delete, update). This addition properly integrates sites as a first-class resource within the event system.app/controllers/api/project.php (4)
20-20: LGTM: Added Boolean validator import.This import is needed for the new secret parameter in variable endpoints.
153-153: Good refactoring to generalize metrics for multiple resource types.The code now uses separate
{resourceType}and{resourceInternalId}placeholders instead of function-specific placeholders. This change supports the platform's expansion to handle multiple resource types (functions and sites) in a unified way.Also applies to: 169-169, 185-185, 234-235, 240-241, 258-259, 274-275
405-405: Good addition of secret flag for project variables.Adding the secret flag enhances security by allowing variables to be marked as sensitive, which can limit their visibility during build and runtime.
Also applies to: 410-410, 425-425
529-529: Good security enhancement preventing secret variables from being downgraded.The code now prevents variables marked as secret from having their secret flag unset, which is an important security protection.
Also applies to: 534-534, 540-542, 547-547
app/controllers/api/users.php (4)
12-13: LGTM: Added delete helper classes imports.These imports support the enhanced cleanup operations when deleting users.
26-26: LGTM: Added Memberships query validator import.Required for the enhanced filtering capability in the membership listing endpoint.
826-827: Good enhancement to membership listing with filtering and search.The endpoint now supports advanced filtering and search capabilities for user memberships, which improves API flexibility and usability.
Also applies to: 838-850
2296-2297: Thorough cleanup on user deletion.The code now properly deletes all associated identities and targets when a user is deleted, preventing orphaned records in the database.
app/config/collections/common.php (2)
1443-1448: Indexing an array column (roles) withINDEX_KEYmay not behave as expected
rolesis stored as an array – ultimately a JSON string – so the new_key_rolesBTREE index will only be useful for exact value matches on the entire encoded string.
If the goal is to query for memberships that contain a role (e.g.member,owner) consider:
- Keeping the column scalar and creating a join table or
- Switching the index to
INDEX_FULLTEXTand using full-text search predicates.Otherwise the index adds write-overhead without real query benefit.
2385-2397: Good addition – indexes forexpired&sessionInternalIdThese two keys are frequently filtered in house-keeping and look-up paths; the new indexes will reduce full-table scans.
app/controllers/api/account.php (9)
722-722: Database operation simplificationThe code now directly calls the
deleteDocumentmethod without using awithRequestTimestampwrapper. This simplification appears throughout the file for database operations and makes the code more straightforward.
1185-1186: Enhanced URL validation with development key supportThe validator now intelligently adapts based on the presence of a development key, using a more strict
Hostvalidator when no dev key is present and a more permissiveURLvalidator otherwise. This change improves security while providing flexibility for development scenarios.
1213-1214: Improved OAuth2 provider resolutionThe code now retrieves OAuth2 provider class names from configuration instead of using hardcoded namespace concatenation. This change enhances modularity and makes the OAuth2 provider system more configurable.
- $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); + $oAuthProviders = Config::getParam('oAuthProviders'); + $className = $oAuthProviders[$provider]['class'];
1782-1783: Consistent implementation of development key support for OAuth2 token URL validationSimilar to the changes in the OAuth2 session endpoint, this update implements the same flexible validation pattern for success and failure URLs in the OAuth2 token creation endpoint.
1863-1863: Development key support for magic URL login redirectionThe magic URL login endpoint now also implements the dynamic validator selection pattern based on development key presence, consistent with other authentication endpoints.
2002-2003: Minor whitespace adjustmentSmall whitespace change for better code readability.
2771-2771: Simplified database update operationsMultiple instances of database update operations have been simplified by removing the
withRequestTimestampwrapper, making the code more consistent and easier to understand. The updated code now directly assigns the result of the update operation back to the user variable, which allows for proper handling of the returned updated document.Also applies to: 2846-2846, 2931-2931, 3017-3017, 3067-3067, 3105-3105, 3869-3869
3149-3149: Development key support for password recovery URL validationThe password recovery endpoint now implements the same flexible URL validation based on development key presence, consistent with other authentication endpoints.
3415-3415: Development key support for email verification URL validationThe email verification endpoint now also implements the development key-based URL validation, providing consistent behavior across all authentication-related endpoints that use URL redirection.
.github/workflows/benchmark.yml (1)
71-79: Security & reproducibility – pin the production compose/env files
Fetchingdocker-compose.ymland.envfrom the live site means every CI run may pick up different images or configs, breaking reproducibility and obscuring regressions.Consider referencing a specific release tag (or commit hash) instead of
latest:- curl https://appwrite.io/install/compose -o docker-compose.yml - curl https://appwrite.io/install/env -o .env + curl -sL https://raw.githubusercontent.com/appwrite/appwrite/1.6.2/docker-compose.yml -o docker-compose.yml + curl -sL https://raw.githubusercontent.com/appwrite/appwrite/1.6.2/.env -o .envThis locks the baseline for fair, deterministic comparisons.
app/views/general/error.phtml (1)
56-58: Inconsistent size-class naming (large-error↔︎small-error)
$isSimpleMessage=truemaps tolarge-error, while complex messages map tosmall-error, which is counter-intuitive.
If this is accidental, swap the class names for clarity; otherwise consider renaming the boolean for readability..env (1)
76-84: Verify naming consistency between “Functions” and new “Compute” varsYou introduce
_APP_COMPUTE_*limits (size, build timeout, CPU, memory …) yet_APP_FUNCTIONS_TIMEOUTremains the old name for per-function timeout.
If functions are now part of “Compute”, consider either:
- Adding an
_APP_COMPUTE_TIMEOUTand deprecating_APP_FUNCTIONS_TIMEOUT, or- Documenting that functions still read the legacy variable while sites use
_APP_SITES_TIMEOUT.Please double-check runtime code paths to avoid a mismatch in timeout enforcement.
app/controllers/api/storage.php (1)
410-413: SDK metadata looks correct – nice addition of explicit UPLOAD semanticsSetting
type: MethodType::UPLOAD, requestType: ContentType::MULTIPARTmakes the behaviour unambiguous for code-generators and clients; 👍 for tightening the contract.
app/init/resources.php (1)
934-958: Constant safety check
TOKENS_RESOURCE_TYPE_FILESis referenced without auseordefine.
If the constant isn’t defined it will throw anErroron PHP 8+.
Consider importing or adding an explicitdefined()guard.docker-compose.yml (1)
975-978: Verify that_APP_DOMAIN_SITESis defined
_APP_DOMAIN_SITESis passed to multiple services but isn’t present inapp/config/variables.php.
Please confirm it is defined elsewhere; otherwise the variable will be empty inside the containers.app/init/constants.php (1)
76-79:Details
✅ Verification successful
Rename ripple check: do we still reference the old
_APP_FUNCTION_*constants anywhere?The defaults were renamed to
APP_COMPUTE_*, but residual usages ofAPP_FUNCTION_CPUS_DEFAULT/APP_FUNCTION_MEMORY_DEFAULTwill now be undefined and evaluated asnull.
🏁 Script executed:
#!/bin/bash # Find references to the old constants that would now break. rg --fixed-strings --type php 'APP_FUNCTION_CPUS_DEFAULT|APP_FUNCTION_MEMORY_DEFAULT'Length of output: 87
No leftover references to
APP_FUNCTION_*constants
Ran a global search across the PHP codebase and found no usages ofAPP_FUNCTION_CPUS_DEFAULTorAPP_FUNCTION_MEMORY_DEFAULT. The rename to the newAPP_COMPUTE_*constants is safe to merge.app/config/collections/platform.php (1)
228-234:Details
❌ Incorrect review comment
Re-evaluate 1 000 000-byte column size & fix TODO
templatesjumps from 16 384 to 1 000 000 bytes with a// TODO make sure size fitsnote.
• MySQLTEXTis limited to 65 535 B – 1 000 000 silently promotes toMEDIUMTEXT(16 MiB).
• On PostgreSQL the declaration maps toTEXT, so the value is ignored.
Relying on implicit type‐upgrades is risky and platform-specific.- 'size' => 1_000_000, // TODO make sure size fits + // MEDIUMTEXT upper-bound (16 777 215). Set explicit constant to avoid silent type change. + 'size' => Database::LENGTH_MEDIUMTEXT,Remove the TODO once verified.
Would you like a quick shell script that checks the current driver’s max length mapping?
🏁 Script executed:
#!/usr/bin/env bash set -e # Locate the Database class file db_file=$(rg -l "class Database" . | head -n1) if [[ -n "$db_file" ]]; then echo "🔍 Found Database class in: $db_file" echo "📝 Listing LENGTH_* constants defined in Database:" rg "const LENGTH_" -n "$db_file" else echo "❗️ Database class definition not found in repository." fi echo echo "🔍 Searching for any usage of LENGTH_MEDIUMTEXT:" rg "LENGTH_MEDIUMTEXT" -n .Length of output: 574
🏁 Script executed:
#!/usr/bin/env bash set -e echo "🔍 Searching for PHP files defining class Database (excluding tests)…" rg -n --glob "!tests/*" "class Database" . echo echo "🔍 Searching for LENGTH_MEDIUMTEXT constant definitions…" rg -n "const LENGTH_MEDIUMTEXT" --glob "*.php"Length of output: 956
Verify template JSON maximum size and remove TODO
The
templatesfield jumps from 16 384 bytes straight to 1 000 000 bytes, exceeding MySQL’sTEXTlimit (65 535 B → implicitMEDIUMTEXT) and being ignored on PostgreSQL (TEXTis unbounded).Action items:
- Confirm that 1 000 000 bytes is the desired upper bound.
- Remove the
// TODO make sure size fitscomment once confirmed.- To avoid a magic number, define a descriptive constant (for example,
TEMPLATES_MAX_SIZE = 1_000_000) rather than referencing a non-existentDatabase::LENGTH_MEDIUMTEXT.File to update:
- app/config/collections/platform.php (around line 228)
Likely an incorrect or invalid review comment.
app/controllers/general.php (1)
1050-1053: Origin validation bypassed for dev-key – document intent
&& $devKey->isEmpty()bypasses the CSRF origin validator when any dev-key is present. If this is intentional (e.g., internal tooling), add an inline comment explaining the security model; otherwise reconsider.app/config/collections/projects.php (1)
1183-1192: ConstantAPP_COMPUTE_SPECIFICATION_DEFAULTmust be definedThe default value for the
specificationattribute referencesAPP_COMPUTE_SPECIFICATION_DEFAULT.
Compilation will fail if the constant is missing or renamed.Please verify the constant exists in
app/init/constants.php.Also applies to: 1675-1684
| $validators = []; | ||
| $targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', '')); | ||
| if (!$targetCNAME->isKnown() || $targetCNAME->isTest()) { | ||
| $validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME); | ||
| } | ||
| if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) { | ||
| $validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A); | ||
| } | ||
| if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) { | ||
| $validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA); | ||
| } | ||
|
|
||
| if (!$target->isKnown() || $target->isTest()) { | ||
| throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Domain target must be configured as environment variable.'); | ||
| if (empty($validators)) { | ||
| throw new Exception(Exception::GENERAL_SERVER_ERROR, 'At least one of domain targets environment variable must be configured.'); | ||
| } |
There was a problem hiding this comment.
Potential mis-validation when _APP_DOMAIN_TARGET_CNAME is empty
$targetCNAME is always instantiated – even when the env-var is an empty string.
Because an empty string is neither known nor test, the if condition becomes true and a DNS validator gets created with an empty host name.
This will fail every verification attempt and may even hide the real reason from the caller.
- $targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
- if (!$targetCNAME->isKnown() || $targetCNAME->isTest()) {
- $validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
- }
+ $targetCNAMEEnv = System::getEnv('_APP_DOMAIN_TARGET_CNAME', '');
+ if (!empty($targetCNAMEEnv)) {
+ $targetCNAME = new Domain($targetCNAMEEnv);
+ // Skip validation for local/test domains, but validate all real domains.
+ if (!$targetCNAME->isTest()) {
+ $validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
+ }
+ }Side effects:
- Prevents unnecessary look-ups when the variable is not configured.
- Keeps the “at least one validator” logic intact while avoiding false negatives.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $validators = []; | |
| $targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', '')); | |
| if (!$targetCNAME->isKnown() || $targetCNAME->isTest()) { | |
| $validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME); | |
| } | |
| if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) { | |
| $validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A); | } |
| if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) { | |
| $validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA); | |
| } | |
| if (!$target->isKnown() || $target->isTest()) { | |
| throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Domain target must be configured as environment variable.'); | |
| if (empty($validators)) { | |
| throw new Exception(Exception::GENERAL_SERVER_ERROR, 'At least one of domain targets environment variable must be configured.'); | |
| } | |
| $validators = []; | |
| $targetCNAMEEnv = System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''); | |
| if (!empty($targetCNAMEEnv)) { | |
| $targetCNAME = new Domain($targetCNAMEEnv); | |
| // Skip validation for local/test domains, but validate all real domains. | |
| if (!$targetCNAME->isTest()) { | |
| $validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME); | |
| } | |
| } | |
| if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) { | |
| $validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A); | |
| } | |
| if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) { | |
| $validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA); | |
| } | |
| if (empty($validators)) { | |
| throw new Exception(Exception::GENERAL_SERVER_ERROR, 'At least one of domain targets environment variable must be configured.'); | |
| } |
🤖 Prompt for AI Agents
In app/controllers/api/proxy.php around lines 217 to 231, the code creates a
Domain object from the _APP_DOMAIN_TARGET_CNAME environment variable without
checking if it is empty, causing a DNS validator with an empty hostname to be
added and leading to false validation failures. To fix this, add a condition to
check that _APP_DOMAIN_TARGET_CNAME is not empty before instantiating the Domain
object and adding the DNS validator. This prevents unnecessary lookups and
maintains the logic that at least one validator must be configured.
Chore review fixes
Update console
What does this PR do?
Test Plan
(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Screenshots may also be helpful.)
Related PRs and Issues
Checklist
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Documentation
Chores
This release delivers Appwrite Sites, improved resource management, enhanced security, and a more robust developer experience.