Compare commits

...
Author SHA1 Message Date
fogelito c6a8e5710e Merge branch '1.9.x' of https://github.com/appwrite/appwrite into update-migration-processing 2026-05-26 09:57:42 +03:00
Chirag AggarwalandGitHub 4efe1e6890 Merge pull request #12392 from appwrite/fix/preserve-sdk-enum-metadata
Update SDK spec metadata generation
2026-05-26 11:53:00 +05:30
Chirag Aggarwal c7caf8d23d fix: map numeric spec enum keys 2026-05-26 11:33:25 +05:30
Chirag Aggarwal a4d889145b test: expect client web version 2026-05-26 11:28:30 +05:30
Chirag Aggarwal fe1a2f6364 fix: preserve organization project region enum 2026-05-26 11:19:48 +05:30
Chirag Aggarwal 3f0d1d2a27 fix: preserve remaining spec enum metadata 2026-05-26 11:14:52 +05:30
Chirag Aggarwal 08b18f0774 fix: name preserved enum metadata 2026-05-26 11:06:34 +05:30
Chirag Aggarwal 6f1841681f fix: preserve runtime and migration enum metadata 2026-05-26 11:02:52 +05:30
Chirag Aggarwal 29d2a99e92 fix: remove weight from spec metadata 2026-05-26 10:53:50 +05:30
Chirag Aggarwal 17bae22b24 Revert "Merge pull request #12356 from appwrite/fix-account-server-specs-auth"
This reverts commit ff76f3efa0, reversing
changes made to ed14acfc75.
2026-05-26 10:51:52 +05:30
Chirag Aggarwal 6bc5d0dd06 fix: remove endpoint docs appwrite metadata 2026-05-26 10:51:10 +05:30
Chirag Aggarwal 7f97d91f66 fix: order spec defaults before examples 2026-05-26 10:48:13 +05:30
Chirag Aggarwal 6266dfb7ab fix: preserve remaining SDK enum metadata 2026-05-26 10:45:48 +05:30
Chirag Aggarwal 88648b78f0 fix: preserve SDK enum metadata 2026-05-26 10:30:50 +05:30
Chirag AggarwalandGitHub e7f720b8e7 Merge pull request #12358 from appwrite/feat/platform-param-enums
Use platform enum metadata for SDK specs
2026-05-26 10:10:43 +05:30
fogelito 8685266e97 Merge branch '1.9.x' of https://github.com/appwrite/appwrite into update-migration-processing 2026-05-25 19:11:35 +03:00
Chirag Aggarwal e19ca24d5d Update enum metadata tests 2026-05-25 20:36:14 +05:30
Chirag Aggarwal ee97d4ef4d Use compatible HTTP release for platform 2026-05-25 19:27:04 +05:30
Chirag Aggarwal 764fb0d156 Merge remote-tracking branch 'origin/1.9.x' into feat/platform-param-enums
# Conflicts:
#	composer.lock
2026-05-25 19:23:54 +05:30
Chirag Aggarwal a659b0b187 Use stable Utopia dependency releases 2026-05-25 19:21:35 +05:30
Shmuel FogelandGitHub 22be6514fb Merge pull request #12293 from appwrite/users-skip-targets
skip subQueryTargets in users route
2026-05-25 12:11:58 +03:00
Jake BarnbyandGitHub 7e4645ffbd Merge branch '1.9.x' into users-skip-targets 2026-05-25 20:09:58 +12:00
Damodar LohaniandGitHub 4b801273c0 Merge pull request #12384 from appwrite/CLO-4385-fix-event-params-on-chunked-retry
fix(uploads): reset queueForEvents on idempotent chunked-upload retry
2026-05-25 13:04:08 +05:45
Damodar LohaniandClaude Opus 4.7 d6ca57d008 fix(uploads): reset queueForEvents on idempotent chunked-upload retry
The early-return branches added in #12138 for already-complete chunked
uploads bypass the trailing $queueForEvents->setParam('bucketId', ...)
calls. The action returns cleanly, the shutdown hook then calls
Event::generateEvents with empty params, throws \InvalidArgumentException,
and the error handler maps it to HTTP 500.

Reset the queue on each early-return path so the shutdown short-circuits
on the empty event string -- the resource was created on a previous
request and that request already fired the event; replaying it would
double-trigger webhooks/functions.

Applied to Storage Files Create, Functions Deployments Create, and
Sites Deployments Create -- all three endpoints share the same pattern
introduced by #12138.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 06:36:25 +00:00
Chirag AggarwalandGitHub 03555fa365 Merge pull request #12376 from appwrite/codex/builds-worker-span-logs
Replace builds worker logs with span attributes
2026-05-25 09:00:38 +05:30
fogelito b07046eaba Merge branch '1.9.x' of https://github.com/appwrite/appwrite into update-migration-processing 2026-05-24 10:19:42 +03:00
Damodar LohaniandGitHub 9cbd5be707 Merge pull request #12329 from appwrite/feat/actor-type-constants-CLO-4357
feat!: rename ACTIVITY_TYPE_*, ROLE_APPS, isApp() to ACTOR_TYPE_*, ROLE_KEYS, isKey() + bump utopia-php/audit to ^2.4
2026-05-24 10:02:05 +05:45
Damodar LohaniandGitHub e9aaea19a4 Merge pull request #12378 from appwrite/CLO-4364-bump-php-runtimes-0.20.1
chore: bump appwrite/php-runtimes to 0.20.1
2026-05-24 09:44:45 +05:45
Damodar Lohani 3fc5fd8fcf chore: bump appwrite/php-runtimes to 0.20.1 2026-05-24 03:08:25 +00:00
Damodar Lohani 5f63100f4c fix(presences): rename isApp() callers to isKey() (new files from upstream 1.9.x merge) 2026-05-24 02:20:47 +00:00
Damodar Lohani 39aeecc58c fix(audits): drop removed 'location' field from event payload (utopia-php/audit 2.4 schema) 2026-05-24 02:20:47 +00:00
Damodar Lohani ce31a4f336 feat!: rename User::ROLE_APPS to ROLE_KEYS and isApp() to isKey() 2026-05-24 02:20:47 +00:00
Damodar Lohani 5f1e537e53 chore: bump utopia-php/audit to ^2.4 2026-05-24 02:20:47 +00:00
Damodar LohaniandClaude Opus 4.7 27370b6acb feat!: rename ACTIVITY_TYPE_* constants to ACTOR_TYPE_*
Renames the actor identity constants used by the audit/auth flow:

- ACTIVITY_TYPE_USER             -> ACTOR_TYPE_USER             ('user')
- ACTIVITY_TYPE_ADMIN            -> ACTOR_TYPE_ADMIN            ('admin')
- ACTIVITY_TYPE_GUEST            -> ACTOR_TYPE_GUEST            ('guest')
- ACTIVITY_TYPE_KEY_PROJECT      -> ACTOR_TYPE_KEY_PROJECT      ('keyProject')
- ACTIVITY_TYPE_KEY_ACCOUNT      -> ACTOR_TYPE_KEY_ACCOUNT      ('keyAccount')
- ACTIVITY_TYPE_KEY_ORGANIZATION -> ACTOR_TYPE_KEY_ORGANIZATION ('keyOrganization')

Values are unchanged. Call sites updated in:
- app/controllers/shared/api.php
- src/Appwrite/Platform/Workers/Audits.php

Audit payload key rename (userType -> actorType) and utopia-php/audit
bump will land in a follow-up PR.

BREAKING CHANGE: ACTIVITY_TYPE_* global constants are removed. Any
downstream extension or plugin importing those names must be updated
to the ACTOR_TYPE_* equivalents.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 02:20:17 +00:00
Chirag Aggarwal f1abdde9cf Replace builds worker logs with span attributes 2026-05-23 20:37:34 +05:30
Harsh MahajanandGitHub 8436fb0175 Merge pull request #12375 from appwrite/fix/organization-projects-api
Fix: organization project API headers and queries
2026-05-22 16:46:45 +05:30
harsh mahajan 6a4dcd76a7 Keep organization projects schema unchanged 2026-05-22 15:45:32 +05:30
harsh mahajan e831b3e952 Add project status index 2026-05-22 15:39:16 +05:30
harsh mahajan 4dec4f2ff2 Fix organization project API headers and queries 2026-05-22 15:32:44 +05:30
Harsh MahajanandGitHub aa4c6b6e8f Merge pull request #12374 from appwrite/fix/smtp-test-email-missing-platform-vars
Fix missing platform variables in SMTP test email template
2026-05-22 13:39:59 +05:30
harsh mahajan 2628cc31fc Remove unused $plan injection 2026-05-22 13:12:50 +05:30
harsh mahajanandHarsh Mahajan e3768ce8ee Fix missing platform variables in SMTP test email template
The SMTP test email uses email-base-styled.tpl as its base template,
which contains {{platform}}, {{logoUrl}}, {{accentColor}}, and social/
legal link placeholders. These were never passed as template variables,
causing them to render as literal strings (e.g. "{{platform}} logo").

Inject the platform config and pass the variables to MailMessage,
matching the pattern used by OTP and magic-url email flows.

Co-Authored-By: Harsh Mahajan <harsh@appwrite.io>
2026-05-22 13:03:48 +05:30
Jake BarnbyandGitHub dfc5f1c8dc Merge pull request #12371 from appwrite/fix-project-smtp-port-type
fix(project): cast smtpPort to int in response model
2026-05-22 19:09:07 +12:00
Harsh MahajanandGitHub e375009a49 Merge pull request #12373 from appwrite/feat-ser-401-expose-build-trigger-fields
Expose providerBranches and providerPaths in Function and Site response
2026-05-22 12:36:59 +05:30
harsh mahajanandHarsh Mahajan cf1623bc91 Expose providerBranches and providerPaths in Function and Site response models
These fields were already persisted on update but omitted from the response
model, causing them to disappear after a page refresh in the console.

Co-Authored-By: Harsh Mahajan <harsh@appwrite.io>
2026-05-22 12:27:05 +05:30
Prem Palanisamy e364082577 fix(project): cast smtpPort to int in response model 2026-05-22 07:52:25 +01:00
Luke B. SilverandGitHub 9951ccdca3 Merge pull request #12338 from appwrite/fix/coroutines-correctness
chore: migrate to utopia-php/http feat-safe-wildcards
2026-05-21 21:58:55 +01:00
loks0nandClaude Opus 4.7 035cbacbfb Use 'params' injection in V20 filter
Drops the redundant Route::resolveParams() call. The matched path
params are now provided directly via the new frame-local 'params'
injection from utopia-php/http, avoiding a second URL parse.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:09:55 +01:00
loks0nandClaude Opus 4.7 690c72b789 Use 'route' injection in remaining api/auth init hooks
The 'route' injection is frame-local and non-nullable inside a
matched action's hooks. Replaces \$utopia->match() lookups in api.php
and auth.php init hooks, drops the dead \$utopia inject from the
session shutdown hook, and removes the now-redundant null guards.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:09:41 +01:00
loks0nandClaude Opus 4.7 dd0c8af160 Use 'route' injection in shutdown hooks
The 'route' injection introduced in utopia-php/http feat-safe-wildcards
is frame-local and non-nullable inside a matched action's hooks, so
the shutdown handlers in api.php and mock.php no longer need to call
match() and dereference a nullable result.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:09:41 +01:00
loks0nandClaude Opus 4.7 933fffd763 Use route template instead of request URI for documentsdb path check
The documentsdb/vectorsdb routes are registered with
setHttpPath('/v1/documentsdb/...') with no aliases, so getPath()
returns a template containing the substring we're matching against
— and matches the prior getMatchedPath() semantics without depending
on the raw request URI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:09:41 +01:00
loks0nandClaude Opus 4.7 1538927486 chore: migrate to utopia-php/http feat-safe-wildcards
Adopts the new safe-wildcard dispatch primitive from
utopia-php/http#feat-safe-wildcards. Http::execute() is now the
re-entrant dispatch entry point and Http::match() is pure (returns
?RouteMatch). The removed Http::getRoute()/setRoute(),
Route::getMatchedPath(), Route::getPathValues() callsites are migrated
to the new API.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:09:41 +01:00
Harsh MahajanandGitHub 49bf24d388 Merge pull request #11955 from appwrite/feat-ser-401-custom-triggers
Feat: custom triggers for VCS builds
2026-05-21 19:08:38 +05:30
harsh mahajan f62d765bbf format 2026-05-21 18:46:18 +05:30
harsh mahajanandClaude Sonnet 4.6 268dd50106 Use Globstar validator directly, remove BuildTrigger wrapper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 18:43:34 +05:30
Harsh MahajanandGitHub 4eb956b820 Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-05-21 16:37:24 +05:30
harsh mahajan 01a6d6e4d6 Inline VCS build trigger checks 2026-05-21 15:35:44 +05:30
harsh mahajan c1e902c79c Restore deployments on branch creation 2026-05-21 15:32:35 +05:30
harsh mahajan 9bcb4d7ca7 Clarify renamed PR file filtering 2026-05-21 15:31:05 +05:30
Matej BačoandGitHub f77205295b Merge pull request #12309 from appwrite/feat-public-organization-api
Feat: Public organization API
2026-05-21 10:25:59 +02:00
Matej BačoandGitHub 781df9d4cf Merge branch '1.9.x' into feat-public-organization-api 2026-05-21 09:42:32 +02:00
Jake Barnby 238b4e447d test: stabilize function logging executions 2026-05-21 18:38:59 +12:00
Jake Barnby 349ac6bbc1 test: stabilize account log pagination 2026-05-21 16:47:45 +12:00
Jake BarnbyandGitHub dca75b059b Merge pull request #12361 from appwrite/fix-smtp-template-regressions
Fix SMTP empty sender regressions
2026-05-21 12:42:51 +12:00
Jake Barnby fd145e988a test: align versions endpoint expectations 2026-05-21 12:18:11 +12:00
Jake Barnby c6ac0f28e4 chore: restore twig security update 2026-05-21 12:16:06 +12:00
Jake Barnby 52d7ebd41e chore: revert to 2.0.0-rc.1 2026-05-21 10:59:37 +12:00
Jake Barnby 41ff2ed48e chore: update lock 2026-05-21 10:37:36 +12:00
harsh mahajan 436064e7cc Revert test fixture change 2026-05-20 23:44:11 +05:30
harsh mahajan a3ae9f39ec Fix SMTP empty sender regressions 2026-05-20 23:40:41 +05:30
fogelito 19ab27bf57 Merge branch '1.9.x' of https://github.com/appwrite/appwrite into update-migration-processing 2026-05-20 17:39:45 +03:00
fogelito 9ad625da36 formatting 2026-05-20 16:38:17 +03:00
fogelito 26e8792b63 Use $updatedAt 2026-05-20 16:37:50 +03:00
fogelito c2df9409d6 Use $updatedAt 2026-05-20 16:00:35 +03:00
fogelito fd6146888b Merge branch '1.9.x' of https://github.com/appwrite/appwrite into users-skip-targets 2026-05-20 15:54:15 +03:00
Chirag Aggarwal 91227249b8 chore: use enum metadata server branch 2026-05-20 17:47:45 +05:30
Matej Bačo 4400eedbae Add proper test coverage 2026-05-20 13:56:47 +02:00
Matej Bačo cbcf86e362 Add missing delete endpoint 2026-05-20 13:49:40 +02:00
Chirag Aggarwal 83dc606c14 Use platform enum metadata for SDK specs 2026-05-20 17:19:35 +05:30
Matej Bačo e69b9eb428 PR cleanup 2026-05-20 13:49:29 +02:00
Harsh MahajanandGitHub 8cfc28f08c Merge pull request #12348 from appwrite/fix-smtp-template-empty-string-params
fix: allow empty string to clear optional SMTP and email template fields
2026-05-20 17:00:14 +05:30
harsh mahajan 5473be5756 chore: revert twig override, restore sdk-generator to 1.31.0 2026-05-20 16:56:56 +05:30
harsh mahajan a3fca62818 chore: bump twig/twig to ^3.26 to fix security advisories 2026-05-20 16:45:17 +05:30
harsh mahajan d397ab9b40 chore: update composer dependencies 2026-05-20 16:34:15 +05:30
Harsh MahajanandGitHub e59e726d38 Merge branch '1.9.x' into fix-smtp-template-empty-string-params 2026-05-20 16:28:06 +05:30
harsh mahajan 8272aa6fa2 fix: remove unnecessary null coalescing on senderEmail 2026-05-20 16:27:52 +05:30
harsh mahajan 43b9bf8152 fix: remove redundant senderEmail empty check before setFrom 2026-05-20 16:25:04 +05:30
fogelito 7312f4bfe0 Merge branch '1.9.x' of https://github.com/appwrite/appwrite into users-skip-targets 2026-05-20 13:50:31 +03:00
fogelito a83c01db65 Created at 2026-05-20 13:46:29 +03:00
fogelito d50dcad24a Update message 2026-05-20 13:15:54 +03:00
Chirag AggarwalandGitHub 5df3280131 Merge pull request #12357 from appwrite/fix/spec-regional-endpoint-validation
Fix generated spec endpoint and enum defaults
2026-05-20 15:21:12 +05:30
fogelito 151ef8ab7c console info 2026-05-20 12:41:38 +03:00
Chirag Aggarwal 515696dd36 Fix generated spec endpoint and enum defaults 2026-05-20 14:58:56 +05:30
fogelito 227e47f121 return presents 2026-05-20 12:27:42 +03:00
fogelito 940fa701da return on transactions 2026-05-20 12:02:34 +03:00
Chirag AggarwalandGitHub ff76f3efa0 Merge pull request #12356 from appwrite/fix-account-server-specs-auth
Fix account server specs auth
2026-05-20 14:26:14 +05:30
fogelito 2ef2d4d498 return for stats 2026-05-20 11:53:07 +03:00
Chirag Aggarwal 0d19894331 Move Web SDK to server platform 2026-05-20 14:09:07 +05:30
Chirag Aggarwal 1d9acf5f29 Fix account SDK specs auth 2026-05-20 14:03:20 +05:30
Harsh MahajanandGitHub d3994b436d Merge branch '1.9.x' into fix-smtp-template-empty-string-params 2026-05-20 11:40:47 +05:30
harsh mahajan cc51f42430 fix: allow SMTP connection test without senderEmail 2026-05-20 11:40:23 +05:30
Matej Bačo 8cf0438a98 Merge branch '1.9.x' into feat-public-organization-api 2026-05-19 17:20:33 +02:00
Matej Bačo b2ebfa9bb9 Revert unwanted tests 2026-05-19 17:20:15 +02:00
Matej BačoandGitHub ed14acfc75 Merge pull request #12353 from appwrite/fix-trace-ending-too-soon
Fix: subspan ending main request span
2026-05-19 16:57:59 +02:00
Matej Bačo 90df8efe0a Formatting fix 2026-05-19 15:50:48 +02:00
fogelito c1aeaf9bb9 Merge remote-tracking branch 'origin/update-migration-processing' into update-migration-processing 2026-05-19 16:29:57 +03:00
fogelito 2b8d035545 use constant for processing stuck 2026-05-19 16:29:45 +03:00
Matej Bačo f7b09c090b Fix subspan ending main request span 2026-05-19 15:23:34 +02:00
Shmuel FogelGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
d9e4318ab9 Update src/Appwrite/Platform/Workers/Deletes.php
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-05-19 16:01:27 +03:00
Shmuel FogelGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
4523ad5e1f Update src/Appwrite/Platform/Workers/Deletes.php
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-05-19 16:00:55 +03:00
fogelito a67930a18a Remove use 2026-05-19 15:56:19 +03:00
fogelito 24900ee08e retention 2026-05-19 15:54:56 +03:00
fogelito aa3a63c87b Merge branch '1.9.x' of https://github.com/appwrite/appwrite into users-skip-targets 2026-05-19 15:51:12 +03:00
fogelito 586eb3ca19 updateProcessingMigrations 2026-05-19 15:49:55 +03:00
harsh mahajan 8c903ab687 fix: allow empty string to clear optional SMTP and email template fields 2026-05-19 16:29:55 +05:30
Harsh MahajanandGitHub cf101b6a8e Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-05-19 12:35:41 +05:30
harsh mahajanandClaude Sonnet 4.6 74a4ae19ee refactor: remove unnecessary comments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:28:04 +05:30
harsh mahajanandClaude Sonnet 4.6 3b3a04877f feat: remove CommitSkipPatterns - already available in 1.9.x
Keep only branch and path skip trigger logic. Commit message skip
is handled by the existing Contains(VCS_DEPLOYMENT_SKIP_PATTERNS) check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:21:04 +05:30
harsh mahajanandClaude Sonnet 4.6 a4a57bc64d Merge branch '1.9.x' into feat-ser-401-custom-triggers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:20:08 +05:30
fogelito 5c9f360744 Merge branch '1.9.x' of https://github.com/appwrite/appwrite into users-skip-targets 2026-05-17 17:17:09 +03:00
Matej Bačo b627a7d6ff Org key tests 2026-05-15 12:46:27 +02:00
Matej Bačo a0c27afec8 Revert test changes 2026-05-15 11:47:52 +02:00
Matej Bačo 5a0bb57db2 linter fix 2026-05-15 11:45:39 +02:00
Matej Bačo d422b7abdc Final reverts 2026-05-15 11:44:47 +02:00
Matej Bačo 34078ad9af Revert unwanted changes 2026-05-15 11:37:04 +02:00
Matej Bačo 2d94704948 Formatting fix 2026-05-15 11:30:06 +02:00
Matej Bačo cd54e91784 Deprecate old projects endpoints 2026-05-15 11:27:19 +02:00
Matej Bačo 79f536445e Revive old endpoints 2026-05-15 11:26:35 +02:00
Matej Bačo 11839c6dcc Remove old endpoint aliases 2026-05-15 11:26:22 +02:00
Matej Bačo a9eb9d47a5 Merge branch '1.9.x' into feat-public-organization-api 2026-05-15 11:21:17 +02:00
Matej Bačo 5b109f2f8d Fix org key usecase 2026-05-14 19:52:14 +02:00
Matej Bačo 3e35b888a7 Fix bug 2026-05-14 19:47:59 +02:00
Matej Bačo bcd2bfe5b2 Fix security 2026-05-14 19:34:49 +02:00
Matej Bačo d7e29a4dae fix more tests 2026-05-14 19:03:14 +02:00
Matej Bačo 3596662fec Update more tests 2026-05-14 18:42:30 +02:00
Matej Bačo f40c7d415c Prioritize org id header 2026-05-14 18:26:47 +02:00
Matej Bačo 176d59e7c9 Fix broken test after breaking change
List ALL projects no longer exists - we now have list project per organization
2026-05-14 18:02:20 +02:00
Matej Bačo bb25a36cf5 Fix project creation 401 expectation tests 2026-05-14 17:53:03 +02:00
Matej Bačo f37e091b77 Fix specs generation 2026-05-14 17:50:36 +02:00
Matej Bačo 18380a679d Fix backwards compatibility 2026-05-14 17:46:13 +02:00
Matej Bačo 2a82604a2b Better backwards compatibility for project creation 2026-05-14 17:36:03 +02:00
Matej Bačo b618bf1353 Fix inability to CRUD projects 2026-05-14 17:26:08 +02:00
fogelito 3684fee2a2 Merge branch '1.9.x' of https://github.com/appwrite/appwrite into users-skip-targets 2026-05-14 14:58:50 +03:00
Matej Bačo aaa870e656 Formatting fixes 2026-05-14 13:52:34 +02:00
Matej Bačo 94274381ff agentic migration fixes 2026-05-14 13:52:25 +02:00
fogelito d9446fa892 address 2026-05-14 14:45:00 +03:00
Matej Bačo 8a4a6d83d4 Manual migration fixes 2026-05-14 13:06:39 +02:00
Matej Bačo b524b9f934 Fix scopes 2026-05-14 12:18:09 +02:00
Matej Bačo 275a6fe078 merge endpoints as aliases 2026-05-14 12:01:51 +02:00
Matej Bačo 8b4c90e603 Introduce organization endpoints 2026-05-14 11:47:46 +02:00
fogelito 1435e2c526 use max 2026-05-13 08:41:14 +03:00
fogelito 2ea66a0d8b APP_LIMIT_SUBQUERY 2026-05-13 08:36:57 +03:00
fogelito 2d5289c383 Merge branch '1.9.x' of https://github.com/appwrite/appwrite into users-skip-targets 2026-05-12 20:55:54 +03:00
fogelito 06068c0406 skip subQueryTargets 2026-05-12 20:51:57 +03:00
harsh mahajanandClaude Sonnet 4.6 90f5f9b30b refactor: standalone regex matching for commit skip patterns
Replace directive-extraction approach with word-boundary regex matching
so plain-word patterns like "skip appwrite" and "appwrite skip" work
alongside bracket directives. Use \s+ between word tokens (required
space) and \s* only after ":" tokens (git trailer flexibility).
Add tests for "skip appwrite" and "appwrite skip" with case insensitivity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 18:25:39 +05:30
Harsh MahajanandGitHub 408a12322a Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-05-07 18:17:27 +05:30
harsh mahajan 61cee5892a fix: tighten commit skip directive matching 2026-05-05 18:23:14 +05:30
Harsh MahajanandGitHub a77558807c Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-05-05 17:58:54 +05:30
harsh mahajanandClaude Sonnet 4.6 40c2e1a1fa feat: skip deployment on commit message pattern match
Add providerCommitSkipPatterns array field to functions and sites.
Any commit message containing one of the patterns (case-insensitive
substring) skips the VCS-triggered deployment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 13:09:38 +05:30
harsh mahajan e7405b4393 addressed comments 2026-04-30 13:01:00 +05:30
Harsh MahajanandGitHub 3eabca1d7a Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-04-30 12:10:16 +05:30
Harsh MahajanandGitHub ec984de510 Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-04-29 17:23:08 +05:30
harsh mahajan 2d3c1086ae add endpoints 2026-04-29 13:50:40 +05:30
Harsh MahajanandGitHub 9c646c2893 Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-04-29 11:25:05 +05:30
Harsh MahajanandGitHub 1eb7bf7619 Merge branch '1.9.x' into feat-ser-401-custom-triggers 2026-04-27 15:14:58 +05:30
harsh mahajan 63f04f893d fix composer 2026-04-20 12:18:26 +05:30
Hemachandarandharsh mahajan aa5543ac0a filter out null values 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan 60e51548e8 more tests 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan e802102c8f fix exclusion sub-directory 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan 87f29c6889 include previous_filename 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan a70d241da0 fix path trigger 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan e17cdc2bd4 fix pattern logic 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan a4f174ea7e update VCS 2026-04-20 12:02:07 +05:30
Hemachandarandharsh mahajan 175fcb51a8 remove default 2026-04-20 12:00:27 +05:30
Hemachandarandharsh mahajan 772358ff51 more tests 2026-04-20 12:00:27 +05:30
Hemachandarandharsh mahajan abad809a91 get PR files in Appwrite 2026-04-20 12:00:27 +05:30
Hemachandarandharsh mahajan 076e64886e validator pattern 2026-04-20 11:59:57 +05:30
harsh mahajan 88107ee7b3 feat: implement custom triggers for VCS builds 2026-04-20 11:57:57 +05:30
191 changed files with 2765 additions and 1714 deletions
+44
View File
@@ -841,6 +841,28 @@ return [
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('providerBranches'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => false,
'default' => [],
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('providerPaths'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => false,
'default' => [],
'array' => true,
'filters' => [],
],
],
'indexes' => [
[
@@ -1320,6 +1342,28 @@ return [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('providerBranches'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => false,
'default' => [],
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('providerPaths'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => false,
'default' => [],
'array' => true,
'filters' => [],
],
],
'indexes' => [
[
+1
View File
@@ -22,6 +22,7 @@ return [
'X-Appwrite-Locale',
'X-Appwrite-Mode',
'X-Appwrite-JWT',
'X-Appwrite-Organization',
'X-Appwrite-Response-Format',
'X-Appwrite-Timeout',
'X-Appwrite-ID',
+1 -1
View File
@@ -150,7 +150,7 @@ return [
'label' => 'Owner',
'scopes' => \array_merge($member, $admins),
],
User::ROLE_APPS => [
User::ROLE_KEYS => [
'label' => 'Applications',
'scopes' => ['global', 'health.read', 'graphql'],
],
+3 -2
View File
@@ -67,6 +67,7 @@ use Utopia\Emails\Email;
use Utopia\Emails\Validator\Email as EmailValidator;
use Utopia\Http\Http;
use Utopia\Locale\Locale;
use Utopia\Platform\Enum;
use Utopia\Storage\Validator\FileName;
use Utopia\System\System;
use Utopia\Validator;
@@ -1243,7 +1244,7 @@ Http::get('/v1/account/sessions/oauth2/:provider')
))
->label('abuse-limit', 50)
->label('abuse-key', 'ip:{ip}')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.', enum: new Enum(name: 'OAuthProvider', exclude: ['mock', 'mock-unverified']))
->param('success', '', fn ($redirectValidator) => $redirectValidator, 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['redirectValidator'])
->param('failure', '', fn ($redirectValidator) => $redirectValidator, 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['redirectValidator'])
->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
@@ -2009,7 +2010,7 @@ Http::get('/v1/account/tokens/oauth2/:provider')
))
->label('abuse-limit', 50)
->label('abuse-key', 'ip:{ip}')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn ($node) => (!$node['mock'])))) . '.', enum: new Enum(name: 'OAuthProvider', exclude: ['mock', 'mock-unverified']))
->param('success', '', fn ($redirectValidator) => $redirectValidator, 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['redirectValidator'])
->param('failure', '', fn ($redirectValidator) => $redirectValidator, 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['redirectValidator'])
->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
+1 -1
View File
@@ -39,7 +39,7 @@ Http::init()
if (
array_key_exists('graphql', $project->getAttribute('apis', []))
&& !$project->getAttribute('apis', [])['graphql']
&& !($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
&& !($user->isPrivileged($authorization->getRoles()) || $user->isKey($authorization->getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
+5 -4
View File
@@ -47,6 +47,7 @@ use Utopia\Database\Validator\UID;
use Utopia\Emails\Validator\Email;
use Utopia\Http\Http;
use Utopia\Locale\Locale;
use Utopia\Platform\Enum;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
@@ -364,7 +365,7 @@ Http::post('/v1/messaging/providers/smtp')
->param('port', 587, new Range(1, 65535), 'The default SMTP server port.', true)
->param('username', '', new Text(0), 'Authentication username.', true)
->param('password', '', new Text(0), 'Authentication password.', true)
->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be omitted, \'ssl\', or \'tls\'', true)
->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be omitted, \'ssl\', or \'tls\'', true, enum: new Enum(name: 'SmtpEncryption'))
->param('autoTLS', true, new Boolean(), 'Enable SMTP AutoTLS feature.', true)
->param('mailer', '', new Text(0), 'The value to use for the X-Mailer header.', true)
->param('fromName', '', new Text(128, 0), 'Sender Name.', true)
@@ -1602,7 +1603,7 @@ Http::patch('/v1/messaging/providers/smtp/:providerId')
->param('port', null, new Nullable(new Range(1, 65535)), 'SMTP port.', true)
->param('username', '', new Text(0), 'Authentication username.', true)
->param('password', '', new Text(0), 'Authentication password.', true)
->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be \'ssl\' or \'tls\'', true)
->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be \'ssl\' or \'tls\'', true, enum: new Enum(name: 'SmtpEncryption'))
->param('autoTLS', null, new Nullable(new Boolean()), 'Enable SMTP AutoTLS feature.', true)
->param('mailer', '', new Text(0), 'The value to use for the X-Mailer header.', true)
->param('fromName', '', new Text(128), 'Sender Name.', true)
@@ -3501,7 +3502,7 @@ Http::post('/v1/messaging/messages/push')
->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->param('contentAvailable', false, new Boolean(), 'If set to true, the notification will be delivered in the background. Available only for iOS Platform.', true)
->param('critical', false, new Boolean(), 'If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.', true)
->param('priority', 'high', new WhiteList(['normal', 'high']), 'Set the notification priority. "normal" will consider device state and may not deliver notifications immediately. "high" will always attempt to immediately deliver the notification.', true)
->param('priority', 'high', new WhiteList(['normal', 'high']), 'Set the notification priority. "normal" will consider device state and may not deliver notifications immediately. "high" will always attempt to immediately deliver the notification.', true, enum: new Enum(name: 'MessagePriority'))
->inject('queueForEvents')
->inject('dbForProject')
->inject('dbForPlatform')
@@ -4388,7 +4389,7 @@ Http::patch('/v1/messaging/messages/push/:messageId')
->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->param('contentAvailable', null, new Nullable(new Boolean()), 'If set to true, the notification will be delivered in the background. Available only for iOS Platform.', true)
->param('critical', null, new Nullable(new Boolean()), 'If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.', true)
->param('priority', null, new Nullable(new WhiteList(['normal', 'high'])), 'Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification.', true)
->param('priority', null, new Nullable(new WhiteList(['normal', 'high'])), 'Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification.', true, enum: new Enum(name: 'MessagePriority'))
->inject('queueForEvents')
->inject('dbForProject')
->inject('dbForPlatform')
+8 -1
View File
@@ -10,6 +10,7 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DateTimeValidator;
use Utopia\Http\Http;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
Http::get('/v1/project/usage')
@@ -31,7 +32,13 @@ Http::get('/v1/project/usage')
))
->param('startDate', '', new DateTimeValidator(), 'Starting date for the usage')
->param('endDate', '', new DateTimeValidator(), 'End date for the usage')
->param('period', '1d', new WhiteList(['1h', '1d']), 'Period used', true)
->param('period', '1d', new WhiteList(['1h', '1d']), 'Period used', true, enum: new Enum(
name: 'ProjectUsageRange',
map: [
'1h' => 'OneHour',
'1d' => 'OneDay',
]
))
->inject('response')
->inject('project')
->inject('dbForProject')
+38 -5
View File
@@ -63,6 +63,7 @@ use Utopia\Emails\Email;
use Utopia\Emails\Validator\Email as EmailValidator;
use Utopia\Http\Http;
use Utopia\Locale\Locale;
use Utopia\Platform\Enum;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
@@ -432,7 +433,7 @@ Http::post('/v1/users/sha')
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
->param('email', '', new EmailValidator(), 'User email.')
->param('password', '', new Password(), 'User password hashed using SHA.')
->param('passwordVersion', '', new WhiteList(['sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']), "Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'", true)
->param('passwordVersion', '', new WhiteList(['sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']), "Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'", true, enum: new Enum(name: 'PasswordHash'))
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
@@ -606,7 +607,7 @@ Http::post('/v1/users/:userId/targets')
))
->param('targetId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
->param('providerType', '', new WhiteList([MESSAGE_TYPE_EMAIL, MESSAGE_TYPE_SMS, MESSAGE_TYPE_PUSH]), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.')
->param('providerType', '', new WhiteList([MESSAGE_TYPE_EMAIL, MESSAGE_TYPE_SMS, MESSAGE_TYPE_PUSH]), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.', enum: new Enum(name: 'MessagingProviderType'))
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true, ['dbForProject'])
->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true)
@@ -732,6 +733,13 @@ Http::get('/v1/users')
$cursor->setValue($cursorDocument);
}
$skipFilters = ['subQueryAuthenticators', 'subQuerySessions', 'subQueryTokens', 'subQueryChallenges', 'subQueryMemberships'];
$selects = Query::getByType($queries, [Query::TYPE_SELECT]);
if (empty($selects)) {
$skipFilters[] = 'subQueryTargets';
}
$users = [];
$total = 0;
@@ -744,7 +752,32 @@ Http::get('/v1/users')
} catch (QueryException $e) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
}, ['subQueryAuthenticators', 'subQuerySessions', 'subQueryTokens', 'subQueryChallenges', 'subQueryMemberships']);
}, $skipFilters);
if (empty($selects) && !empty($users)) {
$sequences = [];
foreach ($users as $user) {
$sequences[] = $user->getSequence();
}
try {
$targets = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('targets', [
Query::equal('userInternalId', $sequences),
Query::limit(PHP_INT_MAX),
]));
} catch (QueryException $e) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$targetsByUser = [];
foreach ($targets as $target) {
$targetsByUser[$target->getAttribute('userInternalId')][] = $target;
}
foreach ($users as $user) {
$user->setAttribute('targets', $targetsByUser[$user->getSequence()] ?? []);
}
}
$response->dynamic(new Document([
'users' => $users,
@@ -2286,7 +2319,7 @@ Http::delete('/v1/users/:userId/mfa/authenticators/:type')
)
])
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.')
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.', enum: new Enum(name: 'AuthenticatorType'))
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
@@ -2799,7 +2832,7 @@ Http::get('/v1/users/usage')
)
]
))
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(name: 'UsageRange'))
->inject('response')
->inject('dbForProject')
->inject('authorization')
+9 -8
View File
@@ -835,7 +835,8 @@ Http::init()
->inject('authorization')
->inject('publisherForDeletes')
->inject('executionsRetentionCount')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, Event $queueForEvents, Bus $bus, Executor $executor, array $platform, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization, DeletePublisher $publisherForDeletes, int $executionsRetentionCount) {
->inject('params')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, Event $queueForEvents, Bus $bus, Executor $executor, array $platform, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization, DeletePublisher $publisherForDeletes, int $executionsRetentionCount, array $params) {
/*
* Appwrite Router
*/
@@ -844,14 +845,14 @@ Http::init()
// Only run Router when external domain
if (!\in_array($hostname, $platformHostnames) || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $publisherForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
$utopia->match($request)?->route->label('router', true);
}
}
/*
* Request format
*/
$route = $utopia->getRoute();
$route = $utopia->match($request)?->route;
$request->setRoute($route);
if ($route === null) {
@@ -876,7 +877,7 @@ Http::init()
}
if (version_compare($requestFormat, '1.8.0', '<')) {
$dbForProject = $getProjectDB($project);
$request->addFilter(new RequestV20($dbForProject, $route->getPathValues($request)));
$request->addFilter(new RequestV20($dbForProject, $params));
}
if (version_compare($requestFormat, '1.9.0', '<')) {
$request->addFilter(new RequestV21());
@@ -1154,7 +1155,7 @@ Http::options()
// Only run Router when external domain
if (!in_array($request->getHostname(), $platformHostnames) || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $publisherForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
$utopia->match($request)?->route->label('router', true);
}
}
@@ -1189,7 +1190,7 @@ Http::error()
->inject('authorization')
->action(function (Throwable $error, Http $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, Bus $bus, Document $devKey, Authorization $authorization) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$route = $utopia->getRoute();
$route = $utopia->match($request)?->route;
$class = \get_class($error);
$code = $error->getCode();
$message = $error->getMessage();
@@ -1555,7 +1556,7 @@ Http::get('/robots.txt')
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $publisherForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
$utopia->match($request)?->route->label('router', true);
}
}
});
@@ -1589,7 +1590,7 @@ Http::get('/humans.txt')
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $publisherForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
$utopia->match($request)?->route->label('router', true);
}
}
});
+3 -4
View File
@@ -13,6 +13,7 @@ use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\UID;
use Utopia\Http\Http;
use Utopia\Http\Route;
use Utopia\Locale\Locale;
use Utopia\System\System;
use Utopia\Validator\Text;
@@ -283,13 +284,11 @@ Http::get('/v1/mock/github/callback')
Http::shutdown()
->groups(['mock'])
->inject('utopia')
->inject('response')
->inject('request')
->action(function (Http $utopia, Response $response, Request $request) {
->inject('route')
->action(function (Response $response, Route $route) {
$result = [];
$route = $utopia->getRoute();
$path = APP_STORAGE_CACHE . '/tests.json';
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
+24 -40
View File
@@ -37,6 +37,7 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Authorization\Input;
use Utopia\Database\Validator\Roles;
use Utopia\Http\Http;
use Utopia\Http\Route;
use Utopia\Span\Span;
use Utopia\System\System;
use Utopia\Telemetry\Adapter as Telemetry;
@@ -85,7 +86,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
Http::init()
->groups(['api'])
->inject('utopia')
->inject('route')
->inject('request')
->inject('dbForPlatform')
->inject('dbForProject')
@@ -98,11 +99,7 @@ Http::init()
->inject('team')
->inject('apiKey')
->inject('authorization')
->action(function (Http $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, AuditContext $auditContext, Document $project, User $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) {
$route = $utopia->getRoute();
if ($route === null) {
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
}
->action(function (Route $route, Request $request, Database $dbForPlatform, Database $dbForProject, AuditContext $auditContext, Document $project, User $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) {
/**
* Handle user authentication and session validation.
@@ -178,8 +175,8 @@ Http::init()
$role = $apiKey->getRole();
$scopes = $apiKey->getScopes();
// Handle special app role case
if ($apiKey->getRole() === User::ROLE_APPS) {
// Handle special key role case
if ($apiKey->getRole() === User::ROLE_KEYS) {
// Disable authorization checks for project API keys
// Dynamic supported for backwards compatibility
if (($apiKey->getType() === API_KEY_STANDARD || $apiKey->getType() === API_KEY_EPHEMERAL || $apiKey->getType() === 'dynamic') && $apiKey->getProjectId() === $project->getId()) {
@@ -189,7 +186,7 @@ Http::init()
$user = new User([
'$id' => '',
'status' => true,
'type' => ACTIVITY_TYPE_KEY_PROJECT,
'type' => ACTOR_TYPE_KEY_PROJECT,
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '',
'name' => $apiKey->getName(),
@@ -261,9 +258,9 @@ Http::init()
$userClone = clone $user;
$userClone->setAttribute('type', match ($apiKey->getType()) {
API_KEY_STANDARD => ACTIVITY_TYPE_KEY_PROJECT,
API_KEY_ACCOUNT => ACTIVITY_TYPE_KEY_ACCOUNT,
default => ACTIVITY_TYPE_KEY_ORGANIZATION,
API_KEY_STANDARD => ACTOR_TYPE_KEY_PROJECT,
API_KEY_ACCOUNT => ACTOR_TYPE_KEY_ACCOUNT,
default => ACTOR_TYPE_KEY_ORGANIZATION,
});
$auditContext->user = $userClone;
}
@@ -428,7 +425,7 @@ Http::init()
if (
array_key_exists($namespace, $project->getAttribute('services', []))
&& ! $project->getAttribute('services', [])[$namespace]
&& ! ($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
&& ! ($user->isPrivileged($authorization->getRoles()) || $user->isKey($authorization->getRoles()))
) {
throw new Exception(Exception::GENERAL_SERVICE_DISABLED);
}
@@ -438,7 +435,7 @@ Http::init()
if (
array_key_exists('rest', $project->getAttribute('apis', []))
&& ! $project->getAttribute('apis', [])['rest']
&& ! ($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
&& ! ($user->isPrivileged($authorization->getRoles()) || $user->isKey($authorization->getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
@@ -477,7 +474,7 @@ Http::init()
Http::init()
->groups(['api'])
->inject('utopia')
->inject('route')
->inject('request')
->inject('response')
->inject('project')
@@ -485,21 +482,16 @@ Http::init()
->inject('timelimit')
->inject('devKey')
->inject('authorization')
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, callable $timelimit, Document $devKey, Authorization $authorization) {
->action(function (Route $route, Request $request, Response $response, Document $project, User $user, callable $timelimit, Document $devKey, Authorization $authorization) {
$response->setUser($user);
$request->setUser($user);
$roles = $authorization->getRoles();
$shouldCheckAbuse = System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled'
&& ! $user->isApp($roles)
&& ! $user->isKey($roles)
&& ! $user->isPrivileged($roles)
&& $devKey->isEmpty();
$route = $utopia->getRoute();
if ($route === null) {
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
}
$abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}');
$abuseKeyLabel = (! is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
$closestLimit = null;
@@ -556,7 +548,7 @@ Http::init()
Http::init()
->groups(['api'])
->inject('utopia')
->inject('route')
->inject('request')
->inject('response')
->inject('project')
@@ -574,17 +566,12 @@ Http::init()
->inject('platform')
->inject('authorization')
->inject('cacheControlForStorage')
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Context $usage, FunctionPublisher $publisherForFunctions, Database $dbForProject, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Telemetry $telemetry, array $platform, Authorization $authorization, callable $cacheControlForStorage) {
->action(function (Route $route, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Context $usage, FunctionPublisher $publisherForFunctions, Database $dbForProject, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Telemetry $telemetry, array $platform, Authorization $authorization, callable $cacheControlForStorage) {
$response->setUser($user);
$request->setUser($user);
$route = $utopia->getRoute();
if ($route === null) {
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
}
$path = $route->getMatchedPath();
$path = $route->getPath();
$databaseType = match (true) {
str_contains($path, '/documentsdb') => DATABASE_TYPE_DOCUMENTSDB,
str_contains($path, '/vectorsdb') => DATABASE_TYPE_VECTORSDB,
@@ -615,7 +602,7 @@ Http::init()
$userClone = clone $user;
// $user doesn't support `type` and can cause unintended effects.
if (empty($user->getAttribute('type'))) {
$userClone->setAttribute('type', $mode === APP_MODE_ADMIN ? ACTIVITY_TYPE_ADMIN : ACTIVITY_TYPE_USER);
$userClone->setAttribute('type', $mode === APP_MODE_ADMIN ? ACTOR_TYPE_ADMIN : ACTOR_TYPE_USER);
}
$auditContext->user = $userClone;
}
@@ -623,9 +610,8 @@ Http::init()
$useCache = $route->getLabel('cache', false);
$storageCacheOperationsCounter = $telemetry->createCounter('storage.cache.operations.load');
if ($useCache) {
$route = $utopia->match($request);
$roles = $authorization->getRoles();
$isAppUser = $user->isApp($roles);
$isAppUser = $user->isKey($roles);
$isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview';
$isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && ! $user->isPrivileged($roles);
@@ -761,12 +747,11 @@ Http::init()
*/
Http::shutdown()
->groups(['session'])
->inject('utopia')
->inject('request')
->inject('response')
->inject('project')
->inject('dbForProject')
->action(function (Http $utopia, Request $request, Response $response, Document $project, Database $dbForProject) {
->action(function (Request $request, Response $response, Document $project, Database $dbForProject) {
$sessionLimit = $project->getAttribute('auths', [])['maxSessions'] ?? 0;
if ($sessionLimit === 0) {
@@ -800,7 +785,7 @@ Http::shutdown()
Http::shutdown()
->groups(['api'])
->inject('utopia')
->inject('route')
->inject('request')
->inject('response')
->inject('project')
@@ -820,7 +805,7 @@ Http::shutdown()
->inject('bus')
->inject('apiKey')
->inject('mode')
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Audit $publisherForAudits, Context $usage, UsagePublisher $publisherForUsage, FunctionPublisher $publisherForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization, callable $timelimit, EventProcessor $eventProcessor, Bus $bus, ?Key $apiKey, string $mode) use ($parseLabel) {
->action(function (Route $route, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Audit $publisherForAudits, Context $usage, UsagePublisher $publisherForUsage, FunctionPublisher $publisherForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization, callable $timelimit, EventProcessor $eventProcessor, Bus $bus, ?Key $apiKey, string $mode) use ($parseLabel) {
$responsePayload = $response->getPayload();
@@ -876,7 +861,6 @@ Http::shutdown()
}
}
$route = $utopia->getRoute();
$requestParams = $route->getParamsValues();
/**
@@ -929,7 +913,7 @@ Http::shutdown()
$userClone = clone $user;
// $user doesn't support `type` and can cause unintended effects.
if (empty($user->getAttribute('type'))) {
$userClone->setAttribute('type', $mode === APP_MODE_ADMIN ? ACTIVITY_TYPE_ADMIN : ACTIVITY_TYPE_USER);
$userClone->setAttribute('type', $mode === APP_MODE_ADMIN ? ACTOR_TYPE_ADMIN : ACTOR_TYPE_USER);
}
$auditContext->user = $userClone;
} elseif ($auditContext->user === null || $auditContext->user->isEmpty()) {
@@ -944,7 +928,7 @@ Http::shutdown()
$user = new User([
'$id' => '',
'status' => true,
'type' => ACTIVITY_TYPE_GUEST,
'type' => ACTOR_TYPE_GUEST,
'email' => 'guest.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '',
'name' => 'Guest',
+4 -5
View File
@@ -9,6 +9,7 @@ use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Http\Http;
use Utopia\Http\Route;
use Utopia\System\System;
Http::init()
@@ -32,13 +33,13 @@ Http::init()
Http::init()
->groups(['auth'])
->inject('utopia')
->inject('route')
->inject('request')
->inject('project')
->inject('geodb')
->inject('user')
->inject('authorization')
->action(function (Http $utopia, Request $request, Document $project, Reader $geodb, User $user, Authorization $authorization) {
->action(function (Route $route, Request $request, Document $project, Reader $geodb, User $user, Authorization $authorization) {
$denylist = System::getEnv('_APP_CONSOLE_COUNTRIES_DENYLIST', '');
if (!empty($denylist && $project->getId() === 'console')) {
$countries = explode(',', $denylist);
@@ -49,10 +50,8 @@ Http::init()
}
}
$route = $utopia->match($request);
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$isAppUser = $user->isApp($authorization->getRoles());
$isAppUser = $user->isKey($authorization->getRoles());
if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
return;
+2 -2
View File
@@ -539,7 +539,7 @@ $swoole->onRequest(function ($utopiaRequest, $utopiaResponse) use ($files, $swoo
$app->run($request, $response);
$route = $app->getRoute();
$route = $app->match($request)?->route;
Span::add('http.path', $route?->getPath() ?? 'unknown');
} catch (\Throwable $th) {
Span::error($th);
@@ -555,7 +555,7 @@ $swoole->onRequest(function ($utopiaRequest, $utopiaResponse) use ($files, $swoo
// All good, user is optional information for logger
}
$route = $app->getRoute();
$route = $app->match($request)?->route;
$log = $app->context()->get("log");
+7 -7
View File
@@ -159,14 +159,14 @@ const SESSION_PROVIDER_TOKEN = 'token';
const SESSION_PROVIDER_SERVER = 'server';
/**
* Activity associated with user or the app.
* Actor that performed the request (user, admin, guest, or API key).
*/
const ACTIVITY_TYPE_USER = 'user';
const ACTIVITY_TYPE_ADMIN = 'admin';
const ACTIVITY_TYPE_GUEST = 'guest';
const ACTIVITY_TYPE_KEY_PROJECT = 'keyProject';
const ACTIVITY_TYPE_KEY_ACCOUNT = 'keyAccount';
const ACTIVITY_TYPE_KEY_ORGANIZATION = 'keyOrganization';
const ACTOR_TYPE_USER = 'user';
const ACTOR_TYPE_ADMIN = 'admin';
const ACTOR_TYPE_GUEST = 'guest';
const ACTOR_TYPE_KEY_PROJECT = 'keyProject';
const ACTOR_TYPE_KEY_ACCOUNT = 'keyAccount';
const ACTOR_TYPE_KEY_ORGANIZATION = 'keyOrganization';
/**
* MFA
+1 -1
View File
@@ -266,7 +266,7 @@ Response::setModel(new BaseList('Frameworks List', Response::MODEL_FRAMEWORK_LIS
Response::setModel(new BaseList('Runtimes List', Response::MODEL_RUNTIME_LIST, 'runtimes', Response::MODEL_RUNTIME));
Response::setModel(new BaseList('Deployments List', Response::MODEL_DEPLOYMENT_LIST, 'deployments', Response::MODEL_DEPLOYMENT));
Response::setModel(new BaseList('Executions List', Response::MODEL_EXECUTION_LIST, 'executions', Response::MODEL_EXECUTION));
Response::setModel(new BaseList('Projects List', Response::MODEL_PROJECT_LIST, 'projects', Response::MODEL_PROJECT, true, false));
Response::setModel(new BaseList('Projects List', Response::MODEL_PROJECT_LIST, 'projects', Response::MODEL_PROJECT, true, true));
Response::setModel(new BaseList('Webhooks List', Response::MODEL_WEBHOOK_LIST, 'webhooks', Response::MODEL_WEBHOOK, true, true));
Response::setModel(new BaseList('API Keys List', Response::MODEL_KEY_LIST, 'keys', Response::MODEL_KEY, true, true));
Response::setModel(new BaseList('Dev Keys List', Response::MODEL_DEV_KEY_LIST, 'devKeys', Response::MODEL_DEV_KEY, true, false));
+2 -2
View File
@@ -596,7 +596,7 @@ return function (Container $context): void {
// These endpoints moved from /v1/projects/:projectId/<resource> to /v1/<resource>
// When accessed via the old alias path, extract projectId from the URI
$deprecatedProjectPathPrefix = '/v1/projects/';
$route = $utopia->match($request);
$route = $utopia->match($request)?->route;
if (!empty($route)) {
$isDeprecatedAlias = \str_starts_with($request->getURI(), $deprecatedProjectPathPrefix) &&
!\str_starts_with($route->getPath(), $deprecatedProjectPathPrefix);
@@ -1093,7 +1093,7 @@ return function (Container $context): void {
if ($project->getId() !== 'console') {
$teamInternalId = $project->getAttribute('teamInternalId', '');
} else {
$route = $utopia->match($request);
$route = $utopia->match($request)?->route;
$path = ! empty($route) ? $route->getPath() : $request->getURI();
$orgHeader = $request->getHeader('x-appwrite-organization', '');
if (str_starts_with($path, '/v1/projects/:projectId')) {
+1 -1
View File
@@ -858,7 +858,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$websocketEnabled = $apis['websocket'] ?? $apis['realtime'] ?? true;
if (
!$websocketEnabled
&& !($user->isPrivileged($authorization->getRoles()) || $user->isApp($authorization->getRoles()))
&& !($user->isPrivileged($authorization->getRoles()) || $user->isKey($authorization->getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
+3 -3
View File
@@ -54,7 +54,7 @@
"utopia-php/abuse": "1.3.*",
"utopia-php/agents": "1.2.*",
"utopia-php/analytics": "0.15.*",
"utopia-php/audit": "2.3.*",
"utopia-php/audit": "^2.4",
"utopia-php/auth": "0.5.*",
"utopia-php/cache": "^3.0",
"utopia-php/cli": "0.23.*",
@@ -67,7 +67,7 @@
"utopia-php/emails": "0.7.*",
"utopia-php/dns": "1.7.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/http": "^2.0@RC",
"utopia-php/http": "2.0.0-rc3",
"utopia-php/fetch": "^1.1",
"utopia-php/validators": "0.2.*",
"utopia-php/image": "0.8.*",
@@ -76,7 +76,7 @@
"utopia-php/logger": "0.8.*",
"utopia-php/messaging": "0.22.*",
"utopia-php/migration": "1.*",
"utopia-php/platform": "1.0.0-rc2",
"utopia-php/platform": "1.0.0-rc3",
"utopia-php/pools": "1.*",
"utopia-php/span": "1.1.*",
"utopia-php/preloader": "0.2.*",
Generated
+142 -211
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b645c7da1728536497fe8186b158f9c6",
"content-hash": "0f60e85b461aa1a57d624e97be0614bd",
"packages": [
{
"name": "adhocore/jwt",
@@ -161,16 +161,16 @@
},
{
"name": "appwrite/php-runtimes",
"version": "0.20.0",
"version": "0.20.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/runtimes.git",
"reference": "7d9b7f4eef5c0a142a60907b06de2219d025c5c3"
"reference": "e9213dfe9fff1b67de77aa61dbcae5f4ca10b6d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/runtimes/zipball/7d9b7f4eef5c0a142a60907b06de2219d025c5c3",
"reference": "7d9b7f4eef5c0a142a60907b06de2219d025c5c3",
"url": "https://api.github.com/repos/appwrite/runtimes/zipball/e9213dfe9fff1b67de77aa61dbcae5f4ca10b6d6",
"reference": "e9213dfe9fff1b67de77aa61dbcae5f4ca10b6d6",
"shasum": ""
},
"require": {
@@ -210,9 +210,9 @@
],
"support": {
"issues": "https://github.com/appwrite/runtimes/issues",
"source": "https://github.com/appwrite/runtimes/tree/0.20.0"
"source": "https://github.com/appwrite/runtimes/tree/0.20.1"
},
"time": "2026-05-01T07:47:07+00:00"
"time": "2026-05-24T03:00:39+00:00"
},
{
"name": "brick/math",
@@ -3510,16 +3510,16 @@
},
{
"name": "utopia-php/audit",
"version": "2.3.2",
"version": "2.4.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "e7b4049fc2ee9be34bcc18771fa593db3b0e9fe3"
"reference": "eddd79d93f23ed2851c0df2b1e2e2dfb25ba06c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/e7b4049fc2ee9be34bcc18771fa593db3b0e9fe3",
"reference": "e7b4049fc2ee9be34bcc18771fa593db3b0e9fe3",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/eddd79d93f23ed2851c0df2b1e2e2dfb25ba06c6",
"reference": "eddd79d93f23ed2851c0df2b1e2e2dfb25ba06c6",
"shasum": ""
},
"require": {
@@ -3554,9 +3554,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/2.3.2"
"source": "https://github.com/utopia-php/audit/tree/2.4.1"
},
"time": "2026-05-14T04:00:37+00:00"
"time": "2026-05-20T06:25:45+00:00"
},
{
"name": "utopia-php/auth",
@@ -3615,16 +3615,16 @@
},
{
"name": "utopia-php/cache",
"version": "3.0.0",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cache.git",
"reference": "ece1f4d11ec2804cd7e05b9717dc7a2bc66e4176"
"reference": "086687d7ae23dd1dae67b943161e8cef143539e1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/ece1f4d11ec2804cd7e05b9717dc7a2bc66e4176",
"reference": "ece1f4d11ec2804cd7e05b9717dc7a2bc66e4176",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/086687d7ae23dd1dae67b943161e8cef143539e1",
"reference": "086687d7ae23dd1dae67b943161e8cef143539e1",
"shasum": ""
},
"require": {
@@ -3663,9 +3663,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cache/issues",
"source": "https://github.com/utopia-php/cache/tree/3.0.0"
"source": "https://github.com/utopia-php/cache/tree/3.0.2"
},
"time": "2026-05-14T14:13:17+00:00"
"time": "2026-05-19T22:38:16+00:00"
},
{
"name": "utopia-php/circuit-breaker",
@@ -3731,21 +3731,21 @@
},
{
"name": "utopia-php/cli",
"version": "0.23.3",
"version": "0.23.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cli.git",
"reference": "3c45ae5bcdcd3c7916e1909d74c60b8e771610db"
"reference": "59f66e72ec1f8350968d8b95c0039faaac7a6d6d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/cli/zipball/3c45ae5bcdcd3c7916e1909d74c60b8e771610db",
"reference": "3c45ae5bcdcd3c7916e1909d74c60b8e771610db",
"url": "https://api.github.com/repos/utopia-php/cli/zipball/59f66e72ec1f8350968d8b95c0039faaac7a6d6d",
"reference": "59f66e72ec1f8350968d8b95c0039faaac7a6d6d",
"shasum": ""
},
"require": {
"php": ">=7.4",
"utopia-php/servers": "0.4.0"
"utopia-php/servers": "0.4.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
@@ -3776,9 +3776,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cli/issues",
"source": "https://github.com/utopia-php/cli/tree/0.23.3"
"source": "https://github.com/utopia-php/cli/tree/0.23.4"
},
"time": "2026-05-05T04:38:59+00:00"
"time": "2026-05-21T14:42:15+00:00"
},
{
"name": "utopia-php/compression",
@@ -4079,16 +4079,16 @@
},
{
"name": "utopia-php/dns",
"version": "1.7.0",
"version": "1.7.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/dns.git",
"reference": "90bf1bc4a51ceca93590d09e7365317b28d1eb89"
"reference": "5225f52a82d4128e69ad17c2a81fcfea6aa00ae1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/dns/zipball/90bf1bc4a51ceca93590d09e7365317b28d1eb89",
"reference": "90bf1bc4a51ceca93590d09e7365317b28d1eb89",
"url": "https://api.github.com/repos/utopia-php/dns/zipball/5225f52a82d4128e69ad17c2a81fcfea6aa00ae1",
"reference": "5225f52a82d4128e69ad17c2a81fcfea6aa00ae1",
"shasum": ""
},
"require": {
@@ -4099,9 +4099,9 @@
"utopia-php/validators": "0.*"
},
"require-dev": {
"laravel/pint": "1.25.*",
"laravel/pint": "1.29.*",
"phpstan/phpstan": "2.0.*",
"phpunit/phpunit": "12.4.*",
"phpunit/phpunit": "12.5.*",
"swoole/ide-helper": "5.1.8"
},
"type": "library",
@@ -4130,9 +4130,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/dns/issues",
"source": "https://github.com/utopia-php/dns/tree/1.7.0"
"source": "https://github.com/utopia-php/dns/tree/1.7.2"
},
"time": "2026-05-13T07:11:31+00:00"
"time": "2026-05-20T04:49:11+00:00"
},
{
"name": "utopia-php/domains",
@@ -4245,16 +4245,16 @@
},
{
"name": "utopia-php/emails",
"version": "0.7.0",
"version": "0.7.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/emails.git",
"reference": "115e24aa908e2b1f06c7ff3b94434a0bdbed9107"
"reference": "a5f1d111e5023918731f2de96d348f5b6a0de143"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/emails/zipball/115e24aa908e2b1f06c7ff3b94434a0bdbed9107",
"reference": "115e24aa908e2b1f06c7ff3b94434a0bdbed9107",
"url": "https://api.github.com/repos/utopia-php/emails/zipball/a5f1d111e5023918731f2de96d348f5b6a0de143",
"reference": "a5f1d111e5023918731f2de96d348f5b6a0de143",
"shasum": ""
},
"require": {
@@ -4300,9 +4300,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/emails/issues",
"source": "https://github.com/utopia-php/emails/tree/0.7.0"
"source": "https://github.com/utopia-php/emails/tree/0.7.1"
},
"time": "2026-05-13T05:01:26+00:00"
"time": "2026-05-20T13:05:30+00:00"
},
{
"name": "utopia-php/fetch",
@@ -4346,23 +4346,23 @@
},
{
"name": "utopia-php/http",
"version": "2.0.0-rc1",
"version": "2.0.0-rc3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/http.git",
"reference": "3e3b431d443844c6bf810120dee735f45880856f"
"reference": "e1a51a2eb906a3d461378fb551a647ef01714f1c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/http/zipball/3e3b431d443844c6bf810120dee735f45880856f",
"reference": "3e3b431d443844c6bf810120dee735f45880856f",
"url": "https://api.github.com/repos/utopia-php/http/zipball/e1a51a2eb906a3d461378fb551a647ef01714f1c",
"reference": "e1a51a2eb906a3d461378fb551a647ef01714f1c",
"shasum": ""
},
"require": {
"php": ">=8.3",
"utopia-php/compression": "0.1.*",
"utopia-php/di": "0.3.*",
"utopia-php/servers": "0.4.0",
"utopia-php/servers": "0.4.*",
"utopia-php/telemetry": "0.2.*",
"utopia-php/validators": "0.2.*"
},
@@ -4396,9 +4396,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/http/issues",
"source": "https://github.com/utopia-php/http/tree/2.0.0-rc1"
"source": "https://github.com/utopia-php/http/tree/2.0.0-rc3"
},
"time": "2026-05-05T15:00:03+00:00"
"time": "2026-05-21T14:42:41+00:00"
},
{
"name": "utopia-php/image",
@@ -4606,16 +4606,16 @@
},
{
"name": "utopia-php/messaging",
"version": "0.22.2",
"version": "0.22.3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
"reference": "f99feceab575243f3a86ee2e90cd1a6407805def"
"reference": "67366d5f45cc92efe7adb6aab5d6dcd2342f2f9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/f99feceab575243f3a86ee2e90cd1a6407805def",
"reference": "f99feceab575243f3a86ee2e90cd1a6407805def",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/67366d5f45cc92efe7adb6aab5d6dcd2342f2f9e",
"reference": "67366d5f45cc92efe7adb6aab5d6dcd2342f2f9e",
"shasum": ""
},
"require": {
@@ -4651,9 +4651,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
"source": "https://github.com/utopia-php/messaging/tree/0.22.2"
"source": "https://github.com/utopia-php/messaging/tree/0.22.3"
},
"time": "2026-05-14T08:51:26+00:00"
"time": "2026-05-19T05:31:20+00:00"
},
{
"name": "utopia-php/migration",
@@ -4773,16 +4773,16 @@
},
{
"name": "utopia-php/platform",
"version": "1.0.0-rc2",
"version": "1.0.0-rc3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/platform.git",
"reference": "a67e5037007ee7fdca5359ab4577b82917e55452"
"reference": "674fd3cea6d1f8db660b01c5be89e8333dfb6de9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/a67e5037007ee7fdca5359ab4577b82917e55452",
"reference": "a67e5037007ee7fdca5359ab4577b82917e55452",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/674fd3cea6d1f8db660b01c5be89e8333dfb6de9",
"reference": "674fd3cea6d1f8db660b01c5be89e8333dfb6de9",
"shasum": ""
},
"require": {
@@ -4818,9 +4818,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/platform/issues",
"source": "https://github.com/utopia-php/platform/tree/1.0.0-rc2"
"source": "https://github.com/utopia-php/platform/tree/1.0.0-rc3"
},
"time": "2026-05-15T06:19:20+00:00"
"time": "2026-05-25T11:48:18+00:00"
},
{
"name": "utopia-php/pools",
@@ -4976,16 +4976,16 @@
},
{
"name": "utopia-php/queue",
"version": "0.18.3",
"version": "0.18.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/queue.git",
"reference": "141aad162b90728353f3aa834684b1f2affed045"
"reference": "1323b52f39b899c580dbb7af8562fc53d4e13e62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/141aad162b90728353f3aa834684b1f2affed045",
"reference": "141aad162b90728353f3aa834684b1f2affed045",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/1323b52f39b899c580dbb7af8562fc53d4e13e62",
"reference": "1323b52f39b899c580dbb7af8562fc53d4e13e62",
"shasum": ""
},
"require": {
@@ -4993,7 +4993,7 @@
"php-amqplib/php-amqplib": "^3.7",
"utopia-php/di": "0.3.*",
"utopia-php/pools": "1.*",
"utopia-php/servers": "0.4.0",
"utopia-php/servers": "0.4.*",
"utopia-php/telemetry": "0.2.*",
"utopia-php/validators": "0.2.*"
},
@@ -5036,9 +5036,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/queue/issues",
"source": "https://github.com/utopia-php/queue/tree/0.18.3"
"source": "https://github.com/utopia-php/queue/tree/0.18.4"
},
"time": "2026-05-14T08:53:35+00:00"
"time": "2026-05-21T14:43:24+00:00"
},
{
"name": "utopia-php/registry",
@@ -5094,16 +5094,16 @@
},
{
"name": "utopia-php/servers",
"version": "0.4.0",
"version": "0.4.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/servers.git",
"reference": "7db346ef377503efe0acafe0791085270cd9ed70"
"reference": "6e9241f587a19c0e9e7a3587fe3b15ffb2d4c2a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/servers/zipball/7db346ef377503efe0acafe0791085270cd9ed70",
"reference": "7db346ef377503efe0acafe0791085270cd9ed70",
"url": "https://api.github.com/repos/utopia-php/servers/zipball/6e9241f587a19c0e9e7a3587fe3b15ffb2d4c2a4",
"reference": "6e9241f587a19c0e9e7a3587fe3b15ffb2d4c2a4",
"shasum": ""
},
"require": {
@@ -5142,9 +5142,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/servers/issues",
"source": "https://github.com/utopia-php/servers/tree/0.4.0"
"source": "https://github.com/utopia-php/servers/tree/0.4.1"
},
"time": "2026-05-05T04:08:30+00:00"
"time": "2026-05-21T13:08:45+00:00"
},
{
"name": "utopia-php/span",
@@ -5355,16 +5355,16 @@
},
{
"name": "utopia-php/validators",
"version": "0.2.3",
"version": "0.2.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/validators.git",
"reference": "9770269c8ed8e6909934965fa8722103c7434c23"
"reference": "b4ee60db4dbae5ffbe53968d01f69b6941251576"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/validators/zipball/9770269c8ed8e6909934965fa8722103c7434c23",
"reference": "9770269c8ed8e6909934965fa8722103c7434c23",
"url": "https://api.github.com/repos/utopia-php/validators/zipball/b4ee60db4dbae5ffbe53968d01f69b6941251576",
"reference": "b4ee60db4dbae5ffbe53968d01f69b6941251576",
"shasum": ""
},
"require": {
@@ -5394,9 +5394,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/validators/issues",
"source": "https://github.com/utopia-php/validators/tree/0.2.3"
"source": "https://github.com/utopia-php/validators/tree/0.2.4"
},
"time": "2026-05-14T08:05:44+00:00"
"time": "2026-05-21T12:47:43+00:00"
},
{
"name": "utopia-php/vcs",
@@ -5638,16 +5638,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "1.29.5",
"version": "1.31.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "e670edcdfb9ffcec36125b1eb3e4473dce30b620"
"reference": "5699f6da951aef9378fabdcf12f40a9a54fb3128"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/e670edcdfb9ffcec36125b1eb3e4473dce30b620",
"reference": "e670edcdfb9ffcec36125b1eb3e4473dce30b620",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/5699f6da951aef9378fabdcf12f40a9a54fb3128",
"reference": "5699f6da951aef9378fabdcf12f40a9a54fb3128",
"shasum": ""
},
"require": {
@@ -5656,7 +5656,7 @@
"ext-mbstring": "*",
"matthiasmullie/minify": "1.3.*",
"php": ">=8.3",
"twig/twig": "3.14.*"
"twig/twig": "3.26.*"
},
"require-dev": {
"brianium/paratest": "7.*",
@@ -5683,9 +5683,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/1.29.5"
"source": "https://github.com/appwrite/sdk-generator/tree/1.31.1"
},
"time": "2026-05-15T06:49:05+00:00"
"time": "2026-05-20T22:22:59+00:00"
},
{
"name": "brianium/paratest",
@@ -6394,11 +6394,11 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.54",
"version": "2.1.55",
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8be50c3992107dc837b17da4d140fbbdf9a5c5bd",
"reference": "8be50c3992107dc837b17da4d140fbbdf9a5c5bd",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/9eaac3826ed5e9b8427350a43cac825eeca3f566",
"reference": "9eaac3826ed5e9b8427350a43cac825eeca3f566",
"shasum": ""
},
"require": {
@@ -6443,7 +6443,7 @@
"type": "github"
}
],
"time": "2026-04-29T13:31:09+00:00"
"time": "2026-05-18T11:57:34+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -6882,23 +6882,23 @@
},
{
"name": "sebastian/cli-parser",
"version": "4.2.0",
"version": "4.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/cli-parser.git",
"reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04"
"reference": "7d05781b13f7dec9043a629a21d086ed74582a15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04",
"reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04",
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/7d05781b13f7dec9043a629a21d086ed74582a15",
"reference": "7d05781b13f7dec9043a629a21d086ed74582a15",
"shasum": ""
},
"require": {
"php": ">=8.3"
},
"require-dev": {
"phpunit/phpunit": "^12.0"
"phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
@@ -6927,7 +6927,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
"security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
"source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0"
"source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.1"
},
"funding": [
{
@@ -6947,7 +6947,7 @@
"type": "tidelift"
}
],
"time": "2025-09-14T09:36:45+00:00"
"time": "2026-05-17T05:29:34+00:00"
},
{
"name": "sebastian/comparator",
@@ -7244,25 +7244,25 @@
},
{
"name": "sebastian/exporter",
"version": "7.0.2",
"version": "7.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "016951ae10980765e4e7aee491eb288c64e505b7"
"reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7",
"reference": "016951ae10980765e4e7aee491eb288c64e505b7",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23",
"reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=8.3",
"sebastian/recursion-context": "^7.0"
"sebastian/recursion-context": "^7.0.1"
},
"require-dev": {
"phpunit/phpunit": "^12.0"
"phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
@@ -7310,7 +7310,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
"source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2"
"source": "https://github.com/sebastianbergmann/exporter/tree/7.0.3"
},
"funding": [
{
@@ -7330,7 +7330,7 @@
"type": "tidelift"
}
],
"time": "2025-09-24T06:16:11+00:00"
"time": "2026-05-20T04:37:17+00:00"
},
{
"name": "sebastian/global-state",
@@ -7408,24 +7408,24 @@
},
{
"name": "sebastian/lines-of-code",
"version": "4.0.0",
"version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
"reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f"
"reference": "d543b8ef219dcd8da262cbb958639a96bedba10e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f",
"reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d543b8ef219dcd8da262cbb958639a96bedba10e",
"reference": "d543b8ef219dcd8da262cbb958639a96bedba10e",
"shasum": ""
},
"require": {
"nikic/php-parser": "^5.0",
"nikic/php-parser": "^5.7.0",
"php": ">=8.3"
},
"require-dev": {
"phpunit/phpunit": "^12.0"
"phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
@@ -7454,15 +7454,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
"security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0"
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/lines-of-code",
"type": "tidelift"
}
],
"time": "2025-02-07T04:57:28+00:00"
"time": "2026-05-19T16:22:07+00:00"
},
{
"name": "sebastian/object-enumerator",
@@ -7656,23 +7668,23 @@
},
{
"name": "sebastian/type",
"version": "6.0.3",
"version": "6.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "e549163b9760b8f71f191651d22acf32d56d6d4d"
"reference": "82ff822c2edc46724be9f7411d3163021f602773"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d",
"reference": "e549163b9760b8f71f191651d22acf32d56d6d4d",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/82ff822c2edc46724be9f7411d3163021f602773",
"reference": "82ff822c2edc46724be9f7411d3163021f602773",
"shasum": ""
},
"require": {
"php": ">=8.3"
},
"require-dev": {
"phpunit/phpunit": "^12.0"
"phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
@@ -7701,7 +7713,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
"security": "https://github.com/sebastianbergmann/type/security/policy",
"source": "https://github.com/sebastianbergmann/type/tree/6.0.3"
"source": "https://github.com/sebastianbergmann/type/tree/6.0.4"
},
"funding": [
{
@@ -7721,7 +7733,7 @@
"type": "tidelift"
}
],
"time": "2025-08-09T06:57:12+00:00"
"time": "2026-05-20T06:45:45+00:00"
},
{
"name": "sebastian/version",
@@ -8201,86 +8213,6 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.37.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php81\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/process",
"version": "v8.0.11",
@@ -8537,26 +8469,27 @@
},
{
"name": "twig/twig",
"version": "v3.14.2",
"version": "v3.26.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a"
"reference": "1fcae487b180d78e6351f4e0afa91f9eab96a2bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/1fcae487b180d78e6351f4e0afa91f9eab96a2bc",
"reference": "1fcae487b180d78e6351f4e0afa91f9eab96a2bc",
"shasum": ""
},
"require": {
"php": ">=8.0.2",
"php": ">=8.1.0",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php81": "^1.29"
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"php-cs-fixer/shim": "^3.0@stable",
"phpstan/phpstan": "^2.0@stable",
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
},
@@ -8600,7 +8533,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.14.2"
"source": "https://github.com/twigphp/Twig/tree/v3.26.0"
},
"funding": [
{
@@ -8612,14 +8545,12 @@
"type": "tidelift"
}
],
"time": "2024-11-07T12:36:22+00:00"
"time": "2026-05-20T07:31:59+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
"utopia-php/http": 5
},
"stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
-1
View File
@@ -1 +0,0 @@
Create a new JWT token. This token can be used to authenticate users with custom scopes and expiration time.
@@ -1 +0,0 @@
Send a test email to verify SMTP configuration.
-1
View File
@@ -1 +0,0 @@
Create a new project. You can create a maximum of 100 projects per account.
@@ -1 +0,0 @@
Reset a custom email template to its default value. This endpoint removes any custom content and restores the template to its original state.
-1
View File
@@ -1 +0,0 @@
Delete a project by its unique ID.
@@ -1 +0,0 @@
Get a custom email template for the specified locale and type. This endpoint returns the template content, subject, and other configuration details.
-1
View File
@@ -1 +0,0 @@
Get a project by its unique ID. This endpoint allows you to retrieve the project's details, including its name, description, team, region, and other metadata.
@@ -1 +0,0 @@
Update the status of a specific authentication method. Use this endpoint to enable or disable different authentication methods such as email, magic urls or sms in your project.
@@ -1 +0,0 @@
Update a custom email template for the specified locale and type. Use this endpoint to modify the content of your email templates.
@@ -1 +0,0 @@
Update the list of mock phone numbers for testing. Use these numbers to bypass SMS verification in development.
@@ -1 +0,0 @@
Update the OAuth2 provider configurations. Use this endpoint to set up or update the OAuth2 provider credentials or enable/disable providers.
-1
View File
@@ -1 +0,0 @@
Update the SMTP configuration for your project. Use this endpoint to configure your project's SMTP provider with your custom settings for sending transactional emails.
-1
View File
@@ -1 +0,0 @@
Update a project by its unique ID.
+3 -3
View File
@@ -122,9 +122,9 @@ class Key
$secret = $key;
}
$role = User::ROLE_APPS;
$role = User::ROLE_KEYS;
$roles = Config::getParam('roles', []);
$scopes = $roles[User::ROLE_APPS]['scopes'] ?? [];
$scopes = $roles[User::ROLE_KEYS]['scopes'] ?? [];
$expired = false;
$guestKey = new Key(
@@ -270,7 +270,7 @@ class Key
$name = $key->getAttribute('name', 'UNKNOWN');
$role = User::ROLE_APPS;
$role = User::ROLE_KEYS;
$scopes = $key->getAttribute('scopes', []);
+2 -8
View File
@@ -342,7 +342,6 @@ class Resolvers
$lock->acquire();
$original = $utopia->getRoute();
try {
$request = clone $request;
$request->addHeader('x-appwrite-source', 'graphql');
@@ -363,10 +362,9 @@ class Resolvers
$resolverResponse->setContentType(Response::CONTENT_TYPE_NULL);
$resolverResponse->setSent(false);
$route = $utopia->match($request, fresh: true);
$request->setRoute($route);
$request->setRoute($utopia->match($request)?->route);
$utopia->execute($route, $request, $resolverResponse);
$utopia->execute($request, $resolverResponse);
self::mergeResponseSideEffects($resolverResponse, $response);
@@ -385,10 +383,6 @@ class Resolvers
$reject($e);
return;
} finally {
if ($original !== null) {
$utopia->setRoute($original);
}
$lock->release();
unset(self::$locks[\spl_object_hash($utopia)]);
}
+2
View File
@@ -11,6 +11,7 @@ use Appwrite\Platform\Modules\Databases;
use Appwrite\Platform\Modules\Functions;
use Appwrite\Platform\Modules\Health;
use Appwrite\Platform\Modules\Migrations;
use Appwrite\Platform\Modules\Organization;
use Appwrite\Platform\Modules\Presences;
use Appwrite\Platform\Modules\Project;
use Appwrite\Platform\Modules\Projects;
@@ -44,6 +45,7 @@ class Appwrite extends Platform
$this->addModule(new VCS\Module());
$this->addModule(new Webhooks\Module());
$this->addModule(new Migrations\Module());
$this->addModule(new Organization\Module());
$this->addModule(new Project\Module());
$this->addModule(new Advisor\Module());
}
@@ -6,6 +6,7 @@ use Appwrite\Auth\MFA\Type;
use Appwrite\Auth\MFA\Type\TOTP;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Deprecated;
@@ -17,7 +18,7 @@ use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\WhiteList;
@@ -77,7 +78,7 @@ class Create extends Action
contentType: ContentType::JSON
)
])
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator. Must be `' . Type::TOTP . '`')
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator. Must be `' . Type::TOTP . '`', enum: new Enum(name: 'AuthenticatorType'))
->inject('response')
->inject('project')
->inject('user')
@@ -6,6 +6,7 @@ use Appwrite\Auth\MFA\Type;
use Appwrite\Auth\MFA\Type\TOTP;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Deprecated;
@@ -14,7 +15,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\WhiteList;
@@ -74,7 +75,7 @@ class Delete extends Action
contentType: ContentType::NONE
)
])
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.')
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.', enum: new Enum(name: 'AuthenticatorType'))
->inject('response')
->inject('user')
->inject('dbForProject')
@@ -7,6 +7,7 @@ use Appwrite\Auth\MFA\Type;
use Appwrite\Auth\MFA\Type\TOTP;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Deprecated;
@@ -15,7 +16,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
@@ -76,7 +77,7 @@ class Update extends Action
contentType: ContentType::JSON
)
])
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.')
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.', enum: new Enum(name: 'AuthenticatorType'))
->param('otp', '', new Text(256), 'Valid verification token.')
->inject('response')
->inject('user')
@@ -10,6 +10,7 @@ use Appwrite\Event\Message\Messaging as MessagingMessage;
use Appwrite\Event\Publisher\Mail as MailPublisher;
use Appwrite\Event\Publisher\Messaging as MessagingPublisher;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Deprecated;
@@ -29,7 +30,7 @@ use Utopia\Database\Document;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Locale\Locale;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Storage\Validator\FileName;
use Utopia\System\System;
@@ -94,7 +95,7 @@ class Create extends Action
])
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{userId}')
->param('factor', '', new WhiteList([Type::EMAIL, Type::PHONE, Type::TOTP, Type::RECOVERY_CODE]), 'Factor used for verification. Must be one of following: `' . Type::EMAIL . '`, `' . Type::PHONE . '`, `' . Type::TOTP . '`, `' . Type::RECOVERY_CODE . '`.')
->param('factor', '', new WhiteList([Type::EMAIL, Type::PHONE, Type::TOTP, Type::RECOVERY_CODE]), 'Factor used for verification. Must be one of following: `' . Type::EMAIL . '`, `' . Type::PHONE . '`, `' . Type::TOTP . '`, `' . Type::RECOVERY_CODE . '`.', enum: new Enum(name: 'AuthenticationFactor'))
->inject('response')
->inject('dbForProject')
->inject('user')
@@ -11,6 +11,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Config\Config;
use Utopia\Platform\Action as UtopiaAction;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
@@ -49,7 +50,10 @@ class Get extends Action
],
contentType: ContentType::IMAGE_PNG
))
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-browsers'))), 'Browser Code.')
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-browsers'))), 'Browser Code.', enum: new Enum(
name: 'Browser',
map: \array_map(fn (array $browser) => $browser['name'], Config::getParam('avatar-browsers')),
))
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', -1, new Range(-1, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true)
@@ -11,6 +11,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Config\Config;
use Utopia\Platform\Action as UtopiaAction;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
@@ -49,7 +50,10 @@ class Get extends Action
],
contentType: ContentType::IMAGE_PNG
))
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.')
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.', enum: new Enum(
name: 'CreditCard',
map: \array_map(fn (array $creditCard) => $creditCard['name'], Config::getParam('avatar-credit-cards')),
))
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', -1, new Range(-1, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true)
@@ -11,6 +11,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Config\Config;
use Utopia\Platform\Action as UtopiaAction;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
@@ -49,7 +50,10 @@ class Get extends Action
],
contentType: ContentType::IMAGE_PNG
))
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-flags'))), 'Country Code. ISO Alpha-2 country code format.')
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-flags'))), 'Country Code. ISO Alpha-2 country code format.', enum: new Enum(
name: 'Flag',
map: \array_map(fn (array $flag) => $flag['name'], Config::getParam('avatar-flags')),
))
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('quality', -1, new Range(-1, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true)
@@ -16,6 +16,7 @@ use Utopia\Domains\Domain;
use Utopia\Fetch\Client;
use Utopia\Image\Image;
use Utopia\Platform\Action as UtopiaAction;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
@@ -68,21 +69,21 @@ class Get extends Action
->param('viewportWidth', 1280, new Range(1, 1920), 'Browser viewport width. Pass an integer between 1 to 1920. Defaults to 1280.', true, example: '1920')
->param('viewportHeight', 720, new Range(1, 1080), 'Browser viewport height. Pass an integer between 1 to 1080. Defaults to 720.', true, example: '1080')
->param('scale', 1, new Range(0.1, 3, Range::TYPE_FLOAT), 'Browser scale factor. Pass a number between 0.1 to 3. Defaults to 1.', true, example: '2')
->param('theme', 'light', new WhiteList(['light', 'dark']), 'Browser theme. Pass "light" or "dark". Defaults to "light".', true, example: 'dark')
->param('theme', 'light', new WhiteList(['light', 'dark']), 'Browser theme. Pass "light" or "dark". Defaults to "light".', true, example: 'dark', enum: new Enum(name: 'BrowserTheme'))
->param('userAgent', '', new Text(512), 'Custom user agent string. Defaults to browser default.', true, example: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15')
->param('fullpage', false, new Boolean(true), 'Capture full page scroll. Pass 0 for viewport only, or 1 for full page. Defaults to 0.', true, example: 'true')
->param('locale', '', new Text(10), 'Browser locale (e.g., "en-US", "fr-FR"). Defaults to browser default.', true, example: 'en-US')
->param('timezone', '', new WhiteList(timezone_identifiers_list()), 'IANA timezone identifier (e.g., "America/New_York", "Europe/London"). Defaults to browser default.', true, example: 'america/new_york')
->param('timezone', '', new WhiteList(timezone_identifiers_list()), 'IANA timezone identifier (e.g., "America/New_York", "Europe/London"). Defaults to browser default.', true, example: 'America/New_York', enum: new Enum(name: 'Timezone'))
->param('latitude', 0, new Range(-90, 90, Range::TYPE_FLOAT), 'Geolocation latitude. Pass a number between -90 to 90. Defaults to 0.', true, example: '37.7749')
->param('longitude', 0, new Range(-180, 180, Range::TYPE_FLOAT), 'Geolocation longitude. Pass a number between -180 to 180. Defaults to 0.', true, example: '-122.4194')
->param('accuracy', 0, new Range(0, 100000, Range::TYPE_FLOAT), 'Geolocation accuracy in meters. Pass a number between 0 to 100000. Defaults to 0.', true, example: '100')
->param('touch', false, new Boolean(true), 'Enable touch support. Pass 0 for no touch, or 1 for touch enabled. Defaults to 0.', true, example: 'true')
->param('permissions', [], new ArrayList(new WhiteList(['geolocation', 'camera', 'microphone', 'notifications', 'midi', 'push', 'clipboard-read', 'clipboard-write', 'payment-handler', 'usb', 'bluetooth', 'accelerometer', 'gyroscope', 'magnetometer', 'ambient-light-sensor', 'background-sync', 'persistent-storage', 'screen-wake-lock', 'web-share', 'xr-spatial-tracking'])), 'Browser permissions to grant. Pass an array of permission names like ["geolocation", "camera", "microphone"]. Defaults to empty.', true, example: '["geolocation","notifications"]')
->param('permissions', [], new ArrayList(new WhiteList(['geolocation', 'camera', 'microphone', 'notifications', 'midi', 'push', 'clipboard-read', 'clipboard-write', 'payment-handler', 'usb', 'bluetooth', 'accelerometer', 'gyroscope', 'magnetometer', 'ambient-light-sensor', 'background-sync', 'persistent-storage', 'screen-wake-lock', 'web-share', 'xr-spatial-tracking'])), 'Browser permissions to grant. Pass an array of permission names like ["geolocation", "camera", "microphone"]. Defaults to empty.', true, example: '["geolocation","notifications"]', enum: new Enum(name: 'BrowserPermission'))
->param('sleep', 0, new Range(0, 10), 'Wait time in seconds before taking the screenshot. Pass an integer between 0 to 10. Defaults to 0.', true, example: '3')
->param('width', 0, new Range(0, 2000), 'Output image width. Pass 0 to use original width, or an integer between 1 to 2000. Defaults to 0 (original width).', true, example: '800')
->param('height', 0, new Range(0, 2000), 'Output image height. Pass 0 to use original height, or an integer between 1 to 2000. Defaults to 0 (original height).', true, example: '600')
->param('quality', -1, new Range(-1, 100), 'Screenshot quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true, example: '85')
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true, example: 'jpeg')
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true, example: 'jpeg', enum: new Enum(name: 'ImageFormat'))
->inject('response')
->inject('usage')
->callback($this->action(...));
@@ -3,6 +3,7 @@
namespace Appwrite\Platform\Modules\Console\Http\Resources;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@@ -12,7 +13,7 @@ use Utopia\Database\Database;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Domains\Domain as Domain;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\Domain as DomainValidator;
@@ -56,7 +57,7 @@ class Get extends Action
->label('abuse-key', 'userId:{userId}, url:{url}')
->label('abuse-time', 60)
->param('value', '', new Text(256), 'Resource value.')
->param('type', '', new WhiteList(['rules']), 'Resource type.')
->param('type', '', new WhiteList(['rules']), 'Resource type.', enum: new Enum(name: 'ConsoleResourceType'))
->inject('response')
->inject('dbForPlatform')
->inject('platform')
@@ -11,6 +11,7 @@ use Utopia\Config\Config;
use Utopia\Database\Document;
use Utopia\Locale\Locale;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\WhiteList;
@@ -46,8 +47,8 @@ class Get extends Action
)
]
))
->param('templateId', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? [], true), 'Email template type. Can be one of: ' . \implode(', ', Config::getParam('locale-templates')['email'] ?? []))
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale. If left empty, the fallback locale (en) will be used.', optional: true, injections: ['localeCodes'])
->param('templateId', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? [], true), 'Email template type. Can be one of: ' . \implode(', ', Config::getParam('locale-templates')['email'] ?? []), enum: new Enum(name: 'ProjectEmailTemplateId'))
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale. If left empty, the fallback locale (en) will be used.', optional: true, injections: ['localeCodes'], enum: new Enum(name: 'ProjectEmailTemplateLocale'))
->inject('response')
->callback($this->action(...));
}
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
use Utopia\Validator\WhiteList;
@@ -70,7 +71,7 @@ class Create extends Action
Database::RELATION_MANY_TO_ONE,
Database::RELATION_MANY_TO_MANY,
Database::RELATION_ONE_TO_MANY
], true), 'Relation type')
], true), 'Relation type', enum: new Enum(name: 'RelationshipType'))
->param('twoWay', false, new Boolean(), 'Is Two Way?', true)
->param('key', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'Attribute Key.', true, ['dbForProject'])
->param('twoWayKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'Two Way Attribute Key.', true, ['dbForProject'])
@@ -78,7 +79,7 @@ class Create extends Action
Database::RELATION_MUTATE_CASCADE,
Database::RELATION_MUTATE_RESTRICT,
Database::RELATION_MUTATE_SET_NULL
], true), 'Constraints option', true)
], true), 'Constraints option', true, enum: new Enum(name: 'RelationMutate'))
->inject('response')
->inject('dbForProject')
->inject('publisherForDatabase')
@@ -16,6 +16,7 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\Nullable;
use Utopia\Validator\WhiteList;
@@ -69,7 +70,7 @@ class Update extends Action
Database::RELATION_MUTATE_CASCADE,
Database::RELATION_MUTATE_RESTRICT,
Database::RELATION_MUTATE_SET_NULL
], true), 'Constraints option', true)
], true), 'Constraints option', true, enum: new Enum(name: 'RelationMutate'))
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
->inject('response')
->inject('dbForProject')
@@ -93,7 +93,7 @@ class Decrement extends Action
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, array $plan, Authorization $authorization, User $user): void
{
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -93,7 +93,7 @@ class Increment extends Action
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Event $queueForEvents, Context $usage, array $plan, Authorization $authorization, User $user): void
{
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -201,7 +201,7 @@ class Create extends Action
$documents = [$data];
}
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($isBulk && !$isAPIKey && !$isPrivilegedUser) {
@@ -107,7 +107,7 @@ class Delete extends Action
): void {
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
@@ -78,7 +78,7 @@ class Get extends Action
public function action(string $databaseId, string $collectionId, string $documentId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, Context $usage, TransactionState $transactionState, Authorization $authorization, User $user): void
{
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -103,7 +103,7 @@ class Update extends Action
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
@@ -108,7 +108,7 @@ class Upsert extends Action
throw new Exception($this->getMissingPayloadException());
}
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -88,7 +88,7 @@ class XList extends Action
public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, bool $includeTotal, int $ttl, UtopiaResponse $response, Database $dbForProject, User $user, callable $getDatabasesDB, Context $usage, TransactionState $transactionState, Authorization $authorization, ?Http $utopia = null): void
{
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -22,6 +22,7 @@ use Utopia\Database\Validator\Index as IndexValidator;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
use Utopia\Validator\Nullable;
@@ -72,9 +73,9 @@ class Create extends Action
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
->param('key', null, fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Index Key.', false, ['dbForProject'])
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.', enum: new Enum(name: 'DatabasesIndexType'))
->param('attributes', null, fn (Database $dbForProject) => new ArrayList(new Key(true, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.', false, ['dbForProject'])
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true, enum: new Enum(name: 'OrderBy'))
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
->inject('response')
->inject('dbForProject')
@@ -17,6 +17,7 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends Action
@@ -64,7 +65,14 @@ class Get extends Action
),
))
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
->inject('response')
->inject('dbForProject')
@@ -75,7 +75,7 @@ class Create extends Action
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Operations array cannot be empty');
}
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
// API keys and admins can read any transaction, regular users need permissions
@@ -120,7 +120,7 @@ class Update extends Action
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Cannot commit and rollback at the same time');
}
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$transaction = ($isAPIKey || $isPrivilegedUser)
@@ -3,6 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Databases\Usage;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Deprecated;
@@ -16,7 +17,7 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends Action
@@ -36,7 +37,9 @@ class Get extends Action
default => DATABASE_TYPE_LEGACY,
};
return parent::setHttpPath($path);
parent::setHttpPath($path);
return $this;
}
protected function getMetrics(): array
@@ -93,7 +96,14 @@ class Get extends Action
)
])
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -2,6 +2,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Databases\Usage;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Deprecated;
@@ -14,7 +15,7 @@ use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class XList extends Action
@@ -34,7 +35,9 @@ class XList extends Action
default => DATABASE_TYPE_LEGACY,
};
return parent::setHttpPath($path);
parent::setHttpPath($path);
return $this;
}
protected function getMetrics(): array
@@ -90,7 +93,14 @@ class XList extends Action
)
),
])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -12,6 +12,7 @@ use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
use Utopia\Validator\Nullable;
@@ -58,9 +59,9 @@ class Create extends IndexCreate
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
->param('key', null, fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Index Key.', false, ['dbForProject'])
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.', enum: new Enum(name: 'DocumentsDBIndexType'))
->param('attributes', null, fn (Database $dbForProject) => new ArrayList(new Key(true, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.', false, ['dbForProject'])
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true, enum: new Enum(name: 'OrderBy'))
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
->inject('response')
->inject('dbForProject')
@@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends CollectionUsageGet
@@ -54,7 +55,14 @@ class Get extends CollectionUsageGet
contentType: ContentType::JSON,
))
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
->inject('response')
->inject('dbForProject')
@@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends DatabaseUsageGet
@@ -51,7 +52,14 @@ class Get extends DatabaseUsageGet
),
])
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -9,6 +9,7 @@ use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class XList extends DatabaseUsageXList
@@ -48,7 +49,14 @@ class XList extends DatabaseUsageXList
contentType: ContentType::JSON
),
])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->callback($this->action(...));
@@ -11,6 +11,7 @@ use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
use Utopia\Validator\WhiteList;
@@ -60,7 +61,7 @@ class Create extends RelationshipCreate
Database::RELATION_MANY_TO_ONE,
Database::RELATION_MANY_TO_MANY,
Database::RELATION_ONE_TO_MANY
], true), 'Relation type')
], true), 'Relation type', enum: new Enum(name: 'RelationshipType'))
->param('twoWay', false, new Boolean(), 'Is Two Way?', true)
->param('key', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'Column Key.', true, ['dbForProject'])
->param('twoWayKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'Two Way Column Key.', true, ['dbForProject'])
@@ -68,7 +69,7 @@ class Create extends RelationshipCreate
Database::RELATION_MUTATE_CASCADE,
Database::RELATION_MUTATE_RESTRICT,
Database::RELATION_MUTATE_SET_NULL
], true), 'Constraints option', true)
], true), 'Constraints option', true, enum: new Enum(name: 'RelationMutate'))
->inject('response')
->inject('dbForProject')
->inject('publisherForDatabase')
@@ -12,6 +12,7 @@ use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\Nullable;
use Utopia\Validator\WhiteList;
@@ -60,7 +61,7 @@ class Update extends RelationshipUpdate
Database::RELATION_MUTATE_CASCADE,
Database::RELATION_MUTATE_RESTRICT,
Database::RELATION_MUTATE_SET_NULL
], true)), 'Constraints option', true)
], true)), 'Constraints option', true, enum: new Enum(name: 'RelationMutate'))
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Column Key.', true, ['dbForProject'])
->inject('response')
->inject('dbForProject')
@@ -12,6 +12,7 @@ use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
use Utopia\Validator\Nullable;
@@ -58,9 +59,9 @@ class Create extends IndexCreate
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('tableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).', false, ['dbForProject'])
->param('key', null, fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Index Key.', false, ['dbForProject'])
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.', enum: new Enum(name: 'TablesDBIndexType'))
->param('columns', null, fn (Database $dbForProject) => new ArrayList(new Key(true, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of columns to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' columns are allowed, each 32 characters long.', false, ['dbForProject'])
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true, enum: new Enum(name: 'OrderBy'))
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
->inject('response')
->inject('dbForProject')
@@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends CollectionUsageGet
@@ -49,7 +50,14 @@ class Get extends CollectionUsageGet
contentType: ContentType::JSON,
))
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->param('tableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Table ID.', false, ['dbForProject'])
->inject('response')
->inject('dbForProject')
@@ -11,6 +11,7 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends DatabaseUsageGet
@@ -46,7 +47,14 @@ class Get extends DatabaseUsageGet
),
])
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -9,6 +9,7 @@ use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class XList extends DatabaseUsageXList
@@ -43,7 +44,14 @@ class XList extends DatabaseUsageXList
contentType: ContentType::JSON
),
])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -12,6 +12,7 @@ use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
use Utopia\Validator\Nullable;
@@ -58,9 +59,9 @@ class Create extends IndexCreate
->param('databaseId', '', new UID(), 'Database ID.')
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
->param('key', null, new Key(), 'Index Key.')
->param('type', null, new WhiteList([Database::INDEX_HNSW_EUCLIDEAN,Database::INDEX_HNSW_DOT, Database::INDEX_HNSW_COSINE, Database::INDEX_OBJECT, Database::INDEX_KEY, Database::INDEX_UNIQUE]), 'Index type.')
->param('type', null, new WhiteList([Database::INDEX_HNSW_EUCLIDEAN,Database::INDEX_HNSW_DOT, Database::INDEX_HNSW_COSINE, Database::INDEX_OBJECT, Database::INDEX_KEY, Database::INDEX_UNIQUE]), 'Index type.', enum: new Enum(name: 'VectorsDBIndexType'))
->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.')
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true, enum: new Enum(name: 'OrderBy'))
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
->inject('response')
->inject('dbForProject')
@@ -10,6 +10,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends CollectionUsageGet
@@ -53,7 +54,14 @@ class Get extends CollectionUsageGet
contentType: ContentType::JSON,
))
->param('databaseId', '', new UID(), 'Database ID.')
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->param('collectionId', '', new UID(), 'Collection ID.')
->inject('response')
->inject('dbForProject')
@@ -16,6 +16,7 @@ use Utopia\Database\Document;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Logger\Log;
use Utopia\Logger\Logger;
use Utopia\Platform\Enum;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
@@ -74,7 +75,7 @@ class Create extends CreateDocumentAction
)
])
->param('texts', [], fn (array $plan) => new ArrayList(new Text(0), $plan['databasesMaxEmbeddingTexts'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of text to generate embeddings.', false, ['plan'])
->param('model', Ollama::MODEL_EMBEDDING_GEMMA, new WhiteList(Ollama::MODELS), 'The embedding model to use for generating vector embeddings.', true)
->param('model', Ollama::MODEL_EMBEDDING_GEMMA, new WhiteList(Ollama::MODELS), 'The embedding model to use for generating vector embeddings.', true, enum: new Enum(name: 'EmbeddingModel'))
->inject('response')
->inject('project')
->inject('embeddingAgent')
@@ -10,6 +10,7 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class Get extends DatabaseUsageGet
@@ -50,7 +51,14 @@ class Get extends DatabaseUsageGet
),
])
->param('databaseId', '', new UID(), 'Database ID.')
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -9,6 +9,7 @@ use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Platform\Enum;
use Utopia\Validator\WhiteList;
class XList extends DatabaseUsageXList
@@ -48,7 +49,14 @@ class XList extends DatabaseUsageXList
contentType: ContentType::JSON
),
])
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->callback($this->action(...));
@@ -227,6 +227,7 @@ class Create extends Action
}
if ($completed) {
$queueForEvents->reset();
return;
}
@@ -249,6 +250,8 @@ class Create extends Action
$metadata = \array_merge($deployment->getAttribute('sourceMetadata', []), $metadata);
if ($uploaded === $chunks) {
$queueForEvents->reset();
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($deployment, Response::MODEL_DEPLOYMENT);
@@ -3,6 +3,7 @@
namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Download;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@@ -12,7 +13,7 @@ use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Request;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Storage\Device;
use Utopia\Validator\WhiteList;
@@ -55,7 +56,7 @@ class Get extends Action
))
->param('functionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Function ID.', false, ['dbForProject'])
->param('deploymentId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Deployment ID.', false, ['dbForProject'])
->param('type', 'source', new WhiteList(['source', 'output']), 'Deployment file to download. Can be: "source", "output".', true)
->param('type', 'source', new WhiteList(['source', 'output']), 'Deployment file to download. Can be: "source", "output".', true, enum: new Enum(name: 'DeploymentDownloadType'))
->inject('response')
->inject('request')
->inject('dbForProject')
@@ -6,6 +6,7 @@ use Appwrite\Event\Event;
use Appwrite\Event\Message\Build as BuildMessage;
use Appwrite\Event\Publisher\Build as BuildPublisher;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\Platform\Modules\Compute\Base;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -19,7 +20,7 @@ use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Request;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
@@ -68,7 +69,7 @@ class Create extends Base
->param('repository', '', new Text(128, 0), 'Repository name of the template.')
->param('owner', '', new Text(128, 0), 'The name of the owner of the template.')
->param('rootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.')
->param('type', '', new WhiteList(['commit', 'branch', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag')
->param('type', '', new WhiteList(['commit', 'branch', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag', enum: new Enum(name: 'TemplateReferenceType'))
->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag')
->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true)
->inject('request')
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Vcs;
use Appwrite\Event\Event;
use Appwrite\Event\Publisher\Build as BuildPublisher;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\Platform\Modules\Compute\Base;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -14,7 +15,7 @@ use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Request;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
@@ -61,7 +62,7 @@ class Create extends Base
))
->param('functionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Function ID.', false, ['dbForProject'])
// TODO: Support tag in future
->param('type', '', new WhiteList(['branch', 'commit']), 'Type of reference passed. Allowed values are: branch, commit')
->param('type', '', new WhiteList(['branch', 'commit']), 'Type of reference passed. Allowed values are: branch, commit', enum: new Enum(name: 'VCSReferenceType'))
->param('reference', '', new Text(255), 'VCS reference to create deployment from. Depending on type this can be: branch name, commit hash')
->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true)
->inject('request')
@@ -38,6 +38,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Request;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\AnyOf;
@@ -86,7 +87,7 @@ class Create extends Base
->param('body', '', new Text(10485760, 0), 'HTTP body of execution. Default value is empty string.', true)
->param('async', false, new Boolean(true), 'Execute code in the background. Default value is false.', true)
->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true)
->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'], true), 'HTTP method of execution. Default value is POST.', true)
->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'], true), 'HTTP method of execution. Default value is POST.', true, enum: new Enum(name: 'ExecutionMethod'))
->param('headers', [], new AnyOf([new Assoc(), new Text(65535)], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true)
->param('scheduledAt', null, new Nullable(new Text(100)), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true)
->inject('response')
@@ -161,7 +162,7 @@ class Create extends Base
/* @var Document $function */
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
@@ -67,7 +67,7 @@ class Get extends Base
) {
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
@@ -77,7 +77,7 @@ class XList extends Base
) {
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
$isAPIKey = $user->isApp($authorization->getRoles());
$isAPIKey = $user->isKey($authorization->getRoles());
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
if ($function->isEmpty() || (!$function->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
@@ -33,6 +33,7 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Roles;
use Utopia\Http\Request;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
@@ -80,7 +81,7 @@ class Create extends Base
))
->param('functionId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.', enum: new Enum(name: 'FunctionRuntime'))
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('events', [], new ArrayList(new FunctionEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
@@ -89,12 +90,14 @@ class Create extends Base
->param('logging', true, new Boolean(), 'When disabled, executions will exclude logs and errors, and will be slightly faster.', true)
->param('entrypoint', '', new Text(1028, 0), 'Entrypoint File. This path is relative to the "providerRootDirectory".', true)
->param('commands', '', new Text(8192, 0), 'Build Commands.', true)
->param('scopes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('projectScopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of scopes allowed for API key auto-generated for every execution. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.', true)
->param('scopes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('projectScopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of scopes allowed for API key auto-generated for every execution. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.', true, enum: new Enum(name: 'ProjectKeyScopes'))
->param('installationId', '', new Text(128, 0), 'Appwrite Installation ID for VCS (Version Control System) deployment.', true)
->param('providerRepositoryId', '', new Text(128, 0), 'Repository ID of the repo linked to the function.', true)
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function.', true)
->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true)
->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true)
->param('providerBranches', [], new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of branch name patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all branches.', true)
->param('providerPaths', [], new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of file path patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all file changes.', true)
->param('buildSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
$plan,
Config::getParam('specifications', []),
@@ -147,6 +150,8 @@ class Create extends Base
string $providerBranch,
bool $providerSilentMode,
string $providerRootDirectory,
array $providerBranches,
array $providerPaths,
string $buildSpecification,
string $runtimeSpecification,
string $templateRepository,
@@ -248,6 +253,8 @@ class Create extends Base
'providerBranch' => $providerBranch,
'providerRootDirectory' => $providerRootDirectory,
'providerSilentMode' => $providerSilentMode,
'providerBranches' => $providerBranches,
'providerPaths' => $providerPaths,
'buildSpecification' => $buildSpecification,
'runtimeSpecification' => $runtimeSpecification,
]));
@@ -25,6 +25,7 @@ use Utopia\Database\Validator\Roles;
use Utopia\Database\Validator\UID;
use Utopia\Http\Adapter\Swoole\Request;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
@@ -72,7 +73,7 @@ class Update extends Base
))
->param('functionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Function ID.', false, ['dbForProject'])
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.', true)
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.', true, enum: new Enum(name: 'FunctionRuntime'))
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('events', [], new ArrayList(new FunctionEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
@@ -81,12 +82,14 @@ class Update extends Base
->param('logging', true, new Boolean(), 'When disabled, executions will exclude logs and errors, and will be slightly faster.', true)
->param('entrypoint', '', new Text(1028, 0), 'Entrypoint File. This path is relative to the "providerRootDirectory".', true)
->param('commands', '', new Text(8192, 0), 'Build Commands.', true)
->param('scopes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('projectScopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of scopes allowed for API Key auto-generated for every execution. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.', true)
->param('scopes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('projectScopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of scopes allowed for API Key auto-generated for every execution. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.', true, enum: new Enum(name: 'ProjectKeyScopes'))
->param('installationId', '', new Text(128, 0), 'Appwrite Installation ID for VCS (Version Controle System) deployment.', true)
->param('providerRepositoryId', null, new Nullable(new Text(128, 0)), 'Repository ID of the repo linked to the function', true)
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function', true)
->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true)
->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true)
->param('providerBranches', null, new Nullable(new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE)), 'List of branch name patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all branches.', true)
->param('providerPaths', null, new Nullable(new ArrayList(new Text(128), APP_LIMIT_ARRAY_PARAMS_SIZE)), 'List of file path patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all file changes.', true)
->param('buildSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
$plan,
Config::getParam('specifications', []),
@@ -132,6 +135,8 @@ class Update extends Base
string $providerBranch,
bool $providerSilentMode,
string $providerRootDirectory,
?array $providerBranches,
?array $providerPaths,
string $buildSpecification,
string $runtimeSpecification,
int $deploymentRetention,
@@ -276,6 +281,8 @@ class Update extends Base
'providerBranch' => $providerBranch,
'providerRootDirectory' => $providerRootDirectory,
'providerSilentMode' => $providerSilentMode,
'providerBranches' => $providerBranches ?? $function->getAttribute('providerBranches', []),
'providerPaths' => $providerPaths ?? $function->getAttribute('providerPaths', []),
'buildSpecification' => $buildSpecification,
'runtimeSpecification' => $runtimeSpecification,
'search' => implode(' ', [$functionId, $name, $runtime]),
@@ -11,6 +11,7 @@ use FunctionUseCases;
use Utopia\Config\Config;
use Utopia\Database\Document;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
@@ -50,8 +51,8 @@ class XList extends Base
)
]
))
->param('runtimes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('runtimes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of runtimes allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' runtimes are allowed.', true)
->param('useCases', [], new ArrayList(new WhiteList(FunctionUseCases::getAll()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of use cases allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' use cases are allowed.', true)
->param('runtimes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('runtimes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of runtimes allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' runtimes are allowed.', true, enum: new Enum(name: 'FunctionRuntime'))
->param('useCases', [], new ArrayList(new WhiteList(FunctionUseCases::getAll()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of use cases allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' use cases are allowed.', true, enum: new Enum(name: 'FunctionTemplateUseCase'))
->param('limit', 25, new Range(1, 5000), 'Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.', true)
->param('offset', 0, new Range(0, 5000), 'Offset the list of returned templates. Maximum offset is 5000.', true)
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
@@ -3,6 +3,7 @@
namespace Appwrite\Platform\Modules\Functions\Http\Usage;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\Platform\Modules\Compute\Base;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -14,7 +15,7 @@ use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\WhiteList;
@@ -52,7 +53,14 @@ class Get extends Base
]
))
->param('functionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Function ID.', false, ['dbForProject'])
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -3,6 +3,7 @@
namespace Appwrite\Platform\Modules\Functions\Http\Usage;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\Platform\Modules\Compute\Base;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -13,7 +14,7 @@ use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\WhiteList;
@@ -50,7 +51,14 @@ class XList extends Base
)
]
))
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true)
->param('range', '30d', new WhiteList(['24h', '30d', '90d']), 'Date range.', true, enum: new Enum(
name: 'UsageRange',
map: [
'24h' => 'Twenty Four Hours',
'30d' => 'Thirty Days',
'90d' => 'Ninety Days',
]
))
->inject('response')
->inject('dbForProject')
->inject('authorization')
@@ -104,8 +104,6 @@ class Builds extends Action
Executor $executor,
array $plan
): void {
Console::log('Build action started');
$payload = $message->getPayload();
if (empty($payload)) {
@@ -113,6 +111,8 @@ class Builds extends Action
}
$type = $payload['type'] ?? '';
Span::add('build.type', $type);
$resource = new Document($payload['resource'] ?? []);
$deployment = new Document($payload['deployment'] ?? []);
$template = new Document($payload['template'] ?? []);
@@ -124,7 +124,6 @@ class Builds extends Action
switch ($type) {
case BUILD_TYPE_DEPLOYMENT:
case BUILD_TYPE_RETRY:
Console::info('Creating build for deployment: ' . $deployment->getId());
$github = new GitHub($cache);
$this->buildDeployment(
$deviceForFunctions,
@@ -193,8 +192,6 @@ class Builds extends Action
Span::add('deployment.id', $deployment->getId());
Span::add('build.timeout', $timeout);
Console::info('Deployment action started');
$startTime = DateTime::now();
$durationStart = \microtime(true);
@@ -268,7 +265,7 @@ class Builds extends Action
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
}
Console::log('Status marked as processing');
Span::add('deployment.status', 'processing');
$queueForRealtime
->setPayload($deployment->getArrayCopy())
@@ -359,7 +356,7 @@ class Builds extends Action
->setPayload($deployment->getArrayCopy())
->trigger();
Console::log('Template cloned');
Span::add('build.source_size', $deployment->getAttribute('sourceSize'));
}
} elseif ($isVcsEnabled) {
// VCS and VCS+Temaplte
@@ -403,8 +400,6 @@ class Builds extends Action
throw new \Exception('Unable to clone code repository: ' . $stderr);
}
Console::log('Git repository cloned');
// Local refactoring for function folder with spaces
if (str_contains($rootDirectory, ' ')) {
$rootDirectoryWithoutSpaces = str_replace(' ', '', $rootDirectory);
@@ -478,8 +473,6 @@ class Builds extends Action
$queueForRealtime
->setPayload($deployment->getArrayCopy())
->trigger();
Console::log('Git template pushed');
}
$tmpPath = '/tmp/builds/' . $deploymentId;
@@ -531,18 +524,17 @@ class Builds extends Action
->setPayload($deployment->getArrayCopy())
->trigger();
Console::log('Git source uploaded');
Span::add('build.source_size', $deployment->getAttribute('sourceSize'));
$this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime, $platform);
}
Console::log('Status marked as building');
/** Request the executor to build the code... */
$deployment->setAttribute('status', 'building');
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), new Document([
'status' => 'building',
]));
Span::add('deployment.status', 'building');
if ($deployment->getSequence() === $resource->getAttribute('latestDeploymentInternalId', '')) {
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
@@ -687,11 +679,10 @@ class Builds extends Action
}
$isCanceled = false;
Console::log('Runtime creation started');
$span = Span::current();
Co::join([
Co\go(function () use ($executor, &$response, $project, $deployment, $source, $resource, $runtime, $vars, $command, $cpus, $memory, $timeout, &$err, $version) {
Co\go(function () use ($executor, &$response, $project, $deployment, $source, $resource, $runtime, $vars, $command, $cpus, $memory, $timeout, &$err, $version, $span) {
try {
if ($version === 'v2') {
$command = 'tar -zxf /tmp/code.tar.gz -C /usr/code && cd /usr/local/src/ && ./build.sh';
@@ -739,16 +730,18 @@ class Builds extends Action
outputDirectory: $outputDirectory ?? ''
);
Console::log('createRuntime finished');
} catch (ExecutorTimeout $error) {
Console::warning('createRuntime timed out');
$span?->set('build.runtime.timed_out', true);
$span?->set('build.runtime.error_type', $error::class);
$span?->set('build.runtime.error_message', $error->getMessage());
$err = new AppwriteException(AppwriteException::BUILD_TIMEOUT, previous: $error);
} catch (\Throwable $error) {
Console::warning('createRuntime failed');
$span?->set('build.runtime.error_type', $error::class);
$span?->set('build.runtime.error_message', $error->getMessage());
$err = $error;
}
}),
Co\go(function () use ($executor, $project, &$deployment, &$response, $dbForProject, $timeout, &$err, $queueForRealtime, &$isCanceled) {
Co\go(function () use ($executor, $project, &$deployment, &$response, $dbForProject, $timeout, &$err, $queueForRealtime, &$isCanceled, $span) {
try {
$insideSeparation = false;
@@ -756,7 +749,7 @@ class Builds extends Action
deploymentId: $deployment->getId(),
projectId: $project->getId(),
timeout: $timeout,
callback: function ($logs) use (&$response, &$err, $dbForProject, &$isCanceled, &$deployment, $queueForRealtime, &$insideSeparation) {
callback: function ($logs) use (&$response, &$err, $dbForProject, &$isCanceled, &$deployment, $queueForRealtime, &$insideSeparation, $span) {
if ($isCanceled) {
return;
}
@@ -767,7 +760,7 @@ class Builds extends Action
if ($deployment->getAttribute('status') === 'canceled') {
$isCanceled = true;
Console::info('Ignoring realtime logs because build has been canceled');
$span?->set('build.logs.ignored_reason', 'canceled');
return;
}
@@ -836,9 +829,10 @@ class Builds extends Action
}
}
);
Console::warning('listLogs finished');
$span?->set('build.logs.finished', true);
} catch (\Throwable $error) {
Console::warning('listLogs failed');
$span?->set('build.logs.error_type', $error::class);
$span?->set('build.logs.error_message', $error->getMessage());
if (empty($err)) {
$err = $error;
}
@@ -846,8 +840,6 @@ class Builds extends Action
}),
]);
Console::log('Runtime creation finished');
$latestDeployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($latestDeployment->getAttribute('status') === 'canceled') {
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
@@ -870,6 +862,8 @@ class Builds extends Action
$deployment->setAttribute('buildPath', $response['path']);
$deployment->setAttribute('buildSize', $response['size']);
$deployment->setAttribute('totalSize', $deployment->getAttribute('buildSize', 0) + $deployment->getAttribute('sourceSize', 0));
Span::add('build.size', $deployment->getAttribute('buildSize'));
Span::add('build.total_size', $deployment->getAttribute('totalSize'));
$logs = '';
foreach ($response['output'] as $log) {
@@ -908,8 +902,8 @@ class Builds extends Action
$deployment->setAttribute('adapter', $detection->getName());
$deployment->setAttribute('fallbackFile', $detection->getFallbackFile() ?? '');
Console::log('Adapter detected');
Span::add('build.adapter', $deployment->getAttribute('adapter'));
Span::add('build.fallback_file', $deployment->getAttribute('fallbackFile'));
} elseif ($adapter === 'ssr' && $detection->getName() === 'static') {
throw new \Exception('Adapter mismatch. Detected: ' . $detection->getName() . ' does not match with the set adapter: ' . $adapter);
}
@@ -927,8 +921,6 @@ class Builds extends Action
->setPayload($deployment->getArrayCopy())
->trigger();
Console::log('Build details stored');
$this->afterBuildSuccess($queueForRealtime, $dbForProject, $deployment, $runtime, $adapter);
$logs = $deployment->getAttribute('buildLogs', '');
@@ -942,8 +934,7 @@ class Builds extends Action
'buildLogs' => $deployment->getAttribute('buildLogs'),
'status' => 'ready',
]));
Console::log('Status marked as ready');
Span::add('deployment.status', 'ready');
if ($deployment->getSequence() === $resource->getAttribute('latestDeploymentInternalId', '')) {
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
@@ -969,7 +960,7 @@ class Builds extends Action
if ($currentActiveStartTime < $deploymentStartTime) {
$activateBuild = true;
} else {
Console::info('Skipping auto-activation as current deployment is more recent');
Span::add('build.auto_activation.skipped_reason', 'current_deployment_newer');
}
}
} else {
@@ -1031,7 +1022,7 @@ class Builds extends Action
break;
}
Console::log('Deployment activated');
Span::add('build.activated', true);
}
$this->afterDeploymentSuccess(
@@ -1099,7 +1090,7 @@ class Builds extends Action
]));
}, $queries);
Console::log('Preview rule created');
Span::add('build.preview_rule_created', true);
}
}
@@ -1109,6 +1100,7 @@ class Builds extends Action
'buildEndedAt' => $endTime,
'buildDuration' => \intval(\ceil($durationEnd - $durationStart)),
]));
Span::add('build.duration', $deployment->getAttribute('buildDuration'));
$queueForRealtime
->setPayload($deployment->getArrayCopy())
->trigger();
@@ -1119,8 +1111,6 @@ class Builds extends Action
return;
}
Console::log('Build duration updated');
/** Update function schedule */
// Inform scheduler if function is still active
@@ -1144,23 +1134,21 @@ class Builds extends Action
deploymentId: $deployment->getId(),
));
Console::log('Site screenshot queued');
Span::add('build.screenshot_queued', true);
}
Console::info('Deployment action finished');
} catch (\Throwable $th) {
Console::warning('Build failed:');
Console::error($th->getMessage());
Console::error($th->getFile());
Console::error($th->getLine());
Console::error($th->getTraceAsString());
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
return;
}
Span::add('build.error.stage', 'deployment');
Span::add('build.error.type', $th::class);
Span::add('build.error.message', $th->getMessage());
Span::add('build.error.file', $th->getFile());
Span::add('build.error.line', $th->getLine());
// Color message red
$message = $th->getMessage();
if (! \str_contains($message, '')) {
@@ -1182,6 +1170,8 @@ class Builds extends Action
$deployment->setAttribute('buildEndedAt', $endTime);
$deployment->setAttribute('buildDuration', \intval(\ceil($durationEnd - $durationStart)));
$deployment->setAttribute('status', 'failed');
Span::add('deployment.status', 'failed');
Span::add('build.duration', $deployment->getAttribute('buildDuration'));
$deployment->setAttribute('buildLogs', $message);
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, new Document([
@@ -1200,7 +1190,7 @@ class Builds extends Action
->trigger();
if ($isVcsEnabled) {
$this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime, $platform);
$this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime, $platform, true);
}
} finally {
$queueForRealtime
@@ -1360,7 +1350,8 @@ class Builds extends Action
Database $dbForProject,
Database $dbForPlatform,
Realtime $queueForRealtime,
array $platform
array $platform,
bool $secondaryError = false
): void {
$deployment = new Document();
@@ -1456,9 +1447,14 @@ class Builds extends Action
}
}
} catch (\Throwable $th) {
Console::warning('Git action failed:');
Console::warning($th->getMessage());
Console::warning($th->getTraceAsString());
$span = Span::current();
$errorPrefix = $secondaryError ? 'build.error.secondary' : 'build.git_action.error';
$span?->set("{$errorPrefix}.stage", 'git_action');
$span?->set("{$errorPrefix}.status", $status);
$span?->set("{$errorPrefix}.type", $th::class);
$span?->set("{$errorPrefix}.message", $th->getMessage());
$span?->set("{$errorPrefix}.file", $th->getFile());
$span?->set("{$errorPrefix}.line", $th->getLine());
$logs = $deployment->getAttribute('buildLogs', '');
$date = \date('H:i:s');
@@ -1477,7 +1473,7 @@ class Builds extends Action
private function cancelDeployment(string $deploymentId, Database $dbForProject, Realtime $queueForRealtime)
{
Console::info('Build has been canceled');
Span::add('deployment.status', 'canceled');
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
@@ -24,6 +24,7 @@ use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Document;
use Utopia\Platform\Enum;
use Utopia\System\System;
use Utopia\Validator\Integer;
use Utopia\Validator\WhiteList;
@@ -71,7 +72,7 @@ class Get extends Base
System::getEnv('_APP_SCREENSHOTS_QUEUE_NAME', Event::SCREENSHOTS_QUEUE_NAME),
System::getEnv('_APP_MESSAGING_QUEUE_NAME', Event::MESSAGING_QUEUE_NAME),
System::getEnv('_APP_MIGRATIONS_QUEUE_NAME', Event::MIGRATIONS_QUEUE_NAME),
]), 'The name of the queue')
]), 'The name of the queue', enum: new Enum(name: 'HealthQueueName'))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('response')
->inject('publisherForDatabase')
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\Appwrite;
use Appwrite\Event\Event;
use Appwrite\Event\Message\Migration as MigrationMessage;
use Appwrite\Event\Publisher\Migration as MigrationPublisher;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
@@ -15,7 +16,7 @@ use Utopia\Database\Helpers\ID;
use Utopia\Database\Validator\UID;
use Utopia\Migration\Destinations\OnDuplicate;
use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
@@ -54,11 +55,11 @@ class Create extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(AppwriteSource::getSupportedResources())), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(AppwriteSource::getSupportedResources())), 'List of resources to migrate', enum: new Enum(name: 'AppwriteMigrationResource'))
->param('endpoint', '', new URL(), 'Source Appwrite endpoint')
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Source Project ID', false, ['dbForProject'])
->param('apiKey', '', new Text(512), 'Source API Key')
->param('onDuplicate', OnDuplicate::Fail->value, new WhiteList(OnDuplicate::values()), 'Behavior when a row with an existing $id is encountered. "fail" (default): abort on first conflict. "skip": silently ignore. "overwrite": replace existing row.', true)
->param('onDuplicate', OnDuplicate::Fail->value, new WhiteList(OnDuplicate::values()), 'Behavior when a row with an existing $id is encountered. "fail" (default): abort on first conflict. "skip": silently ignore. "overwrite": replace existing row.', true, enum: new Enum(name: 'MigrationOnDuplicate'))
->inject('response')
->inject('dbForProject')
->inject('project')
@@ -3,13 +3,14 @@
namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\Appwrite\Report;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Document;
use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
@@ -46,7 +47,7 @@ class Get extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(AppwriteSource::getSupportedResources())), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(AppwriteSource::getSupportedResources())), 'List of resources to migrate', enum: new Enum(name: 'AppwriteMigrationResource'))
->param('endpoint', '', new URL(), "Source's Appwrite Endpoint")
->param('projectID', '', new Text(512), "Source's Project ID")
->param('key', '', new Text(512), "Source's API Key")
@@ -26,6 +26,7 @@ use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Migration\Sources\CSV;
use Utopia\Migration\Transfer;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Storage\Device;
use Utopia\System\System;
@@ -69,7 +70,7 @@ class Create extends Action
->param('fileId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'File ID.', false, ['dbForProject'])
->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.')
->param('internalFile', false, new Boolean(), 'Is the file stored in an internal bucket?', true)
->param('onDuplicate', OnDuplicate::Fail->value, new WhiteList(OnDuplicate::values()), 'Behavior when a row with an existing $id is encountered. "fail" (default): abort on first conflict. "skip": silently ignore. "overwrite": replace existing row.', true)
->param('onDuplicate', OnDuplicate::Fail->value, new WhiteList(OnDuplicate::values()), 'Behavior when a row with an existing $id is encountered. "fail" (default): abort on first conflict. "skip": silently ignore. "overwrite": replace existing row.', true, enum: new Enum(name: 'MigrationOnDuplicate'))
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
@@ -6,6 +6,7 @@ use Appwrite\Event\Event;
use Appwrite\Event\Message\Migration as MigrationMessage;
use Appwrite\Event\Publisher\Migration as MigrationPublisher;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
@@ -15,7 +16,7 @@ use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Migration\Sources\Firebase;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
@@ -53,7 +54,7 @@ class Create extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate', enum: new Enum(name: 'FirebaseMigrationResource'))
->param('serviceAccount', '', new Text(65536), 'JSON of the Firebase service account credentials')
->inject('response')
->inject('dbForProject')
@@ -3,13 +3,14 @@
namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\Firebase\Report;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Document;
use Utopia\Migration\Sources\Firebase;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
@@ -45,7 +46,7 @@ class Get extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate', enum: new Enum(name: 'FirebaseMigrationResource'))
->param('serviceAccount', '', new Text(65536), 'JSON of the Firebase service account credentials')
->inject('response')
->callback($this->action(...));
@@ -26,6 +26,7 @@ use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Migration\Sources\JSON as JSONSource;
use Utopia\Migration\Transfer;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Storage\Device;
use Utopia\System\System;
@@ -68,7 +69,7 @@ class Create extends Action
->param('fileId', '', new UID(), 'File ID.')
->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.')
->param('internalFile', false, new Boolean(), 'Is the file stored in an internal bucket?', true)
->param('onDuplicate', OnDuplicate::Fail->value, new WhiteList(OnDuplicate::values()), 'Behavior when a row with an existing $id is encountered. "fail" (default): abort on first conflict. "skip": silently ignore. "overwrite": replace existing row.', true)
->param('onDuplicate', OnDuplicate::Fail->value, new WhiteList(OnDuplicate::values()), 'Behavior when a row with an existing $id is encountered. "fail" (default): abort on first conflict. "skip": silently ignore. "overwrite": replace existing row.', true, enum: new Enum(name: 'MigrationOnDuplicate'))
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\NHost;
use Appwrite\Event\Event;
use Appwrite\Event\Message\Migration as MigrationMessage;
use Appwrite\Event\Publisher\Migration as MigrationPublisher;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
@@ -14,7 +15,7 @@ use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Migration\Sources\NHost;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
@@ -53,7 +54,7 @@ class Create extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(NHost::getSupportedResources())), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(NHost::getSupportedResources())), 'List of resources to migrate', enum: new Enum(name: 'NHostMigrationResource'))
->param('subdomain', '', new Text(512), 'Source\'s Subdomain')
->param('region', '', new Text(512), 'Source\'s Region')
->param('adminSecret', '', new Text(512), 'Source\'s Admin Secret')
@@ -3,13 +3,14 @@
namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\NHost\Report;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Document;
use Utopia\Migration\Sources\NHost;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
@@ -46,7 +47,7 @@ class Get extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(NHost::getSupportedResources())), 'List of resources to migrate.')
->param('resources', [], new ArrayList(new WhiteList(NHost::getSupportedResources())), 'List of resources to migrate.', enum: new Enum(name: 'NHostMigrationResource'))
->param('subdomain', '', new Text(512), 'Source\'s Subdomain.')
->param('region', '', new Text(512), 'Source\'s Region.')
->param('adminSecret', '', new Text(512), 'Source\'s Admin Secret.')
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\Supabase;
use Appwrite\Event\Event;
use Appwrite\Event\Message\Migration as MigrationMessage;
use Appwrite\Event\Publisher\Migration as MigrationPublisher;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
@@ -14,7 +15,7 @@ use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Migration\Sources\Appwrite as AppwriteSource;
use Utopia\Migration\Sources\Supabase;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
@@ -54,7 +55,7 @@ class Create extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(Supabase::getSupportedResources(), true)), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(Supabase::getSupportedResources(), true)), 'List of resources to migrate', enum: new Enum(name: 'SupabaseMigrationResource'))
->param('endpoint', '', new URL(), 'Source\'s Supabase Endpoint')
->param('apiKey', '', new Text(512), 'Source\'s API Key')
->param('databaseHost', '', new Text(512), 'Source\'s Database Host')
@@ -3,13 +3,14 @@
namespace Appwrite\Platform\Modules\Migrations\Http\Migrations\Supabase\Report;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Document;
use Utopia\Migration\Sources\Supabase;
use Utopia\Platform\Action;
use Utopia\Platform\Enum;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
@@ -47,7 +48,7 @@ class Get extends Action
)
]
))
->param('resources', [], new ArrayList(new WhiteList(Supabase::getSupportedResources(), true)), 'List of resources to migrate')
->param('resources', [], new ArrayList(new WhiteList(Supabase::getSupportedResources(), true)), 'List of resources to migrate', enum: new Enum(name: 'SupabaseMigrationResource'))
->param('endpoint', '', new URL(), 'Source\'s Supabase Endpoint.')
->param('apiKey', '', new Text(512), 'Source\'s API Key.')
->param('databaseHost', '', new Text(512), 'Source\'s Database Host.')

Some files were not shown because too many files have changed in this diff Show More