Compare commits

...
Author SHA1 Message Date
Chirag Aggarwal e3a093c960 chore: update version to 66 2025-04-24 13:15:16 +00:00
Chirag Aggarwal 20c3663736 chore: update database library to 0.65.x 2025-04-24 09:05:16 +00:00
Matej BačoandGitHub 77739390dd Merge pull request #9664 from appwrite/chore-separate-benchmark-in-cicd
Chore separate benchmark in ci/cd
2025-04-22 15:43:44 +02:00
Matej Bačo 21f3221a21 Fix consistency with previous implementation 2025-04-22 12:21:10 +00:00
Matej Bačo 00f1723878 Fix merge conflict 2025-04-22 12:18:30 +00:00
Matej Bačo 3d16901ea1 Merge remote-tracking branch 'origin/1.7.x' into chore-separate-benchmark-in-cicd 2025-04-22 12:17:33 +00:00
Matej BačoandGitHub bd204ddca5 Merge pull request #9672 from appwrite/feat-add-favicon-to-error-pages
Feat add favicon to error pages
2025-04-22 13:57:47 +02:00
Khushboo VermaandGitHub 51af7e35bf Merge branch '1.7.x' into feat-add-favicon-to-error-pages 2025-04-22 16:53:03 +05:30
Khushboo Verma 9c2064a5ce dynamic urls 2025-04-22 16:52:29 +05:30
Matej BačoandGitHub 304f33991f Merge pull request #8997 from appwrite/feat-tokens-module
Feat: tokens
2025-04-22 13:16:07 +02:00
Khushboo Verma 8bd89441a4 Add png logo 2025-04-22 16:41:22 +05:30
Khushboo Verma 1401e20247 Merge branch '1.7.x' into feat-add-favicon-to-error-pages 2025-04-22 16:32:19 +05:30
Khushboo Verma bc2e17827c Merge branch '1.7.x' of github.com:appwrite/appwrite into 1.7.x 2025-04-22 16:32:08 +05:30
Matej BačoandGitHub d5cb9d0f1f Merge branch '1.7.x' into feat-tokens-module 2025-04-22 12:25:51 +02:00
Matej BačoandGitHub fd0d891d45 Merge pull request #8378 from appwrite/feat-development-keys
Development Keys
2025-04-22 12:22:12 +02:00
Matej Bačo cb7aad9885 Improve code rabbit 2025-04-22 11:08:19 +02:00
Matej Bačo 1a33b75d42 Fix html error page test 2025-04-22 10:48:25 +02:00
Khushboo Verma 1f51381e4b Merge branch '1.7.x' of github.com:appwrite/appwrite into 1.7.x 2025-04-22 12:46:33 +05:30
Chirag AggarwalandGitHub 1065f27a44 Merge branch '1.7.x' into feat-tokens-module 2025-04-21 19:28:27 +05:30
Chirag Aggarwal b0d03c5109 chore: update file security logic 2025-04-21 13:44:30 +00:00
Eldad A. FuxandGitHub 0bf2318cdd Merge pull request #9673 from appwrite/allow-compressed-csv
Allow compressed CSV
2025-04-21 12:03:09 +02:00
Darshan 53a0424326 update: tests. 2025-04-21 12:12:01 +05:30
Darshan 927489bc5b update: handle decryption as well. 2025-04-21 12:04:36 +05:30
Darshan 0accc494f0 update: tests. 2025-04-21 10:25:43 +05:30
Darshan 21be819025 fix: test message! 2025-04-21 10:12:09 +05:30
Darshan 873b384f70 update: allow compressed files. 2025-04-21 10:01:13 +05:30
Khushboo Verma cda521a5d9 Add favicon 2025-04-20 15:52:29 +05:30
Chirag Aggarwal 421bfed8b7 chore: regenerate specs 2025-04-18 16:06:02 +00:00
Chirag Aggarwal 6d0d15f469 Merge branch '1.7.x' into feat-tokens-module 2025-04-18 16:01:06 +00:00
Chirag Aggarwal d130e7d3bd chore: add stricter checks according to review 2025-04-18 15:32:25 +00:00
Khushboo Verma fe287044a7 Format benchmark.yml 2025-04-17 20:45:53 +05:30
Khushboo Verma 816c3a1401 Fix version 2025-04-17 20:31:08 +05:30
Khushboo Verma deac241e68 Create new file for benchmarking workflow 2025-04-17 20:25:11 +05:30
Matej Bačo f8343e01cd PR review suggestions 2025-04-17 16:13:09 +02:00
Khushboo Verma 208dc37738 Merge branch '1.7.x' of github.com:appwrite/appwrite into 1.7.x 2025-04-17 19:37:44 +05:30
Matej Bačo b8ce3cb9fe Post-merge fixes 2025-04-17 15:57:47 +02:00
Matej Bačo 9993cca484 Merge branch '1.7.x' into feat-development-keys 2025-04-17 15:51:31 +02:00
Matej BačoandGitHub 61868a9b01 Merge pull request #9663 from appwrite/update-specs
Update: specs
2025-04-17 13:42:42 +02:00
Darshan b158c4dec9 update: specs. 2025-04-17 17:06:13 +05:30
Matej BačoandGitHub a2c774de31 Merge pull request #8859 from appwrite/feat-sites
Feat sites
2025-04-17 13:29:27 +02:00
Jake BarnbyandGitHub 3c220d603c Merge pull request #9662 from appwrite/add-resource-id
Add `resourceId`
2025-04-17 11:24:49 +00:00
Darshan c294386e17 add: resourceId for csv. 2025-04-17 16:39:02 +05:30
Matej BačoandGitHub f1ff8dd783 Merge pull request #9660 from appwrite/fix-deployment-deletion
Fix deployment and executions deletion
2025-04-17 12:20:41 +02:00
Matej BačoandGitHub f803a2268b Merge branch 'feat-sites' into fix-deployment-deletion 2025-04-17 12:17:10 +02:00
Matej Bačo db44598419 Update composer.lock 2025-04-17 12:16:58 +02:00
Khushboo Verma 93db0c3cd2 Fix logs and executions deletion 2025-04-17 10:14:58 +00:00
Matej Bačo cd9a2b761c Merge branch '1.7.x' into feat-sites 2025-04-17 12:13:06 +02:00
Matej Bačo 9f69aa624e Update comments 2025-04-17 12:11:52 +02:00
Chirag Aggarwal ba22e5f457 chore: simplify action constructor 2025-04-17 07:38:29 +00:00
Chirag Aggarwal 04b6f62ac2 chore: review changes 2025-04-17 07:21:33 +00:00
Khushboo Verma ad85fc6184 Add resourceType query to deployment deletion 2025-04-17 06:47:16 +00:00
Chirag Aggarwal 7172ccfc5b chore: specs + formatting 2025-04-17 06:25:42 +00:00
Chirag Aggarwal b2dffe4057 Merge branch '1.7.x' into feat-tokens-module 2025-04-17 06:19:18 +00:00
Jake BarnbyandGitHub d8e5a97266 Merge pull request #9622 from appwrite/csv-import
Feat: CSV Import
2025-04-17 06:13:33 +00:00
Darshan 6d3e40d73b address comments: change order, remove comment. 2025-04-17 11:03:03 +05:30
Darshan 767e202b34 update: name. 2025-04-17 10:54:23 +05:30
Darshan fda0af6694 bump: dependency. 2025-04-17 10:51:30 +05:30
Darshan 36ab6ce236 address comments: add more tests. 2025-04-17 10:36:05 +05:30
Darshan 680b214950 update: storage volume name. 2025-04-17 08:59:30 +05:30
Darshan cc7d038c3e address comments: change deviceForCsvImports to deviceForImports. 2025-04-17 08:54:50 +05:30
Matej Bačo 73d1e6c225 Fix tests 2025-04-16 15:39:08 +02:00
Darshan bc8683ab75 add: csv import tests! 2025-04-16 16:52:23 +05:30
Matej Bačo 87d14a88d2 AI-recommended changes 2025-04-16 12:45:58 +02:00
Matej Bačo 733e0498a7 AI-recommended changes 2025-04-16 11:50:42 +02:00
Matej Bačo e48fadf9fd PR review changes 2025-04-16 10:43:02 +02:00
Darshan 9d6cd8249a change: constant name. 2025-04-16 11:56:40 +05:30
Darshan 73b2a14ea3 update: changes as per migrations lib. 2025-04-16 11:55:04 +05:30
Matej BačoandGitHub 9893f77e6d Merge pull request #9606 from appwrite/feat-update-error-pages
Design nice looking error pages
2025-04-15 15:51:21 +02:00
Matej BačoandGitHub 2f537d3948 Merge branch 'feat-sites' into feat-update-error-pages 2025-04-15 15:20:03 +02:00
Matej Bačo e53ec21a2c Improve copy 2025-04-15 15:17:43 +02:00
Matej Bačo 8777fdb417 Remove leftover 2025-04-15 14:16:12 +02:00
Matej Bačo dbe42beb45 Improve tests 2025-04-15 14:16:04 +02:00
Chirag Aggarwal 76c7eb14eb chore: fix sdk fallback back to unknown 2025-04-15 12:08:18 +00:00
Chirag Aggarwal 8944e1db14 chore: update null check for sdk descriptions 2025-04-15 12:04:29 +00:00
Chirag Aggarwal c365480aec chore: small changes from review devkeys 2025-04-15 12:02:55 +00:00
Khushboo Verma 0fc41b27ee Dark theme for trace error page 2025-04-15 10:48:25 +00:00
Chirag Aggarwal 40c15077e2 chore: update devkey init and make tests use mock oauth 2025-04-15 10:47:04 +00:00
Khushboo Verma 60c632363f Merge branch 'feat-sites' into feat-update-error-pages 2025-04-15 10:45:39 +00:00
Matej Bačo 60fafe8feb PR review changes 2025-04-15 11:40:32 +02:00
Matej BačoandGitHub 2669e66ae2 Merge pull request #9597 from appwrite/fix-usage-sites
Fix: usage stats changes
2025-04-15 11:26:02 +02:00
Chirag Aggarwal 9bec94c976 fix: env 2025-04-14 18:02:30 +00:00
Chirag Aggarwal 6596569259 chore: make devkeys test dependence free 2025-04-14 18:01:40 +00:00
Matej Bačo 84ec907a47 Merge branch 'feat-sites' into feat-update-error-pages 2025-04-14 14:17:32 +02:00
Matej BačoandGitHub d1d36a2372 Merge pull request #9566 from appwrite/chore-add-tests-for-empty-output-dir
Add tests for empty output directory
2025-04-14 13:39:32 +02:00
Matej BačoandGitHub 0b6a8ec2ca Update tests/e2e/Services/Sites/SitesCustomServerTest.php 2025-04-14 13:39:23 +02:00
Darshan ab73a70c83 address comments. 2025-04-14 16:30:05 +05:30
Matej Bačo ed95ac7643 Re-add test, simplify 2025-04-14 12:54:56 +02:00
Matej Bačo 42f3e06985 Merge branch 'feat-sites' into chore-add-tests-for-empty-output-dir 2025-04-14 12:45:25 +02:00
Matej BačoandGitHub 470857daf8 Merge pull request #9542 from appwrite/chore-add-test-for-empty-source
Chore add test for empty source
2025-04-14 12:43:30 +02:00
Matej Bačo baa1cb19c6 Re-add test, simplify 2025-04-14 12:28:22 +02:00
Matej Bačo 3f5647bcc9 Merge branch 'feat-sites' into chore-add-test-for-empty-source 2025-04-14 12:10:57 +02:00
Darshan 91199e746b update: use plain csv, use options. 2025-04-14 15:03:30 +05:30
Chirag Aggarwal 74abf4897b chore: fix teamCreateMembership 2025-04-14 08:47:57 +00:00
Chirag Aggarwal 6372180537 chore: update specs 2025-04-14 08:22:42 +00:00
Chirag Aggarwal a1aabd351c fix: env 2025-04-14 07:34:52 +00:00
Chirag Aggarwal f31cb0cdfc chore: added tests for checking if sdks are updated in devkeys 2025-04-14 07:34:05 +00:00
Chirag Aggarwal 3b8354d2ea chore: add sdk to key 2025-04-14 03:55:04 +00:00
Darshan 2ad967043c update: deps. 2025-04-12 17:10:29 +05:30
Darshan a64b8e57af address comments. 2025-04-12 17:10:06 +05:30
Matej Bačo 52024ccc26 Add starters; update console 2025-04-10 16:11:38 +02:00
Khushboo Verma d733e8b75f Add trace button 2025-04-10 16:39:37 +05:30
Matej Bačo 2523613056 Improve logs coloring 2025-04-10 10:20:12 +02:00
Chirag Aggarwal 0479f4cca7 chore: change abuse back to disabled 2025-04-10 07:29:24 +00:00
Khushboo Verma 7bb548aecb Fix test 2025-04-10 00:39:36 +05:30
Khushboo Verma e78a3e1f83 Fix test 2025-04-10 00:11:17 +05:30
Khushboo Verma 98a5294709 Handle route_not_found 2025-04-09 23:35:08 +05:30
Khushboo Verma 39476fa3d5 Fix button URL for no active deployments 2025-04-09 23:20:06 +05:30
Chirag Aggarwal 45df0ef854 chore: add cors test 2025-04-09 16:24:24 +00:00
Chirag Aggarwal 013555cc8e chore: add tests for hostname check with devkeys 2025-04-09 14:21:56 +00:00
Chirag Aggarwal b9f50d9f01 chore: fix test 2025-04-09 13:21:06 +00:00
Chirag Aggarwal 3c78e7efff fix: query description 2025-04-09 13:15:59 +00:00
Chirag Aggarwal c6399a2a01 chore: update specs and tests 2025-04-09 13:11:48 +00:00
Chirag Aggarwal e8a0425cc3 chore: add allowed attributes to query 2025-04-09 13:03:56 +00:00
Darshan a53eb6c750 update: bump migrations and update params. 2025-04-09 18:24:59 +05:30
Matej Bačo db15b05332 Upgrade COnsole 2025-04-09 14:35:54 +02:00
Matej Bačo 1a2db06654 Upgrade detector 2025-04-09 13:51:34 +02:00
Chirag Aggarwal b4b356e61f chore: add queries and search to listing devkeys 2025-04-09 11:14:02 +00:00
Darshan 624538fcaf revert: local dockerfile change. 2025-04-09 16:35:27 +05:30
Matej Bačo e2f082eea1 Update specs 2025-04-09 11:48:27 +02:00
Chirag Aggarwal 4a1bf2eb74 fix: permissions on create devKey 2025-04-09 09:44:30 +00:00
Chirag Aggarwal 84595e625d chore: use getDocument instead to fetch devKey 2025-04-09 09:31:05 +00:00
Chirag Aggarwal 7aecd3814a fix: minor mistakes in devkeys naming and initialization 2025-04-09 09:15:36 +00:00
Matej BačoandGitHub 2be7e1e8d4 Merge pull request #9627 from appwrite/feat-a-record
Feat: A/AAA record support
2025-04-09 11:13:28 +02:00
Chirag Aggarwal 5a5d1752f9 Merge branch '1.7.x' into feat-development-keys 2025-04-09 09:02:20 +00:00
Matej Bačo dff1319e4d Fix failure test 2025-04-09 10:50:26 +02:00
Matej Bačo e7b64113ca pr review changes; fix tests 2025-04-09 10:31:33 +02:00
Khushboo Verma 921311e91e Fix tests 2025-04-09 11:58:54 +05:30
Khushboo Verma 0b4b7f5296 Update error message 2025-04-09 10:19:38 +05:30
Khushboo Verma 83401c1004 Add metadata to buttons 2025-04-09 10:13:54 +05:30
Damodar Lohani be939c6598 Fix typo 2025-04-09 02:57:49 +00:00
Damodar LohaniandGitHub db699fe0f6 Merge branch 'feat-sites' into fix-usage-sites 2025-04-09 08:01:15 +05:45
Damodar Lohani 387ef142cc fix test 2025-04-09 02:16:03 +00:00
Matej Baco 2689cceb71 Implement A/AAAA custom domain support 2025-04-08 14:48:50 +00:00
Matej Bačo d205ea61c1 Separate function & site timeout 2025-04-08 12:23:43 +02:00
Matej Bačo 2acf241827 Increase default timeout to fix screenshot cold-start issues 2025-04-08 12:12:53 +02:00
Damodar LohaniandGitHub b862fc6b4c Merge branch 'feat-sites' into fix-usage-sites 2025-04-08 15:30:52 +05:45
Matej Bačo f7605453b4 Upgrade console 2025-04-08 11:26:24 +02:00
Damodar LohaniandGitHub 0c35498dbb Merge branch 'feat-sites' into fix-usage-sites 2025-04-08 14:58:14 +05:45
Matej Bačo 5a0b22f638 Fix after merge 2025-04-08 11:09:12 +02:00
Damodar Lohani c7a97a16df fix test 2025-04-08 09:08:04 +00:00
Damodar Lohani 12bf434f6a fix division by 0 2025-04-08 09:08:00 +00:00
Damodar Lohani a1a6b40277 fix description 2025-04-08 08:59:20 +00:00
Damodar Lohani 8d239b7dc8 Fix test 2025-04-08 08:55:22 +00:00
Darshan 130024e0ef Merge branch '1.7.x' into csv-import 2025-04-08 14:25:01 +05:30
Damodar Lohani ad72805fd6 Fix test 2025-04-08 08:53:36 +00:00
Damodar Lohani 080350f7ad Fix data types and response 2025-04-08 08:52:12 +00:00
Damodar LohaniandGitHub 8d0cdb8e7f Merge branch 'feat-sites' into fix-usage-sites 2025-04-08 14:30:43 +05:45
Matej Bačo a0c013fcec Post-1.6.x-merge fixes 2025-04-08 10:44:57 +02:00
Damodar Lohani ed332a776f More stats in usage endpoints 2025-04-08 08:42:55 +00:00
Matej Bačo 8e32ef1851 Merge branch '1.7.x' into feat-sites 2025-04-08 10:41:39 +02:00
Matej Bačo 69a7c23d2b Merge branch '1.6.x' into 1.7.x 2025-04-08 10:24:09 +02:00
Darshan 89815cba1c revert: local dockerfile change. 2025-04-08 11:20:47 +05:30
Darshan 8dfbc128ac feat: import csv. 2025-04-08 11:19:39 +05:30
Khushboo Verma 9f00ad47f3 Added function execute tests 2025-04-08 11:07:32 +05:30
Damodar Lohani a6d15d032f improve sites usage 2025-04-08 05:06:03 +00:00
Damodar Lohani 327cb671a1 fix sites usage 2025-04-08 04:49:42 +00:00
Damodar LohaniandGitHub 314da2bb85 Merge branch 'feat-sites' into fix-usage-sites 2025-04-08 10:19:42 +05:45
Khushboo Verma 8db6474d80 Add tests for functions 2025-04-08 00:28:51 +05:30
Steven NguyenandGitHub a20ff31ba3 Merge pull request #9561 from appwrite/improve-gitpod-config
chore: update gitpod.yml config
2025-04-07 10:40:33 -07:00
Matej Bačo 89a0fb8c9b Update docker-compose.yml 2025-04-07 17:29:02 +02:00
Khushboo Verma ea1fc208e1 Add tests for no active deployments 2025-04-07 14:38:06 +05:30
Christy JacobandGitHub 31a5a175b3 Merge pull request #9420 from appwrite/PLA-1968
feat: refactor executor setup
2025-04-07 12:49:25 +04:00
Fabian Gruber 0ae70f8321 feat: inject executor instead of creating a new instance 2025-04-07 09:53:38 +02:00
Fabian Gruber 954ed45a36 feat: update appwrite to use generic S3 adapter 2025-04-07 09:53:38 +02:00
Khushboo Verma e718f4252f Add test for canceled deployment error 2025-04-07 12:56:51 +05:30
Damodar Lohani c07c1479f7 fix 2025-04-07 07:15:49 +00:00
Damodar Lohani 76fb59fd73 fix 2025-04-07 07:11:46 +00:00
Damodar Lohani 14e740e62d fix typo 2025-04-07 07:10:52 +00:00
Damodar Lohani cb2905c837 fix use correct method 2025-04-07 07:09:32 +00:00
Damodar Lohani e46ee904e0 reuse code 2025-04-07 07:07:17 +00:00
Khushboo Verma b78fbf02af Merge branch 'feat-sites' into feat-update-error-pages 2025-04-07 12:15:57 +05:30
Damodar Lohani 092bb1adac fix possible division by zero 2025-04-07 06:41:13 +00:00
Damodar Lohani af7c5f9f40 retry sites state test 2025-04-07 06:36:38 +00:00
Damodar Lohani 49a514a206 separate metric test 2025-04-07 06:35:20 +00:00
Damodar Lohani 1b88aa855c fix typo 2025-04-07 06:28:21 +00:00
Damodar Lohani 23ed68502f Sites usage test 2025-04-07 06:27:56 +00:00
Damodar Lohani 8e18af5db1 update get usage and response model 2025-04-07 04:45:20 +00:00
Darshan 179def8f4d add: imports collection 2025-04-07 10:12:58 +05:30
Damodar Lohani b6550c88ef new metrics in functions usage response 2025-04-07 03:52:17 +00:00
Steven NguyenandGitHub fcd31f4cff Merge pull request #9616 from appwrite/update-dependencies
chore: update php image to 0.8.1
2025-04-06 07:25:34 -07:00
Damodar LohaniandGitHub 2d7b01aa35 Merge pull request #9615 from appwrite/fix-owner-downgrade
Restrict role change for sole org owner
2025-04-06 13:59:02 +05:45
Damodar LohaniandGitHub 86478e463a Merge branch 'feat-sites' into fix-usage-sites 2025-04-06 12:04:04 +05:45
Darshan 2243f0c72e fix: test for only console db <> orgs. 2025-04-06 10:29:18 +05:30
Darshan c3c568653f add: roles check test. 2025-04-06 10:21:55 +05:30
Chirag AggarwalandGitHub 403083b0ce Update .gitpod.yml 2025-04-06 08:31:46 +05:30
Chirag Aggarwal e5ef825ac4 chore: update php image to 0.8.1 2025-04-05 15:47:22 +00:00
Chirag Aggarwal abd953974d chore: give read write permission to vendor for gitpod config 2025-04-05 14:43:07 +00:00
Darshan 7297188c1b update: roles check. 2025-04-05 19:42:20 +05:30
Darshan 2a672f5a63 fix: don't allow the only owner in an org to change their role to anything else. 2025-04-05 19:20:24 +05:30
Eldad A. FuxandGitHub a160b0f987 Merge pull request #9559 from appwrite/change-sample-rate
Sample rate from DSN
2025-04-04 11:08:21 +02:00
Matej Bačo fb1a19747a Add documentation template 2025-04-04 10:44:03 +02:00
DarshanandGitHub 01e2eb5025 Merge branch '1.6.x' into change-sample-rate 2025-04-04 13:44:28 +05:30
Jake BarnbyandGitHub baffa615e6 Merge pull request #9610 from appwrite/remove-audit-payload
Remove audit payload
2025-04-04 04:26:43 +00:00
fogelito bd87672607 Remove audit payload 2025-04-03 18:31:50 +03:00
Khushboo Verma 8139ec0d6f Add more error pages 2025-04-03 18:49:41 +05:30
Khushboo Verma 5841d5ee57 Add tests for error pages 2025-04-03 12:35:05 +05:30
Damodar Lohani 7935658222 dev interval to 30s 2025-04-03 06:11:44 +00:00
Damodar LohaniandGitHub 1c10528585 Merge branch 'feat-sites' into fix-usage-sites 2025-04-03 10:23:34 +05:45
Jake BarnbyandGitHub 2e784c0e8b Merge pull request #9608 from appwrite/fix-image-transformations-cache
Fix: image transformation cache
2025-04-03 04:21:49 +00:00
Damodar Lohani 5d2b0c38d9 Fix reduce for functions and sites 2025-04-03 04:16:27 +00:00
Damodar Lohani 1660c0b00c Fix: image transformation cache 2025-04-03 02:44:29 +00:00
Khushboo Verma 579f795c81 Merge branch 'feat-sites' into feat-update-error-pages 2025-04-03 00:00:19 +05:30
Khushboo Verma c684d0a2cd Enhance error pages 2025-04-02 23:59:43 +05:30
Matej Bačo 8fbc517b17 Fix rules cleanup 2025-04-02 16:47:37 +02:00
Damodar Lohani 13510ffcb5 new sites metrics 2025-04-02 05:15:33 +00:00
Damodar Lohani 0d9743c8cb separate sites network metrics 2025-04-02 05:10:12 +00:00
Damodar Lohani d1e083338e fix disable metrics for static sites 2025-04-02 05:05:24 +00:00
Damodar Lohani 0d7187a5cc Skip metrics when sites executed during build 2025-04-02 04:48:22 +00:00
Jake BarnbyandGitHub 96327a9ebc Merge pull request #9603 from appwrite/feat-tenant-type-fixes
Update database
2025-04-02 02:49:10 +00:00
Jake Barnby 32a5ff4c8c Update release 2025-04-02 13:37:26 +13:00
Jake Barnby 31b1663f6b Merge remote-tracking branch 'origin/1.6.x' into feat-tenant-type-fixes
# Conflicts:
#	composer.lock
2025-04-02 13:30:51 +13:00
Jake Barnby c152d8e001 Update database 2025-04-02 13:02:35 +13:00
Eldad A. FuxandGitHub 8fd6208502 Merge pull request #9602 from appwrite/feat-update-ws
Feat update ws
2025-04-01 21:52:14 +02:00
Eldad Fux 938505da51 Updated websocket version 2025-04-01 21:23:23 +02:00
Matej Bačo 51d2deca5f Fix endpoint description 2025-04-01 20:44:49 +02:00
Matej Bačo 1bdbb8fce1 Fix failing tests 2025-04-01 16:50:11 +02:00
Matej Bačo d87c67eecb Fix failing tests 2025-04-01 15:29:07 +02:00
Matej Bačo 8a2ec0dcd7 Add 1.7.x specs 2025-04-01 15:19:18 +02:00
Matej Bačo 9c6551ff7b Update specs 2025-04-01 13:27:33 +02:00
Matej Bačo 066474010b Improve QR quality 2025-04-01 11:24:42 +02:00
Matej Bačo 7bbf04e7ac Merge branch '1.7.x' into feat-sites 2025-04-01 10:49:44 +02:00
Damodar Lohani feb5d5cbf1 fix counts 2025-04-01 08:07:47 +00:00
Damodar Lohani a36adbd68b Fix: skipped metrics 2025-04-01 07:31:53 +00:00
Damodar LohaniandGitHub 30462b1951 Merge pull request #9598 from appwrite/cast-tenant
Fix tenant casting
2025-04-01 11:54:31 +05:45
fogelito b46de29735 database 0.63.2 2025-04-01 08:15:03 +03:00
fogelito d92413fd6b Revert database lib 2025-04-01 08:13:56 +03:00
Damodar Lohani 04010ca205 fix missing param 2025-04-01 05:08:58 +00:00
Damodar Lohani 840eb1776e fix typo 2025-04-01 05:07:44 +00:00
Damodar Lohani 3fd42d3fc6 sites metrics in stats resources 2025-04-01 05:02:54 +00:00
Damodar Lohani 3a3e9cc281 Fix get usage - sites and functions 2025-04-01 03:59:40 +00:00
Damodar Lohani 7ecba8e5bb add disabled metrics 2025-04-01 02:41:27 +00:00
Damodar Lohani 1af638deef new resource type metrics 2025-04-01 02:21:52 +00:00
Matej Bačo dd8b718985 Rollback unwanted changes 2025-03-31 18:52:46 +02:00
Matej Bačo ef39f8c2e2 Fix multiple small bugs
- VCS deployments stuck in waiting
- Fix tcp coroutine issues in builds worker, failing screenshots
- Fix command escaping with space and quotes
- Remove branding from already branded 404 page
- Fix css reset of preview banner
- Remove scope check from public endpoints
- Improve build logs colors
- Function logs say capturing screenshot
- Update GitHub comment design
2025-03-31 18:51:33 +02:00
fogelito 4698323f38 lock 2025-03-31 16:19:17 +03:00
fogelito 612b064d2a 0.63.2 2025-03-31 15:16:59 +03:00
Damodar Lohani e629037da2 use proper resource type 2025-03-31 07:56:26 +00:00
Damodar Lohani ad9d953e10 fix missing resource type 2025-03-31 07:51:37 +00:00
Damodar Lohani 11bd9e63f0 update constants 2025-03-31 06:45:16 +00:00
Damodar Lohani ac152a76b5 Fix: usage stats changes 2025-03-31 06:28:58 +00:00
Christy JacobandGitHub 1a5e9748f3 Merge pull request #9592 from appwrite/feat-update-fetch
Feat update fetch
2025-03-29 00:37:29 +04:00
Eldad Fux 22939831f2 Updated fetch version 2025-03-28 20:58:25 +01:00
Steven NguyenandGitHub e0a54a2ea6 Merge pull request #9503 from appwrite/pla-2610
feat: add query by role to memberships
2025-03-28 07:14:13 -07:00
Matej Bačo fbd0051118 Make env var public 2025-03-28 11:38:45 +01:00
Khushboo Verma ace7a6baa1 Resolve merge conflicts 2025-03-28 13:35:53 +05:30
Jake BarnbyandGitHub 2069c9fdad Merge pull request #9588 from appwrite/fix-select-cursor-pagination
Add order by for cursor
2025-03-28 06:33:27 +00:00
fogelito a4c18c4b77 Remove array merge 2025-03-28 09:16:25 +03:00
fogelito cba700402b Add order by for cursor 2025-03-28 09:04:50 +03:00
Chirag Aggarwal 85edfc6af8 chore: added test for users.listmemberships 2025-03-28 05:47:18 +00:00
Matej Bačo cfe6b8d34b Add score to function templates 2025-03-27 14:23:15 +01:00
Matej BačoandGitHub aedfe0352d Merge pull request #9553 from appwrite/feat-fix-308-redirect
Feat fix 308 redirect
2025-03-27 14:05:36 +01:00
Christy JacobandGitHub 60399aaa0a Merge pull request #9573 from appwrite/feat-multi-tenant-insert-2
Feat multi tenant insert
2025-03-27 15:54:30 +04:00
Khushboo Verma 9404e9225e Update test 2025-03-27 16:36:37 +05:30
Khushboo Verma e263d681d9 Resolve merge conflicts 2025-03-27 16:27:26 +05:30
Matej Bačo 6b8df26f84 Update libs 2025-03-27 11:56:09 +01:00
Matej Bačo e8cc95323e Generate specs 2025-03-27 11:34:38 +01:00
Matej Bačo 7c1fb0d945 Add template details 2025-03-27 11:32:03 +01:00
Matej Bačo 20f780a58b Add lynx 2025-03-27 09:55:04 +01:00
Jake Barnby ad7552e676 Merge remote-tracking branch 'origin/1.6.x' into feat-multi-tenant-insert-2 2025-03-27 21:39:57 +13:00
Christy JacobandGitHub 93839ec36d Merge pull request #9586 from appwrite/revert-9533-PLA-2683
Revert "chore(audits): return queue pre-fetch results"
2025-03-27 12:38:00 +04:00
Jake BarnbyandGitHub 17dc8e3f8a Revert "chore(audits): return queue pre-fetch results" 2025-03-27 21:37:10 +13:00
Matej BačoandGitHub 3d1ea6d330 Merge pull request #9580 from appwrite/fix-deployment-status
Fix: Deployment status
2025-03-27 09:31:17 +01:00
Matej Bačo 834872870f Linter fix 2025-03-27 09:17:15 +01:00
Matej BačoandGitHub 1946fca9f6 Merge branch 'feat-sites' into fix-deployment-status 2025-03-27 09:00:36 +01:00
Khushboo Verma e4b9b92cbf Use Fira Code for powered by 2025-03-27 13:27:51 +05:30
Jake Barnby c79e8e5b95 Update database 2025-03-27 18:04:17 +13:00
Jake Barnby a60d19fb42 Merge remote-tracking branch 'origin/1.6.x' into feat-multi-tenant-insert-2 2025-03-27 17:23:15 +13:00
Matej Bačo 6af57ca48e Fix async crashes 2025-03-26 17:51:39 +01:00
Christy JacobandGitHub ef7cf41a61 Merge pull request #9533 from appwrite/PLA-2683
chore(audits): return queue pre-fetch results
2025-03-26 22:16:52 +05:30
Matej Bačo 3c8e4da34d Update tests 2025-03-26 17:04:38 +01:00
Matej BačoandGitHub 3b1f2afbd5 Merge pull request #9569 from appwrite/chore-add-error-for-failed-builds
If build has failed, show correct error page
2025-03-26 15:44:39 +01:00
Matej Bačo 34ab21730d Linter fix 2025-03-26 15:22:19 +01:00
Matej Bačo 70fbf69c56 Fix fonts 2025-03-26 14:38:27 +01:00
Matej Bačo 62be0e1d00 Fix latest deployment attributes 2025-03-26 14:38:18 +01:00
Matej Bačo 2c55f5aaa6 Concurrency screenshots 2025-03-26 13:20:14 +01:00
Matej Bačo 681b6031aa Linter fix 2025-03-26 12:59:15 +01:00
Matej Bačo ab03b4e3ca Deployment ready after screenshot 2025-03-26 12:59:05 +01:00
Khushboo Verma 2e0a6f9b9e Update swoole version 2025-03-26 17:22:49 +05:30
Khushboo Verma 572544bf55 Merge branch 'feat-sites' into feat-fix-308-redirect 2025-03-26 17:17:23 +05:30
Khushboo Verma 583a18dcd7 Update assertion 2025-03-26 17:06:19 +05:30
Khushboo Verma 3b9318c2fc Add tests 2025-03-26 16:52:32 +05:30
Jake BarnbyandGitHub 91ad4097ff Merge branch '1.6.x' into feat-multi-tenant-insert-2 2025-03-26 11:16:27 +00:00
Jake Barnby d9d38197dd Update libs 2025-03-26 23:47:59 +13:00
Khushboo Verma e836df13ba Merge branch 'feat-sites' into chore-add-error-for-failed-builds 2025-03-26 16:11:03 +05:30
Jake Barnby a8b2ebb356 Merge remote-tracking branch 'origin/1.6.x' into feat-multi-tenant-insert-2 2025-03-26 23:36:18 +13:00
Matej Bačo 023597842e Merge branch 'feat-sites' of github.com:appwrite/appwrite into feat-sites 2025-03-26 10:34:57 +01:00
Matej Bačo c57ec57277 Upgrade Console 2025-03-26 10:22:58 +01:00
Matej Bačo 6978f6960e Add new templates; fix bash support during QA 2025-03-26 10:14:51 +01:00
Jake BarnbyandGitHub c53262a44c Merge pull request #9579 from appwrite/fix-select-cursor-pagination
Add $permissions for delete documents selects
2025-03-26 08:52:51 +00:00
fogelito 8339435fb5 Merge branch '1.6.x' of https://github.com/appwrite/appwrite into fix-select-cursor-pagination 2025-03-26 10:02:50 +02:00
fogelito 424a357503 Add $permissions 2025-03-26 10:02:30 +02:00
Jake BarnbyandGitHub 9a7512d1fd Merge pull request #9578 from appwrite/fix-select-cursor-pagination
Deletes worker fix selects for pagination
2025-03-26 07:35:41 +00:00
fogelito a461d5bf72 Deletes fix selects 2025-03-26 09:20:44 +02:00
Matej BačoandGitHub 95ba881ab7 Merge pull request #9575 from appwrite/feat-bash-support
Feat: Bash support
2025-03-25 23:55:33 +01:00
Matej Bačo 708b6279e0 upgrade lib 2025-03-25 23:38:44 +01:00
Matej Bačo 0295dfcc63 Fix function tsts 2025-03-25 23:07:56 +01:00
Matej BačoandGitHub 06f138b39d Merge branch 'feat-sites' into feat-bash-support 2025-03-25 22:50:18 +01:00
Christy JacobandGitHub 9d020fdef5 Merge pull request #9577 from appwrite/fix-region-scheduler
Fix: schedules region filtering
2025-03-26 02:24:13 +05:30
Matej Bačo f25143b240 Support fra-region on cloud; temporary fix 2025-03-25 21:52:02 +01:00
Matej Bačo d89cdbcf5a Fix schedules region filtering 2025-03-25 21:34:09 +01:00
Matej Bačo 524ce8789f Upgrade libs 2025-03-25 21:01:28 +01:00
Matej Bačo 8db247c840 Update SDKs 2025-03-25 15:57:38 +01:00
Matej BačoandGitHub b11749c452 Merge pull request #9576 from appwrite/feat-add-logging-param-to-sites
Add logging param to sites
2025-03-25 15:55:22 +01:00
Khushboo Verma c38a5177dd Address PR comments 2025-03-25 20:02:29 +05:30
Khushboo Verma abae54f72c Update copy for logging 2025-03-25 19:49:57 +05:30
Khushboo Verma bf2b3b68e3 Add logging param to sites 2025-03-25 19:14:14 +05:30
Matej BačoandGitHub 11d2b06b67 Merge pull request #9570 from appwrite/feat-add-fallback-file-to-deployment
Add fallbackfile and adapter to deployments collection
2025-03-25 14:14:52 +01:00
Khushboo Verma fe94717196 Update tests 2025-03-25 18:31:14 +05:30
Khushboo Verma 5582c6956d Remove specific checks 2025-03-25 17:03:19 +05:30
Khushboo Verma 2acce83257 Merge branch 'feat-sites' into chore-add-tests-for-empty-output-dir 2025-03-25 16:31:27 +05:30
Matej Bačo 81b3e81d83 Add bash support 2025-03-25 10:57:32 +01:00
Jake Barnby 6195674611 Update database 2025-03-25 21:20:26 +13:00
Jake BarnbyandGitHub 4804bdf110 Merge pull request #9568 from appwrite/db-0-62-1
Bump database 0.62.x
2025-03-25 03:44:18 +00:00
Jake BarnbyandGitHub cb356bc410 Merge pull request #9523 from appwrite/delete-query-fixes
Delete worker queries fixes
2025-03-25 03:19:39 +00:00
Jake Barnby 74d9a3c181 Fix syntax 2025-03-25 16:19:18 +13:00
Jake BarnbyandGitHub 6bcdc8c769 Update src/Appwrite/Utopia/Database/Validator/Queries/Base.php 2025-03-25 16:01:27 +13:00
Jake BarnbyandGitHub c9c9db5640 Update src/Appwrite/Platform/Workers/Deletes.php 2025-03-25 15:52:59 +13:00
Jake BarnbyandGitHub a20140eb36 Update src/Appwrite/Platform/Workers/Deletes.php 2025-03-25 15:52:54 +13:00
Jake BarnbyandGitHub c0cb4b26a3 Apply suggestions from code review 2025-03-25 15:51:47 +13:00
Jake BarnbyandGitHub b842e03f38 Merge branch '1.6.x' into delete-query-fixes 2025-03-25 02:43:08 +00:00
fogelito 2795505e82 line 2025-03-24 17:38:01 +02:00
fogelito 5799ca1041 remove var_dump 2025-03-24 17:37:34 +02:00
fogelito e11e7e6780 Add internalId 2025-03-24 17:33:02 +02:00
Khushboo Verma 9fd8c5ab9d Add fallbackfile and adapter to deployments collection 2025-03-24 20:04:02 +05:30
fogelito 0648de2046 Revert Base 2025-03-24 14:32:57 +02:00
fogelito 42f72b4477 Add internalId to orders 2025-03-24 13:33:36 +02:00
Matej Bačo 871e4b70f7 Upgrade Console 2025-03-24 12:32:44 +01:00
Matej Bačo 3e7cf6d60a Fix tests 2025-03-24 12:13:28 +01:00
fogelito 25b6d59e30 Add internalId 2025-03-24 12:54:19 +02:00
Khushboo Verma bd18edc197 If build has failed, show correct error page 2025-03-24 15:50:25 +05:30
Fabian Gruber 5479e6f8f1 chore(audits): return queue pre-fetch results 2025-03-24 10:18:16 +01:00
fogelito 586e676299 Merge branch '1.6.x' of https://github.com/appwrite/appwrite into db-0-62-1 2025-03-24 11:10:21 +02:00
fogelito 26821c8372 Bump database 0.62 2025-03-24 11:08:39 +02:00
Jake BarnbyandGitHub 6e146889bf Merge pull request #9563 from appwrite/refactor-init-auditretention
refactor: initialization of audit retention
2025-03-24 08:53:19 +00:00
Khushboo Verma 1580bac1fc Add tests for empty output directory 2025-03-24 13:30:21 +05:30
Chirag Aggarwal 7b7fd218f5 chore: formatting + updating specs 2025-03-24 05:06:18 +00:00
Chirag Aggarwal 37dfe0d719 refactor: initialization of audit retention 2025-03-22 14:05:39 +00:00
Chirag Aggarwal 86856bf87d chore: update gitpod.yml config 2025-03-22 13:55:23 +00:00
Darshan 26142f4f21 revert: local dockerfile changes! 🤦‍♂️ 2025-03-22 18:46:13 +05:30
Darshan a62c489a72 fix: missing import. 2025-03-22 18:38:12 +05:30
Darshan b358dad817 update: merge '1.7.x' on feat-development-keys. 2025-03-22 18:35:10 +05:30
Darshan 7c2ab4fcf6 update: change sample rate for 4xx via env. 2025-03-22 13:47:09 +05:30
Steven NguyenandGitHub 29ea03b7bb Merge pull request #9554 from appwrite/fix-team-count
chore: only update total count for privileged users
2025-03-21 10:09:22 -07:00
Chirag Aggarwal d661195a5f chore: only update total count for prviledged users 2025-03-21 15:59:30 +00:00
Matej Bačo 0f182817ec Sync templates 2025-03-21 15:46:36 +01:00
Khushboo Verma 65aa218aac Add test for permanent redirect 2025-03-21 17:54:07 +05:30
Khushboo Verma df943c62ca Add test for permanent redirect 2025-03-21 17:53:22 +05:30
Christy JacobandGitHub 50e7986f84 Merge pull request #9547 from appwrite/fix-audit-deletion
chore: fix console audits delete
2025-03-21 15:23:06 +05:30
Christy JacobandGitHub c7301af18a Merge pull request #9525 from appwrite/pla-2676
chore: stop tests on failure
2025-03-21 15:15:09 +05:30
Chirag Aggarwal c0c0c921dc chore: fix naming 2025-03-21 08:08:30 +00:00
Chirag Aggarwal 7c795da72f chore: fix type 2025-03-21 07:48:50 +00:00
Chirag Aggarwal 13750f7dbd feat: introduce new env 2025-03-21 07:42:10 +00:00
Khushboo Verma 21f12879ef Remove extra check 2025-03-21 12:11:29 +05:30
Khushboo Verma 1091aa3ddc Merge branch 'feat-sites' into chore-add-test-for-empty-source 2025-03-21 12:08:22 +05:30
Matej BačoandGitHub c323c227f9 Merge pull request #9549 from appwrite/fix-github-check-url
Fix GitHub check URL
2025-03-20 16:50:34 +01:00
Matej BačoandGitHub d72ba2a4b9 Merge pull request #9551 from appwrite/chore-code-readability-tasks-and-workers
Split params across multiple lines where overflowing
2025-03-20 16:50:01 +01:00
Matej BačoandGitHub ccb96d6525 Merge pull request #9550 from appwrite/chore-re-enable-commented-tests
Re-enable test
2025-03-20 16:49:16 +01:00
Matej Bačo 2dcebf3083 Add remaining changes after sync with 1.7.x 2025-03-20 16:48:09 +01:00
Matej Bačo cb85cfc5d9 Merge branch '1.7.x' into feat-sites 2025-03-20 16:42:36 +01:00
Matej Bačo 4aaa07d57b Merge branch '1.6.x' into 1.7.x 2025-03-20 16:41:18 +01:00
Matej BačoandGitHub d07b543e71 Merge pull request #9537 from appwrite/feat-latest-deployment-details
Feat: Latest deployment details
2025-03-20 16:40:04 +01:00
Matej Bačo 08b74007f7 Fix specs for console 2025-03-20 16:20:31 +01:00
Khushboo Verma 813424aa3c Split params across multiple lines where overflowing 2025-03-20 20:37:32 +05:30
Khushboo Verma e28333ed63 Re-enable test 2025-03-20 20:23:36 +05:30
Matej Bačo 172ebb5f7f Update specs 2025-03-20 15:51:15 +01:00
Matej Bačo 0f5480cbc0 Fix copy 2025-03-20 15:48:18 +01:00
Matej Bačo e34fc92c7c PR review changes 2025-03-20 15:44:15 +01:00
Matej Bačo bb01c9e9e9 Add latest deployment tests 2025-03-20 15:22:35 +01:00
Chirag Aggarwal b0b57935da chore: add comments 2025-03-20 13:42:19 +00:00
Chirag Aggarwal 7c3f8504bb chore: fix initialization 2025-03-20 13:15:14 +00:00
Khushboo Verma ec6683cfa9 Refactor 2025-03-20 18:44:00 +05:30
Khushboo Verma c2d0aded6d Fix GitHub check URL 2025-03-20 18:04:36 +05:30
Chirag Aggarwal 9d82892219 chore: update logic 2025-03-20 11:32:06 +00:00
Chirag Aggarwal 5eb7c36f50 chore: add console audit retention 2025-03-20 10:32:36 +00:00
fogelito 9c54cce5bd Queries fixes 2025-03-20 09:07:32 +02:00
Jake BarnbyandGitHub 9345025ade Merge pull request #9546 from appwrite/feat-improve-maintenance
Use cursor pagination with bigger limit for maintenance project loop
2025-03-20 02:51:31 +00:00
Jake Barnby 31ca35782b Use cursor pagination with bigger limit for maintenance project loop 2025-03-20 15:21:24 +13:00
Christy JacobandGitHub 2505e25da8 Merge pull request #9430 from appwrite/updates-projects-regions
Remove default region
2025-03-19 22:36:30 +05:30
fogelito cc0a97b10e Fixes 2025-03-19 16:37:15 +02:00
Khushboo Verma 18022d680b Assert exception 2025-03-19 16:22:38 +05:30
Khushboo Verma 7c75b51b1a Merge branch 'feat-sites' into chore-add-test-for-empty-source 2025-03-19 16:16:25 +05:30
shimon 88d6150db2 revert 2025-03-19 10:29:18 +02:00
shimon faed019d92 revert 2025-03-19 09:32:48 +02:00
shimon b318c2cc08 Merge branch '1.6.x' of github.com:appwrite/appwrite into updates-projects-regions 2025-03-18 21:54:55 +02:00
shimon eb4340cf4c revert 2025-03-18 21:49:28 +02:00
shimon ee09e2c91b revert 2025-03-18 21:47:54 +02:00
shimon e6e7c5c816 revert 2025-03-18 21:44:34 +02:00
shimon e9841e53b9 revert 2025-03-18 21:40:46 +02:00
Eldad A. FuxandGitHub 7d86ce76d8 Merge pull request #9536 from appwrite/pla-2687
chore: set min operations to 1 for reads and writes
2025-03-18 16:30:52 +01:00
fogelito 795928a037 Fix $id 2025-03-18 16:59:05 +02:00
Matej Bačo e75441a097 Didn't mean to remove that 🎀 2025-03-18 15:46:28 +01:00
Matej Bačo ffb86ace38 Add latest info detail to site & function 2025-03-18 15:29:21 +01:00
Chirag Aggarwal aab8bca91e fix: logic 2025-03-18 14:20:25 +00:00
Matej BačoandGitHub 963760678c Merge pull request #9534 from appwrite/feat-active-deployment-details
Feat: Active deployment details - status, creation date
2025-03-18 15:03:06 +01:00
Chirag Aggarwal 70e27748be chore: set min operations to 1 for reads and writes 2025-03-18 12:52:41 +00:00
Jake BarnbyandGitHub 556e00b62b Merge pull request #9526 from appwrite/feat-disable-pdo-persist
Disable PDO persistence since we manage our own pool
2025-03-18 12:19:58 +00:00
Khushboo VermaandGitHub e95aeed56c Merge pull request #9535 from appwrite/fix-github-author-url
Fix incorrect URL for git commits
2025-03-18 17:39:37 +05:30
Matej Bačo 362520ff4a Remove active depoyment status (not relevant, always ready) 2025-03-18 12:56:44 +01:00
Matej Bačo 7cade1a27d Add active deployment status and creation date 2025-03-18 12:44:21 +01:00
Matej BačoandGitHub 20d90e06f2 Merge pull request #9532 from appwrite/feat-site-deployment-details
Feat: Add screenshots to site
2025-03-18 12:16:55 +01:00
Matej Bačo ef163e8517 Add screenshots to site 2025-03-18 12:01:30 +01:00
Matej BačoandGitHub a0d4e4736c Merge pull request #9524 from appwrite/feat-deployment-total-size
Feat: totalSize attribute
2025-03-18 11:03:11 +01:00
Matej Bačo 3f1c4c2095 Add per-framework screenshot sleep 2025-03-18 11:02:32 +01:00
Christy JacobandGitHub 370a8e231c Merge pull request #9530 from appwrite/PLA-2662
feat: add pool telemetry
2025-03-18 14:44:52 +05:30
Matej Bačo 83bcad6e17 Fix deployment rule deletion 2025-03-18 10:10:16 +01:00
Fabian Gruber aa5ea7f3a1 feat: add pool telemetry 2025-03-18 10:01:06 +01:00
Jake BarnbyandGitHub 8a77eaf2bb Merge pull request #9529 from appwrite/feat-migration-read-db
Migration read from db
2025-03-18 08:01:07 +00:00
Jake Barnby fe308b4f1f Update lib 2025-03-18 20:49:19 +13:00
Khushboo Verma 20e3597a27 WIP: Add test for empty source 2025-03-18 13:04:44 +05:30
Jake Barnby e43a3109eb Update migration lib 2025-03-18 20:05:12 +13:00
Jake Barnby d9fbe9658d Merge branch '1.6.x' into feat-migration-read-db 2025-03-18 20:04:23 +13:00
Jake BarnbyandGitHub 1e2f5bcb84 Merge branch '1.6.x' into feat-disable-pdo-persist 2025-03-18 07:02:54 +00:00
Christy JacobandGitHub 088d0998cd Merge pull request #9514 from appwrite/feat-domains-count
Feat: domains count
2025-03-18 11:03:45 +05:30
Jake Barnby a7165e6a32 Disable PDO persistence since we manage our own pool 2025-03-18 16:51:00 +13:00
Chirag Aggarwal 5f7ceecb30 chore: stop tests on failure 2025-03-18 03:46:14 +00:00
Matej Bačo fd4b43569b Enable CodeRabbit for feat-sites 2025-03-17 17:48:33 +01:00
Matej Bačo b4536a94e0 Introduce dpeloyment totalSize + tests 2025-03-17 17:35:03 +01:00
shimon e5261e7d70 _app_region 2025-03-17 18:31:14 +02:00
shimon 60912cb084 _app_region 2025-03-17 18:14:58 +02:00
shimon 7149deeacb _app_region 2025-03-17 18:11:49 +02:00
shimon 59f613f9bb _app_region 2025-03-17 17:33:48 +02:00
shimon 8184bc8c78 _app_region 2025-03-17 17:31:24 +02:00
fogelito bbfd22ce2e Index check for delete worker 2025-03-17 17:05:40 +02:00
shimon 9cb860d446 _app_region 2025-03-17 13:52:17 +02:00
shimon 6eff011100 Merge branch '1.6.x' of github.com:appwrite/appwrite into updates-projects-regions
# Conflicts:
#	app/views/install/compose.phtml
2025-03-17 13:29:22 +02:00
Damodar LohaniandGitHub 8fd877810d Merge branch '1.6.x' into feat-domains-count 2025-03-17 12:49:59 +05:45
Jake Barnby 04711d8c02 Add doc 2025-03-17 19:21:31 +13:00
Damodar Lohani 4eece99768 Feat: domains count 2025-03-16 02:35:10 +00:00
Chirag AggarwalandGitHub 026dd56f55 Merge branch '1.7.x' into feat-development-keys 2025-03-15 19:18:44 +05:30
Chirag Aggarwal e80bc2bb39 chore: shifted migration to 1.7.0 2025-03-15 13:36:08 +00:00
Chirag AggarwalandGitHub 9a4220f2dd Merge branch '1.7.x' into pla-2610 2025-03-15 18:53:59 +05:30
Chirag AggarwalandGitHub 9df221d333 Merge branch '1.6.x' into feat-development-keys 2025-03-14 19:42:31 +05:30
Chirag AggarwalandGitHub afabd5b87a Merge branch '1.6.x' into feat-development-keys 2025-03-14 17:20:47 +05:30
Chirag Aggarwal 33ab1513d0 chore: update specs 2025-03-13 10:46:55 +00:00
Chirag Aggarwal d422f693f7 feat: add query by role to memberships 2025-03-13 09:48:39 +00:00
shimon d6e53d8e2e Merge branch '1.6.x' of github.com:appwrite/appwrite into updates-projects-regions 2025-03-11 11:17:18 +02:00
Chirag Aggarwal 3f133cab74 Merge branch '1.7.x' into feat-tokens-module 2025-03-06 15:25:42 +00:00
Chirag AggarwalandGitHub 3e9e0652b0 Merge branch '1.6.x' into feat-development-keys 2025-03-05 15:10:13 +05:30
Chirag AggarwalandGitHub 6bc72cf43f Merge branch '1.6.x' into feat-development-keys 2025-03-04 21:28:14 +05:30
shimon 2a5b3317bf update region 2025-03-04 11:36:45 +02:00
shimon 19ad2088a0 update region 2025-03-04 10:08:07 +02:00
Chirag Aggarwal c05ef9121f Merge branch '1.6.x' into feat-development-keys 2025-02-28 12:56:26 +00:00
Chirag Aggarwal f5172f8462 chore: regenerate specs 2025-02-25 12:30:21 +00:00
Chirag AggarwalandGitHub b72b118c07 Merge branch '1.6.x' into feat-development-keys 2025-02-24 13:53:24 +05:30
Chirag Aggarwal 431eea2787 Merge branch '1.6.x' into feat-development-keys 2025-02-21 09:24:04 +00:00
Chirag Aggarwal 46c4c7b28b chore: fix name 2025-02-13 19:36:01 +00:00
Chirag Aggarwal f67d32fd35 chore: updated devkeys test for shared mode 2025-02-13 19:32:33 +00:00
Chirag Aggarwal 392803b5e8 chore: fix merge conflicts 2025-02-13 19:24:00 +00:00
Chirag Aggarwal a0138455bc fix: queueForStats naming 2025-02-13 19:21:15 +00:00
Chirag Aggarwal e59d95a108 Merge branch '1.6.x' into feat-development-keys 2025-02-13 18:25:39 +00:00
Chirag Aggarwal 351afffdfe Merge branch '1.6.x' into feat-development-keys 2025-02-13 17:55:37 +00:00
Chirag Aggarwal d1502bc7d6 chore: update descriptions for token endpoints 2025-02-06 11:08:58 +00:00
Chirag Aggarwal 37dbbf226e chore: fix: descContents handling 2025-02-06 10:42:41 +00:00
Chirag AggarwalandGitHub 142c5731ca Merge branch '1.6.x' into feat-development-keys 2025-02-06 16:01:33 +05:30
Chirag Aggarwal 1d571e470b chore: update module endpoint descriptions 2025-02-06 10:30:00 +00:00
Chirag Aggarwal c269fc22ed chore: remove unnecessary injections 2025-02-06 10:04:03 +00:00
Chirag Aggarwal fd3da47e8a chore: added required perms in migrations 2025-02-06 09:55:32 +00:00
Chirag Aggarwal ba0a6f0097 chore: added requires scopes, fix call method 2025-02-05 14:14:03 +00:00
Chirag Aggarwal 97ed0dc89c chore: fix directory naming 2025-02-05 13:42:19 +00:00
Chirag Aggarwal 4f63c520ec chore: remove extra space 2025-02-05 13:36:34 +00:00
Chirag Aggarwal c7611ed382 chore: refactor file tokens with new project structuring 2025-02-05 13:28:22 +00:00
Chirag Aggarwal 24f11dc8d6 Merge branch '1.6.x' into feat-development-keys 2025-02-05 09:58:45 +00:00
Chirag Aggarwal 4aa3a51ef0 chore: refactor module structure 2025-02-05 09:52:43 +00:00
Chirag Aggarwal ca7cf765b2 chore: refactor tokens 2025-02-05 09:22:35 +00:00
Chirag Aggarwal 92b7b1956f Merge remote-tracking branch 'origin/1.7.x' into feat-tokens-module 2025-02-04 17:00:45 +00:00
Chirag Aggarwal a98f32b5e1 merge with 1.7.x 2025-02-04 16:56:14 +00:00
Chirag Aggarwal cea308ef71 chore: remove confusing comment 2025-02-04 11:55:05 +00:00
Chirag Aggarwal fccc6d5605 chore: added docs for devkeys 2025-02-04 11:45:41 +00:00
Chirag Aggarwal ebd6b1b013 chore: added missing import 2025-02-04 11:32:02 +00:00
Chirag Aggarwal c8afd2c613 Merge branch '1.6.x' into feat-development-keys 2025-02-04 11:21:07 +00:00
Chirag Aggarwal 9420340871 chore: changed directory structure for devkeys 2025-02-04 10:53:15 +00:00
Chirag Aggarwal b4849cd6ca chore: remove id 2025-01-30 14:18:28 +00:00
Chirag Aggarwal 1b91b601bc chore: remove cache rebuild 2025-01-30 14:18:08 +00:00
Chirag Aggarwal 2fa22b4b85 chore: workflow added rebuild on cache miss 2025-01-30 14:05:53 +00:00
Chirag Aggarwal 3522e63404 chore: fix tests 2025-01-30 12:36:28 +00:00
Chirag Aggarwal 67ba9a880d chore: fix tests 2025-01-30 12:25:56 +00:00
Chirag Aggarwal 751f7e3fad chore: shifted abuse project test to different job in ci 2025-01-30 12:11:09 +00:00
Chirag Aggarwal bd801712b9 chore: disabled options abuse env 2025-01-30 11:51:43 +00:00
Chirag Aggarwal 5a1ad4d5ae chore: added grouping of devkeys in ci 2025-01-30 11:48:43 +00:00
Chirag Aggarwal 23111d26c4 chore: filtered out customclienttests 2025-01-30 09:28:23 +00:00
Chirag Aggarwal f132c2b266 chore: changed ordering of tests 2025-01-29 05:52:03 +00:00
Chirag Aggarwal 1e71eb84c4 chore: added devkeys to account and database tests 2025-01-29 04:25:52 +00:00
Chirag Aggarwal 28e1ce9dc2 chore: fix recursive tests 2025-01-28 17:49:05 +00:00
Chirag Aggarwal c73f2afbe1 chore: fix run tests loop 2025-01-28 17:41:48 +00:00
Chirag Aggarwal c2aff2c2cb chore: fix fetching of test files 2025-01-28 17:16:35 +00:00
Chirag Aggarwal c01f67f44f chore: fix parsing of test files 2025-01-28 16:58:27 +00:00
Chirag Aggarwal af7f599525 chore: fix remove base 2025-01-28 16:22:32 +00:00
Chirag Aggarwal acadaf2307 chore: fix naming for tests 2025-01-28 16:13:07 +00:00
Chirag Aggarwal 7bd29501c2 chore: added test_suffixes to outputs 2025-01-28 16:07:41 +00:00
Chirag AggarwalandGitHub eecf3aae68 Merge branch '1.6.x' into feat-development-keys 2025-01-28 20:12:15 +05:30
Chirag Aggarwal 222516dbd4 chore: added base tests in e2e service 2025-01-28 14:41:58 +00:00
Chirag Aggarwal cad18dc7c7 chore: fix abstract implementations for scope tests 2025-01-28 14:29:45 +00:00
Chirag Aggarwal 9561ed99d2 chore: fix getHeaders implementation in scope tests 2025-01-28 14:18:00 +00:00
Chirag Aggarwal b399ff00a6 chore: update e2e tests to use abuse env 2025-01-28 14:06:56 +00:00
Chirag Aggarwal d5e775416d chore: added devkeys collections to new file, and formatting 2025-01-27 10:36:40 +00:00
Chirag Aggarwal f867fddaae Merge branch '1.6.x' into feat-development-keys 2025-01-27 10:33:58 +00:00
Damodar Lohani 195ae3fdcb update project desc 2024-12-15 11:06:46 +00:00
Damodar Lohani cd54ba1b83 fix account test 2024-12-15 10:49:35 +00:00
Damodar Lohani b8388a4092 fix expected in test 2024-12-15 10:41:01 +00:00
Damodar Lohani 05baa6090d fix cycle 2024-12-15 10:31:55 +00:00
Damodar Lohani 6f3c60d462 fix tests 2024-12-15 10:25:22 +00:00
Damodar Lohani 85656f81a5 update db name 2024-12-15 10:03:52 +00:00
Damodar Lohani ba83dd9252 fix dev key creation 2024-12-15 09:33:17 +00:00
Damodar Lohani 3ad865319c refactor: rename endpoint 2024-12-15 09:22:16 +00:00
Damodar Lohani 4ffdc9c103 fix existing test by adding dev key 2024-12-15 09:22:05 +00:00
Damodar Lohani b25772483b key that expires after 5 second 2024-12-15 08:57:44 +00:00
Damodar Lohani ae0e1eb302 fix lint 2024-12-15 08:54:13 +00:00
Damodar Lohani 172ef61663 remove devkey check on error 2024-12-15 08:54:10 +00:00
Damodar Lohani 44f70dad56 Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-12-15 08:51:11 +00:00
Damodar Lohani dcacb5ee2c test fix 2024-12-15 08:45:09 +00:00
Damodar Lohani 5627082165 update 2024-12-08 09:45:40 +00:00
Damodar Lohani 30a079a6b9 fix missing key 2024-12-08 09:07:55 +00:00
Damodar LohaniandGitHub a7122ed535 Merge branch '1.6.x' into feat-development-keys 2024-12-08 14:32:08 +05:45
Damodar Lohani 82d64c8daf fix test 2024-12-08 08:45:03 +00:00
Damodar Lohani 98cf3d4b80 format 2024-12-05 06:19:25 +00:00
Damodar Lohani 7c82ff6491 fix naming 2024-12-05 06:17:17 +00:00
Damodar Lohani e21467d9f0 format 2024-12-05 05:40:52 +00:00
Damodar Lohani 0770748c0f validate file and bucket permission
- validate file update permission when creating file token
2024-12-05 05:40:45 +00:00
Damodar Lohani 285544d2d6 delete token test 2024-12-04 09:39:30 +00:00
Damodar Lohani 11bf99c871 restructure endpoints 2024-12-04 08:25:55 +00:00
Damodar Lohani f21281ebf5 format 2024-12-04 06:02:21 +00:00
Damodar Lohani cb1aff42c5 make 10 requests 2024-12-04 05:59:03 +00:00
Damodar Lohani e7943e8490 update test 2024-12-04 05:57:08 +00:00
Damodar Lohani 136cc5fe46 update put request 2024-12-04 05:45:43 +00:00
Damodar Lohani 01f579151d updated project model 2024-12-04 05:43:15 +00:00
Damodar Lohani ec14cc170f fixing response model 2024-12-04 05:40:09 +00:00
Damodar Lohani e536e6ea74 support dev key from param as well 2024-12-04 05:29:13 +00:00
Damodar Lohani fb0da77d2f add todo 2024-12-04 05:26:52 +00:00
Damodar Lohani 8a59a22c2e update suggested changes 2024-12-04 05:25:16 +00:00
b8917bc811 Update tests/e2e/Services/Projects/ProjectsDevKeys.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2024-12-04 10:58:05 +05:45
8206cee449 Update tests/e2e/Services/Projects/ProjectsDevKeys.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2024-12-04 10:57:49 +05:45
Damodar LohaniandGitHub 5cf4a46555 Merge branch '1.6.x' into feat-development-keys 2024-12-02 16:17:22 +05:45
Damodar Lohani 2c6e5d0bea remove old file 2024-11-28 01:43:21 +00:00
Damodar Lohani fe7851b97f Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-11-28 01:37:25 +00:00
Damodar LohaniandGitHub 27905c2a90 Merge branch '1.6.x' into feat-development-keys 2024-11-25 12:36:10 +05:45
Damodar LohaniandGitHub d07f39c0d2 Merge branch '1.6.x' into feat-development-keys 2024-11-22 15:45:17 +05:45
Damodar Lohani 010ace3b57 update redirect validator 2024-11-22 06:56:36 +00:00
Damodar Lohani b3c2f8a024 disable CORS 2024-11-22 05:55:39 +00:00
Damodar Lohani cc3edd7b2b Refactor naming to Dev keys 2024-11-22 04:21:03 +00:00
Damodar Lohani d32dc0a4d9 tokens test and scopes 2024-11-18 08:52:16 +00:00
Damodar Lohani 0d1fec47c6 tokens test 2024-11-18 08:00:14 +00:00
Damodar Lohani a9da4b7b3b refactor token apis 2024-11-18 07:38:48 +00:00
Damodar Lohani 10dab10cc5 refactor module namings 2024-11-17 07:01:20 +00:00
Damodar Lohani 33aca37c1c Tokens module setup 2024-11-17 06:17:55 +00:00
Damodar Lohani c555a707e6 Merge remote-tracking branch 'origin/1.7.x' into feat-file-tokens 2024-11-17 06:00:03 +00:00
Damodar Lohani 179684e8b2 improve dependency 2024-11-14 04:48:46 +00:00
Damodar Lohani 24353a1077 Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-11-14 04:29:36 +00:00
Khushboo Verma 0b93b2de19 Merge branch '1.6.x' into 1.7.x 2024-11-13 12:51:20 +05:30
Damodar Lohani 8a244708fa Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-10-29 01:23:32 +00:00
Damodar Lohani f2377ce5d2 remove submodule 2024-08-12 08:55:14 +00:00
Damodar Lohani 1771b3fed3 Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-08-12 08:48:43 +00:00
Damodar Lohani 383cff5eb8 enable abuse to test development keys 2024-08-12 08:39:03 +00:00
Damodar Lohani 0a2eee0118 detailed error logs if development key is provided 2024-08-12 05:44:52 +00:00
Damodar Lohani 61c5848be4 refactor development keys 2024-08-12 05:34:25 +00:00
Damodar LohaniandGitHub d7b19a8b52 Merge branch '1.6.x' into feat-development-keys 2024-08-06 08:23:51 +05:45
Damodar Lohani d9556ba603 make expiry date required 2024-07-29 10:18:06 +00:00
Damodar Lohani 55fc9d7fbd tests and fixes 2024-07-29 10:12:57 +00:00
Damodar Lohani ca0c38b3c0 subquery for development keys 2024-07-29 10:12:50 +00:00
Damodar Lohani fe26c82dc1 Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-07-29 09:32:58 +00:00
Damodar Lohani 681e382459 Merge remote-tracking branch 'origin/1.6.x' into feat-development-keys 2024-07-16 08:34:38 +00:00
Damodar Lohani ae5a60db89 composer update 2024-07-16 08:33:38 +00:00
Damodar Lohani daf208fe35 Merge remote-tracking branch 'origin/main' into feat-development-keys 2024-07-16 08:32:53 +00:00
Damodar Lohani 760c552ffb support for api test keys 2024-07-16 08:28:22 +00:00
Damodar Lohani 03000c3ad0 add collection for development keys 2024-07-16 07:50:42 +00:00
Damodar Lohani af3dc25e2c add new endpoints to module 2024-07-16 07:48:21 +00:00
Damodar Lohani c058d30d0a all endpoints for development keys 2024-07-16 05:20:56 +00:00
Damodar Lohani bcde2ea223 remove duplicates 2024-07-10 07:32:57 +00:00
Damodar Lohani c21402733f development keys module setup 2024-07-10 07:16:45 +00:00
Damodar Lohani 0dbc37dacf renames and fixes 2024-06-30 08:53:21 +00:00
Damodar Lohani 8f667671ad Merge remote-tracking branch 'origin/main' into feat-file-tokens 2024-06-30 08:45:24 +00:00
Damodar Lohani 61a8457232 format 2024-06-30 08:42:05 +00:00
Damodar Lohani c20504fc7d missing import 2024-06-30 08:40:35 +00:00
Damodar LohaniandGitHub 74a293d425 Merge branch 'main' into feat-file-tokens 2024-06-20 15:43:38 +05:45
Damodar Lohani 52d27179a9 fix jwt response 2024-03-17 03:01:55 +00:00
Damodar Lohani c6d524c25d fix formatting 2024-03-17 02:08:22 +00:00
Damodar Lohani 8d67498e52 Merge remote-tracking branch 'origin/main' into feat-file-tokens 2024-03-17 01:59:07 +00:00
Damodar Lohani 852137b84d update token test 2024-03-17 01:53:08 +00:00
Damodar Lohani b752d29854 basic test and fix response model 2024-01-04 07:27:06 +00:00
Damodar Lohani fa40a33631 fixes and refactor 2024-01-04 06:53:22 +00:00
Damodar Lohani 1065abb0a7 update preview to use token 2024-01-04 04:57:10 +00:00
Damodar Lohani 56087b691b verify and inject resource token 2024-01-04 03:03:07 +00:00
Damodar Lohani c1c98e4ac8 improve API to new data structure and supprot JWT 2024-01-04 02:46:52 +00:00
Damodar Lohani fa09a69a7f Merge remote-tracking branch 'origin/main' into feat-file-tokens 2024-01-04 02:23:50 +00:00
Damodar Lohani a28312be46 refactor collections 2024-01-04 02:23:08 +00:00
Damodar Lohani eb1562f56b rename param to expiry for consistency 2023-12-28 10:48:42 +00:00
Damodar Lohani 324f65c838 token response model 2023-12-27 02:21:53 +00:00
Damodar Lohani b23369c548 improve token endpoints 2023-12-27 02:15:59 +00:00
Damodar Lohani 23d0aae23b improve get file token 2023-12-27 00:03:16 +00:00
Damodar Lohani 92c2e26f3a improve list file tokens 2023-12-26 23:59:41 +00:00
Damodar Lohani 9ccdabb8e9 improve collection config 2023-12-26 23:59:31 +00:00
Damodar Lohani 2e39fbe70f improve file token create 2023-12-26 23:52:20 +00:00
Damodar Lohani bfa941d69c WIP: file tokens endpoint 2023-12-25 07:09:35 +00:00
Damodar Lohani 07ca18caba file tokens collection 2023-12-25 05:28:32 +00:00
270 changed files with 181188 additions and 2868 deletions
+11
View File
@@ -0,0 +1,11 @@
reviews:
path_filters:
- "!app/config/specs/**"
- "!docs/examples/**"
- "!docs/references/**"
- "!docs/sdks/**"
auto_review:
base_branches:
- main
- 1.6.x
- 1.7.x
+8 -4
View File
@@ -18,12 +18,14 @@ _APP_SYSTEM_RESPONSE_FORMAT=
_APP_OPTIONS_ABUSE=disabled
_APP_OPTIONS_ROUTER_PROTECTION=disabled
_APP_OPTIONS_FORCE_HTTPS=disabled
_APP_OPTIONS_COMPUTE_FORCE_HTTPS=disabled
_APP_OPTIONS_ROUTER_FORCE_HTTPS=disabled
_APP_OPENSSL_KEY_V1=your-secret-key
_APP_DOMAIN=traefik
_APP_DOMAIN_FUNCTIONS=functions.localhost
_APP_DOMAIN_SITES=sites.localhost
_APP_DOMAIN_TARGET=test.appwrite.io
_APP_DOMAIN_TARGET_CNAME=test.appwrite.io
_APP_DOMAIN_TARGET_A=127.0.0.1
_APP_DOMAIN_TARGET_AAAA=::1
_APP_RULES_FORMAT=md5
_APP_REDIS_HOST=redis
_APP_REDIS_PORT=6379
@@ -71,7 +73,8 @@ _APP_SMS_PROJECTS_DENY_LIST=
_APP_STORAGE_LIMIT=30000000
_APP_STORAGE_PREVIEW_LIMIT=20000000
_APP_COMPUTE_SIZE_LIMIT=30000000
_APP_COMPUTE_TIMEOUT=900
_APP_FUNCTIONS_TIMEOUT=900
_APP_SITES_TIMEOUT=30
_APP_COMPUTE_BUILD_TIMEOUT=900
_APP_COMPUTE_CPUS=8
_APP_COMPUTE_MEMORY=8192
@@ -88,8 +91,9 @@ _APP_MAINTENANCE_RETENTION_CACHE=2592000
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
_APP_MAINTENANCE_RETENTION_ABUSE=86400
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE=15778800
_APP_USAGE_AGGREGATION_INTERVAL=30
_APP_STATS_RESOURCES_INTERVAL=3600
_APP_STATS_RESOURCES_INTERVAL=30
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
_APP_USAGE_STATS=enabled
+120
View File
@@ -0,0 +1,120 @@
name: Benchmark
concurrency:
group: '${{ github.workflow }}-${{ github.ref }}'
cancel-in-progress: true
env:
IMAGE: appwrite-dev
CACHE_KEY: 'appwrite-dev-${{ github.event.pull_request.head.sha }}'
'on':
- pull_request
jobs:
setup:
name: Setup & Build Appwrite Image
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Appwrite
uses: docker/build-push-action@v6
with:
context: .
push: false
tags: '${{ env.IMAGE }}'
load: true
cache-from: type=gha
cache-to: 'type=gha,mode=max'
outputs: 'type=docker,dest=/tmp/${{ env.IMAGE }}.tar'
build-args: |
DEBUG=false
TESTING=true
VERSION=dev
- name: Cache Docker Image
uses: actions/cache@v4
with:
key: '${{ env.CACHE_KEY }}'
path: '/tmp/${{ env.IMAGE }}.tar'
benchmarking:
name: Benchmark
runs-on: ubuntu-latest
needs: setup
permissions:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Load Cache
uses: actions/cache@v4
with:
key: '${{ env.CACHE_KEY }}'
path: '/tmp/${{ env.IMAGE }}.tar'
fail-on-cache-miss: true
- name: Load and Start Appwrite
run: |
sed -i 's/traefik/localhost/g' .env
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
sleep 10
- name: Install Oha
run: |
echo "deb [signed-by=/usr/share/keyrings/azlux-archive-keyring.gpg] http://packages.azlux.fr/debian/ stable main" | sudo tee /etc/apt/sources.list.d/azlux.list
sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg https://azlux.fr/repo.gpg
sudo apt update
sudo apt install oha
- name: Benchmark PR
run: 'oha -z 180s http://localhost/v1/health/version -j > benchmark.json'
- name: Cleaning
run: docker compose down -v
- name: Installing latest version
run: |
rm docker-compose.yml
rm .env
curl https://appwrite.io/install/compose -o docker-compose.yml
curl https://appwrite.io/install/env -o .env
sed -i 's/_APP_OPTIONS_ABUSE=enabled/_APP_OPTIONS_ABUSE=disabled/g' .env
docker compose up -d
sleep 10
- name: Benchmark Latest
run: oha -z 180s http://localhost/v1/health/version -j > benchmark-latest.json
- name: Prepare comment
run: |
echo '## :sparkles: Benchmark results' > benchmark.txt
echo ' ' >> benchmark.txt
echo "- Requests per second: $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
echo "- Requests with 200 status code: $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
echo "- P99 latency: $(jq -r '.latencyPercentiles.p99' benchmark.json )" >> benchmark.txt
echo " " >> benchmark.txt
echo " " >> benchmark.txt
echo "## :zap: Benchmark Comparison" >> benchmark.txt
echo " " >> benchmark.txt
echo "| Metric | This PR | Latest version | " >> benchmark.txt
echo "| --- | --- | --- | " >> benchmark.txt
echo "| RPS | $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.summary.requestsPerSec|tonumber|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
echo "| 200 | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
echo "| P99 | $(jq -r '.latencyPercentiles.p99' benchmark.json ) | $(jq -r '.latencyPercentiles.p99' benchmark-latest.json ) | " >> benchmark.txt
- name: Save results
uses: actions/upload-artifact@v4
if: '${{ !cancelled() }}'
with:
name: benchmark.json
path: benchmark.json
retention-days: 7
- name: Find Comment
if: github.event.pull_request.head.repo.full_name == github.repository
uses: peter-evans/find-comment@v3
id: fc
with:
issue-number: '${{ github.event.pull_request.number }}'
comment-author: 'github-actions[bot]'
body-includes: Benchmark results
- name: Comment on PR
if: github.event.pull_request.head.repo.full_name == github.repository
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: '${{ steps.fc.outputs.comment-id }}'
issue-number: '${{ github.event.pull_request.number }}'
body-path: benchmark.txt
edit-mode: replace
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Cleanup
run: |
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
submodules: recursive
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
steps:
- name: Check out the repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Run CodeQL
run: |
+68 -67
View File
@@ -197,7 +197,7 @@ jobs:
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude=devKeys
e2e_shared_mode_test:
name: E2E Shared Mode Service Test
@@ -228,7 +228,8 @@ jobs:
Webhooks,
VCS,
Messaging,
Migrations
Migrations,
Tokens
]
tables-mode: [
'Shared V1',
@@ -275,86 +276,86 @@ jobs:
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude=devKeys
benchmarking:
name: Benchmark
e2e_dev_keys:
name: E2E Service Test (Dev Keys)
runs-on: ubuntu-latest
needs: setup
permissions:
pull-requests: write
strategy:
fail-fast: false
steps:
- name: Checkout repository
- name: checkout
uses: actions/checkout@v4
- name: Load Cache
uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
fail-on-cache-miss: true
- name: Load and Start Appwrite
run: |
sed -i 's/traefik/localhost/g' .env
docker load --input /tmp/${{ env.IMAGE }}.tar
docker load --input /tmp/${{ env.IMAGE }}.tar
sed -i 's/_APP_OPTIONS_ABUSE=disabled/_APP_OPTIONS_ABUSE=enabled/' .env
docker compose up -d
sleep 10
- name: Install Oha
sleep 30
- name: Run Projects tests with dev keys in ${{ matrix.tables-mode }} table mode
run: |
echo "deb [signed-by=/usr/share/keyrings/azlux-archive-keyring.gpg] http://packages.azlux.fr/debian/ stable main" | sudo tee /etc/apt/sources.list.d/azlux.list
sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg https://azlux.fr/repo.gpg
sudo apt update
sudo apt install oha
- name: Benchmark PR
run: oha -z 180s http://localhost/v1/health/version -j > benchmark.json
- name: Cleaning
run: docker compose down -v
- name: Installing latest version
echo "Using project tables"
export _APP_DATABASE_SHARED_TABLES=
export _APP_DATABASE_SHARED_TABLES_V1=
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys
e2e_dev_keys_shared_mode:
name: E2E Shared Mode Service Test (Dev Keys)
runs-on: ubuntu-latest
needs: [ setup, check_database_changes ]
if: needs.check_database_changes.outputs.database_changed == 'true'
strategy:
fail-fast: false
matrix:
tables-mode: [
'Shared V1',
'Shared V2',
]
steps:
- name: checkout
uses: actions/checkout@v4
- name: Load Cache
uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
fail-on-cache-miss: true
- name: Load and Start Appwrite
run: |
rm docker-compose.yml
rm .env
curl https://appwrite.io/install/compose -o docker-compose.yml
curl https://appwrite.io/install/env -o .env
sed -i 's/_APP_OPTIONS_ABUSE=enabled/_APP_OPTIONS_ABUSE=disabled/g' .env
docker load --input /tmp/${{ env.IMAGE }}.tar
sed -i 's/_APP_OPTIONS_ABUSE=disabled/_APP_OPTIONS_ABUSE=enabled/' .env
docker compose up -d
sleep 10
- name: Benchmark Latest
run: oha -z 180s http://localhost/v1/health/version -j > benchmark-latest.json
- name: Prepare comment
sleep 30
- name: Run Projects tests with dev keys in ${{ matrix.tables-mode }} table mode
run: |
echo '## :sparkles: Benchmark results' > benchmark.txt
echo ' ' >> benchmark.txt
echo "- Requests per second: $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
echo "- Requests with 200 status code: $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
echo "- P99 latency: $(jq -r '.latencyPercentiles.p99' benchmark.json )" >> benchmark.txt
echo " " >> benchmark.txt
echo " " >> benchmark.txt
echo "## :zap: Benchmark Comparison" >> benchmark.txt
echo " " >> benchmark.txt
echo "| Metric | This PR | Latest version | " >> benchmark.txt
echo "| --- | --- | --- | " >> benchmark.txt
echo "| RPS | $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.summary.requestsPerSec|tonumber|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
echo "| 200 | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
echo "| P99 | $(jq -r '.latencyPercentiles.p99' benchmark.json ) | $(jq -r '.latencyPercentiles.p99' benchmark-latest.json ) | " >> benchmark.txt
- name: Save results
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: benchmark.json
path: benchmark.json
retention-days: 7
- name: Find Comment
if: github.event.pull_request.head.repo.full_name == github.repository
uses: peter-evans/find-comment@v3
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Benchmark results
- name: Comment on PR
if: github.event.pull_request.head.repo.full_name == github.repository
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: benchmark.txt
edit-mode: replace
if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then
echo "Using shared tables V1"
export _APP_DATABASE_SHARED_TABLES=database_db_main
export _APP_DATABASE_SHARED_TABLES_V1=database_db_main
elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then
echo "Using shared tables V2"
export _APP_DATABASE_SHARED_TABLES=database_db_main
export _APP_DATABASE_SHARED_TABLES_V1=
fi
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys
+1 -8
View File
@@ -7,6 +7,7 @@ tasks:
docker pull composer
command: |
docker run --rm --interactive --tty \
--user "$(id -u):$(id -g)" \
--volume $PWD:/app \
composer install \
--ignore-platform-reqs \
@@ -23,11 +24,3 @@ vscode:
extensions:
- ms-azuretools.vscode-docker
- zobo.php-intellisense
github:
# https://www.gitpod.io/docs/prebuilds#github-specific-configuration
prebuilds:
# enable for pull requests coming from forks (defaults to false)
pullRequestsFromForks: true
# add a check to pull requests (defaults to true)
addCheck: false
+2
View File
@@ -44,12 +44,14 @@ COPY ./dev /usr/src/code/dev
# Set Volumes
RUN mkdir -p /storage/uploads && \
mkdir -p /storage/imports && \
mkdir -p /storage/cache && \
mkdir -p /storage/config && \
mkdir -p /storage/certificates && \
mkdir -p /storage/functions && \
mkdir -p /storage/debug && \
chown -Rf www-data.www-data /storage/uploads && chmod -Rf 0755 /storage/uploads && \
chown -Rf www-data.www-data /storage/imports && chmod -Rf 0755 /storage/imports && \
chown -Rf www-data.www-data /storage/cache && chmod -Rf 0755 /storage/cache && \
chown -Rf www-data.www-data /storage/config && chmod -Rf 0755 /storage/config && \
chown -Rf www-data.www-data /storage/certificates && chmod -Rf 0755 /storage/certificates && \
+3
View File
@@ -9,6 +9,7 @@ use Appwrite\Event\StatsResources;
use Appwrite\Event\StatsUsage;
use Appwrite\Platform\Appwrite;
use Appwrite\Runtimes\Runtimes;
use Executor\Executor;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\CLI\CLI;
@@ -255,6 +256,8 @@ CLI::setResource('logError', function (Registry $register) {
};
}, ['register']);
CLI::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
$platform = new Appwrite();
$platform->init(Service::TYPE_TASK);
+10 -3
View File
@@ -1038,7 +1038,7 @@ return [
'$id' => ID::custom('providerUid'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'size' => 2048, // Decrease to 128 as in index length?
'signed' => true,
'required' => false,
'default' => null,
@@ -1107,14 +1107,14 @@ return [
'$id' => ID::custom('_key_userInternalId_provider_providerUid'),
'type' => Database::INDEX_UNIQUE,
'attributes' => ['userInternalId', 'provider', 'providerUid'],
'lengths' => [11, 128, 128],
'lengths' => [11, 128, 128], // providerUid is length 2000!
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_provider_providerUid'),
'type' => Database::INDEX_UNIQUE,
'attributes' => ['provider', 'providerUid'],
'lengths' => [128, 128],
'lengths' => [128, 128], // providerUid is length 2000!
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
],
[
@@ -1417,6 +1417,13 @@ return [
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_roles'),
'type' => Database::INDEX_KEY,
'attributes' => ['roles'],
'lengths' => [128],
'orders' => [],
],
],
],
+130
View File
@@ -287,6 +287,17 @@ return [
'array' => false,
'filters' => ['subQueryKeys'],
],
[
'$id' => ID::custom('devKeys'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['subQueryDevKeys'],
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
@@ -689,6 +700,125 @@ return [
],
],
'devKeys' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('devKeys'),
'name' => 'Dev keys',
'attributes' => [
[
'$id' => ID::custom('projectInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('projectId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => 0,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('name'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('secret'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 512, // var_dump of \bin2hex(\random_bytes(128)) => string(256) doubling for encryption
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => ['encrypt'],
],
[
'$id' => ID::custom('expire'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('accessedAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('sdks'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
],
'indexes' => [
[
'$id' => ID::custom('_key_project'),
'type' => Database::INDEX_KEY,
'attributes' => ['projectInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_accessedAt',
'type' => Database::INDEX_KEY,
'attributes' => ['accessedAt'],
'lengths' => [],
'orders' => [],
],
[
'$id' => ID::custom('_key_search'),
'type' => Database::INDEX_FULLTEXT,
'attributes' => ['search'],
'lengths' => [],
'orders' => [],
],
],
],
'webhooks' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('webhooks'),
+297 -12
View File
@@ -579,6 +579,61 @@ return [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentCreatedAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('latestDeploymentId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('latestDeploymentInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('latestDeploymentCreatedAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('latestDeploymentStatus'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('vars'),
'type' => Database::VAR_STRING,
@@ -916,16 +971,16 @@ return [
'default' => false,
'array' => false,
],
// [
// '$id' => ID::custom('logging'),
// 'type' => Database::VAR_BOOLEAN,
// 'signed' => true,
// 'size' => 0,
// 'format' => '',
// 'filters' => [],
// 'required' => true,
// 'array' => false,
// ],
[
'$id' => ID::custom('logging'),
'type' => Database::VAR_BOOLEAN,
'signed' => true,
'size' => 0,
'format' => '',
'filters' => [],
'required' => true,
'array' => false,
],
[
'$id' => ID::custom('framework'),
'type' => Database::VAR_STRING,
@@ -1003,6 +1058,83 @@ return [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentCreatedAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('deploymentScreenshotLight'), // File ID from 'screenshots' Console bucket
'type' => Database::VAR_STRING,
'format' => '',
'size' => 32,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentScreenshotDark'), // File ID from 'screenshots' Console bucket
'type' => Database::VAR_STRING,
'format' => '',
'size' => 32,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('latestDeploymentId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('latestDeploymentInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('latestDeploymentCreatedAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('latestDeploymentStatus'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('vars'),
'type' => Database::VAR_STRING,
@@ -1070,7 +1202,7 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('adapter'), // ssr or static
'$id' => ID::custom('adapter'), // ssr or static; named this way as it's a term in SSR frameworks
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
@@ -1550,6 +1682,17 @@ return [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('totalSize'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('status'),
'type' => Database::VAR_STRING,
@@ -1582,6 +1725,28 @@ return [
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('adapter'), // ssr or static; named this way as it's a term in SSR frameworks
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('fallbackFile'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
]
],
'indexes' => [
@@ -1620,6 +1785,13 @@ return [
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_totalSize'),
'type' => Database::INDEX_KEY,
'attributes' => ['totalSize'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_buildDuration'),
'type' => Database::INDEX_KEY,
@@ -2103,6 +2275,17 @@ return [
'array' => false,
'filters' => ['json', 'encrypt'],
],
[
'$id' => ID::custom('options'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 65536,
'signed' => true,
'required' => false,
'default' => [],
'array' => false,
'filters' => ['json'],
],
[
'$id' => ID::custom('resources'),
'type' => Database::VAR_STRING,
@@ -2157,7 +2340,29 @@ return [
'default' => null,
'array' => false,
'filters' => [],
]
],
[
'$id' => ID::custom('resourceId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('resourceType'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
],
'indexes' => [
[
@@ -2181,6 +2386,13 @@ return [
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_resource_id',
'type' => Database::INDEX_KEY,
'attributes' => ['resourceId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_DESC],
],
[
'$id' => ID::custom('_fulltext_search'),
'type' => Database::INDEX_FULLTEXT,
@@ -2190,4 +2402,77 @@ return [
]
],
],
'resourceTokens' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('resourceTokens'),
'name' => 'Resource Tokens',
'attributes' => [
[
'$id' => ID::custom('resourceId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('resourceInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('resourceType'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 100,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('secret'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 512,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => ['encrypt'],
],
[
'$id' => ID::custom('expire'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 255,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
]
],
'indexes' => [
[
'$id' => '_key_expiry_date',
'type' => Database::INDEX_KEY,
'attributes' => ['expire'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
],
],
];
+28 -1
View File
@@ -488,6 +488,18 @@ return [
'code' => 403,
],
/** Tokens */
Exception::TOKEN_NOT_FOUND => [
'name' => Exception::TOKEN_NOT_FOUND,
'description' => 'The requested file token could not be found.',
'code' => 404,
],
Exception::TOKEN_EXPIRED => [
'name' => Exception::TOKEN_EXPIRED,
'description' => 'The requested file token has expired.',
'code' => 401,
],
/** VCS */
Exception::INSTALLATION_NOT_FOUND => [
'name' => Exception::INSTALLATION_NOT_FOUND,
@@ -546,6 +558,11 @@ return [
'description' => 'Function runtime could not be detected.',
'code' => 400,
],
Exception::FUNCTION_EXECUTE_PERMISSION_MISSING => [
'name' => Exception::FUNCTION_EXECUTE_PERMISSION_MISSING,
'description' => 'To execute function using domain, execute permissions must include "any" or "guests".',
'code' => 401,
],
/** Sites */
Exception::SITE_NOT_FOUND => [
@@ -580,6 +597,16 @@ return [
'description' => 'Build with the requested ID is already completed and cannot be canceled.',
'code' => 400,
],
Exception::BUILD_CANCELED => [
'name' => Exception::BUILD_CANCELED,
'description' => 'Build with the requested ID has been canceled.',
'code' => 400,
],
Exception::BUILD_FAILED => [
'name' => Exception::BUILD_FAILED,
'description' => 'Build with the requested ID failed. Please check the logs for more information.',
'code' => 400,
],
/** Deployments */
Exception::DEPLOYMENT_NOT_FOUND => [
@@ -832,7 +859,7 @@ return [
Exception::RULE_VERIFICATION_FAILED => [
'name' => Exception::RULE_VERIFICATION_FAILED,
'description' => 'Domain verification failed. Please check if your DNS records are correct and try again.',
'code' => 401,
'code' => 400,
'publish' => true
],
Exception::PROJECT_SMTP_CONFIG_INVALID => [
+55 -26
View File
@@ -19,9 +19,10 @@ return [
'analog' => [
'key' => 'analog',
'name' => 'Analog',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/analog/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/analog/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/analog/env.sh',
'adapters' => [
'ssr' => [
@@ -29,14 +30,14 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/analog',
'startCommand' => 'sh helpers/analog/server.sh',
'startCommand' => 'bash helpers/analog/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/analog/public',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
'fallbackFile' => 'index.html'
]
]
@@ -44,9 +45,10 @@ return [
'angular' => [
'key' => 'angular',
'name' => 'Angular',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/angular/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/angular/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/angular/env.sh',
'adapters' => [
'ssr' => [
@@ -54,14 +56,14 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/angular',
'startCommand' => 'sh helpers/angular/server.sh',
'startCommand' => 'bash helpers/angular/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/angular/browser',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
'fallbackFile' => 'index.csr.html'
]
]
@@ -69,9 +71,10 @@ return [
'nextjs' => [
'key' => 'nextjs',
'name' => 'Next.js',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/next-js/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/next-js/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/next-js/env.sh',
'adapters' => [
'ssr' => [
@@ -79,20 +82,21 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './.next',
'startCommand' => 'sh helpers/next-js/server.sh',
'startCommand' => 'bash helpers/next-js/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './out',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
]
]
],
'react' => [
'key' => 'react',
'name' => 'React',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
@@ -101,7 +105,7 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
'fallbackFile' => 'index.html'
]
]
@@ -109,9 +113,10 @@ return [
'nuxt' => [
'key' => 'nuxt',
'name' => 'Nuxt',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/nuxt/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/nuxt/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/nuxt/env.sh',
'adapters' => [
'ssr' => [
@@ -119,20 +124,21 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './.output',
'startCommand' => 'sh helpers/nuxt/server.sh',
'startCommand' => 'bash helpers/nuxt/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run generate',
'installCommand' => 'npm install',
'outputDirectory' => './output/public',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
]
]
],
'vue' => [
'key' => 'vue',
'name' => 'Vue.js',
'screenshotSleep' => 5000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
@@ -141,7 +147,7 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
'fallbackFile' => 'index.html'
]
]
@@ -149,9 +155,10 @@ return [
'sveltekit' => [
'key' => 'sveltekit',
'name' => 'SvelteKit',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/sveltekit/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/sveltekit/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/sveltekit/env.sh',
'adapters' => [
'ssr' => [
@@ -159,23 +166,24 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/sveltekit/server.sh',
'startCommand' => 'bash helpers/sveltekit/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
]
]
],
'astro' => [
'key' => 'astro',
'name' => 'Astro',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/astro/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/astro/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/astro/env.sh',
'adapters' => [
'ssr' => [
@@ -183,23 +191,24 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/astro/server.sh',
'startCommand' => 'bash helpers/astro/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
]
]
],
'remix' => [
'key' => 'remix',
'name' => 'Remix',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/remix/bundle.sh',
'bundleCommand' => 'bash /usr/local/server/helpers/remix/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/remix/env.sh',
'adapters' => [
'ssr' => [
@@ -207,20 +216,38 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/remix/server.sh',
'startCommand' => 'bash helpers/remix/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './build/client',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
]
]
],
'lynx' => [
'key' => 'lynx',
'name' => 'Lynx',
'screenshotSleep' => 5000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'bash helpers/server.sh',
'fallbackFile' => 'index.html'
]
]
],
'flutter' => [
'key' => 'flutter',
'name' => 'Flutter',
'screenshotSleep' => 5000,
'buildRuntime' => 'flutter-3.29',
'runtimes' => getVersions($templateRuntimes['FLUTTER']['versions'], 'flutter'),
'adapters' => [
@@ -229,13 +256,14 @@ return [
'buildCommand' => 'flutter build web',
'installCommand' => '',
'outputDirectory' => './build/web',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
],
],
],
'vite' => [
'key' => 'vite',
'name' => 'Vite',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
@@ -244,13 +272,14 @@ return [
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
],
]
],
'other' => [
'key' => 'other',
'name' => 'Other',
'screenshotSleep' => 3000,
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
@@ -259,7 +288,7 @@ return [
'buildCommand' => '',
'installCommand' => '',
'outputDirectory' => './',
'startCommand' => 'sh helpers/server.sh',
'startCommand' => 'bash helpers/server.sh',
],
]
],
+1 -65
View File
@@ -3,72 +3,8 @@
return [
'default' => [
'$id' => 'default',
'name' => 'Frankfurt',
'name' => 'default',
'disabled' => false,
'flag' => 'de',
'default' => true,
],
'fra' => [
'$id' => 'fra',
'name' => 'Frankfurt',
'disabled' => false,
'flag' => 'de',
'default' => true,
],
'nyc' => [
'$id' => 'nyc',
'name' => 'New York',
'disabled' => true,
'flag' => 'us',
'default' => true,
],
'sfo' => [
'$id' => 'sfo',
'name' => 'San Francisco',
'disabled' => true,
'flag' => 'us',
'default' => true,
],
'blr' => [
'$id' => 'blr',
'name' => 'Bengaluru',
'disabled' => true,
'flag' => 'in',
'default' => true,
],
'lon' => [
'$id' => 'lon',
'name' => 'London',
'disabled' => true,
'flag' => 'gb',
'default' => true,
],
'ams' => [
'$id' => 'ams',
'name' => 'Amsterdam',
'disabled' => true,
'flag' => 'nl',
'default' => true,
],
'sgp' => [
'$id' => 'sgp',
'name' => 'Singapore',
'disabled' => true,
'flag' => 'sg',
'default' => true,
],
'tor' => [
'$id' => 'tor',
'name' => 'Toronto',
'disabled' => true,
'flag' => 'ca',
'default' => true,
],
'syd' => [
'$id' => 'syd',
'name' => 'Sydney',
'disabled' => true,
'flag' => 'au',
'default' => true,
],
];
+2
View File
@@ -81,6 +81,8 @@ $admins = [
'topics.read',
'subscribers.write',
'subscribers.read',
'tokens.read',
'tokens.write',
];
return [
+6
View File
@@ -142,4 +142,10 @@ return [ // List of publicly visible scopes
'assistant.read' => [
'description' => 'Access to read the Assistant service',
],
'tokens.read' => [
'description' => 'Access to read your project\'s tokens',
],
'tokens.write' => [
'description' => 'Access to create, update, and delete your project\'s tokens',
],
];
+1 -1
View File
@@ -184,7 +184,7 @@ return [
'docsUrl' => 'https://appwrite.io/docs/sites',
'tests' => false,
'optional' => true,
'icon' => '', // TODO: Update icon later
'icon' => '/images/services/sites.png',
],
'functions' => [
'key' => 'functions',
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+522 -9
View File
@@ -4748,7 +4748,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a list of all the current user function execution logs. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Executions List",
@@ -4763,7 +4763,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 383,
"weight": 389,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4822,7 +4822,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"responses": {
"201": {
"description": "Execution",
@@ -4837,7 +4837,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 381,
"weight": 387,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4936,7 +4936,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a function execution log by its unique ID.",
"responses": {
"200": {
"description": "Execution",
@@ -4951,7 +4951,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 382,
"weight": 388,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5534,7 +5534,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 348,
"weight": 349,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5616,7 +5616,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 352,
"weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6848,7 +6848,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"schema": {
"type": "array",
@@ -7448,6 +7448,451 @@
}
}
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceTokenList"
}
}
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"schema": {
"type": "string",
"default": []
},
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"schema": {
"type": "string",
"x-example": "<BUCKET_ID>"
},
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<FILE_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/resourceToken"
}
}
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/jwt"
}
}
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<TOKEN_ID>"
},
"in": "path"
}
]
}
}
},
"tags": [
@@ -7698,6 +8143,30 @@
"files"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"$ref": "#\/components\/schemas\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@@ -8894,6 +9363,50 @@
"chunksUploaded"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+523 -9
View File
@@ -4918,7 +4918,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a list of all the current user function execution logs. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Executions List",
@@ -4929,7 +4929,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 383,
"weight": 389,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4991,7 +4991,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"responses": {
"201": {
"description": "Execution",
@@ -5002,7 +5002,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 381,
"weight": 387,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5109,7 +5109,7 @@
"tags": [
"functions"
],
"description": "",
"description": "Get a function execution log by its unique ID.",
"responses": {
"200": {
"description": "Execution",
@@ -5120,7 +5120,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 382,
"weight": 388,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5761,7 +5761,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 348,
"weight": 349,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5845,7 +5845,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 352,
"weight": 353,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7060,7 +7060,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"type": "array",
"collectionFormat": "multi",
@@ -7653,6 +7653,451 @@
}
]
}
},
"\/tokens\/buckets\/{bucketId}\/files\/{fileId}": {
"get": {
"summary": "List tokens",
"operationId": "tokensList",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"responses": {
"200": {
"description": "Resource Tokens List",
"schema": {
"$ref": "#\/definitions\/resourceTokenList"
}
}
},
"x-appwrite": {
"method": "list",
"weight": 432,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/list.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
}
]
},
"post": {
"summary": "Create file token",
"operationId": "tokensCreateFileToken",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Create a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"responses": {
"201": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "createFileToken",
"weight": 429,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/create-file-token.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "bucketId",
"description": "Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https:\/\/appwrite.io\/docs\/server\/storage#createBucket).",
"required": true,
"type": "string",
"x-example": "<BUCKET_ID>",
"in": "path"
},
{
"name": "fileId",
"description": "File unique ID.",
"required": true,
"type": "string",
"x-example": "<FILE_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "Token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": [],
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
}
},
"\/tokens\/{tokenId}": {
"get": {
"summary": "Get token",
"operationId": "tokensGet",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a token by its unique ID.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "get",
"weight": 430,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
},
"patch": {
"summary": "Update token",
"operationId": "tokensUpdate",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Update a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"responses": {
"200": {
"description": "ResourceToken",
"schema": {
"$ref": "#\/definitions\/resourceToken"
}
}
},
"x-appwrite": {
"method": "update",
"weight": 433,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/update.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token unique ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"expire": {
"type": "string",
"description": "File token expiry date",
"default": null,
"x-example": null,
"x-nullable": true
},
"permissions": {
"type": "array",
"description": "An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
}
}
}
]
},
"delete": {
"summary": "Delete token",
"operationId": "tokensDelete",
"consumes": [
"application\/json"
],
"produces": [],
"tags": [
"tokens"
],
"description": "Delete a token by its unique ID.",
"responses": {
"204": {
"description": "No content"
}
},
"x-appwrite": {
"method": "delete",
"weight": 434,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/delete.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.",
"rate-limit": 60,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "tokens.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "Token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
},
"\/tokens\/{tokenId}\/jwt": {
"get": {
"summary": "Get token as JWT",
"operationId": "tokensGetJWT",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"tokens"
],
"description": "Get a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"responses": {
"200": {
"description": "JWT",
"schema": {
"$ref": "#\/definitions\/jwt"
}
}
},
"x-appwrite": {
"method": "getJWT",
"weight": 431,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "tokens\/get-j-w-t.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "tokens.read",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "tokenId",
"description": "File token ID.",
"required": true,
"type": "string",
"x-example": "<TOKEN_ID>",
"in": "path"
}
]
}
}
},
"tags": [
@@ -7875,6 +8320,31 @@
"files"
]
},
"resourceTokenList": {
"description": "Resource Tokens List",
"type": "object",
"properties": {
"total": {
"type": "integer",
"description": "Total number of tokens documents that matched your query.",
"x-example": 5,
"format": "int32"
},
"tokens": {
"type": "array",
"description": "List of tokens.",
"items": {
"type": "object",
"$ref": "#\/definitions\/resourceToken"
},
"x-example": ""
}
},
"required": [
"total",
"tokens"
]
},
"teamList": {
"description": "Teams List",
"type": "object",
@@ -9082,6 +9552,50 @@
"chunksUploaded"
]
},
"resourceToken": {
"description": "ResourceToken",
"type": "object",
"properties": {
"$id": {
"type": "string",
"description": "Token ID.",
"x-example": "bb8ea5c16897e"
},
"$createdAt": {
"type": "string",
"description": "Token creation date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
},
"resourceId": {
"type": "string",
"description": "Resource ID.",
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
},
"resourceInternalId": {
"type": "string",
"description": "File ID.",
"x-example": "1:1"
},
"resourceType": {
"type": "string",
"description": "Resource type.",
"x-example": "file"
},
"expire": {
"type": "string",
"description": "Token expiration date in ISO 8601 format.",
"x-example": "2020-10-15T06:38:00.000+00:00"
}
},
"required": [
"$id",
"$createdAt",
"resourceId",
"resourceInternalId",
"resourceType",
"expire"
]
},
"team": {
"description": "Team",
"type": "object",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3
View File
@@ -1,5 +1,8 @@
<?php
// TODO: Remove, replace with runtimes.php directly
// Used in function templates and site frameworks
return [
'NODE' => [
'name' => 'node',
+39
View File
@@ -23,6 +23,7 @@ return [
'icon' => 'icon-lightning-bolt',
'id' => 'starter',
'name' => 'Starter function',
'score' => 5,
'tagline' =>
'A simple function to get started. Edit this function to explore endless possibilities with Appwrite Functions.',
'permissions' => ['any'],
@@ -62,6 +63,7 @@ return [
'icon' => 'icon-upstash',
'id' => 'query-upstash-vector',
'name' => 'Query Upstash Vector',
'score' => 4,
'tagline' => 'Vector database that stores text embeddings and context retrieval for LLMs',
'permissions' => ['any'],
'events' => [],
@@ -106,6 +108,7 @@ return [
'icon' => 'icon-redis',
'id' => 'query-redis-labs',
'name' => 'Query Redis Labs',
'score' => 4,
'tagline' => 'Key-value database with advanced caching capabilities.',
'permissions' => ['any'],
'events' => [],
@@ -149,6 +152,7 @@ return [
'icon' => 'icon-neo4j',
'id' => 'query-neo4j-auradb',
'name' => 'Query Neo4j AuraDB',
'score' => 4,
'tagline' => 'Graph database with focus on relations between data.',
'permissions' => ['any'],
'events' => [],
@@ -200,6 +204,7 @@ return [
'icon' => 'icon-mongodb',
'id' => 'query-mongo-atlas',
'name' => 'Query MongoDB Atlas',
'score' => 4,
'tagline' =>
'Realtime NoSQL document database with geospecial, graph, search, and vector suport.',
'permissions' => ['any'],
@@ -237,6 +242,7 @@ return [
'icon' => 'icon-neon',
'id' => 'query-neon-postgres',
'name' => 'Query Neon Postgres',
'score' => 4,
'tagline' =>
'Reliable SQL database with replication, point-in-time recovery, and pgvector support.',
'permissions' => ['any'],
@@ -305,6 +311,7 @@ return [
'icon' => 'icon-open-ai',
'id' => 'prompt-chatgpt',
'name' => 'Prompt ChatGPT',
'score' => 7,
'tagline' => 'Ask questions and let OpenAI GPT-3.5-turbo answer.',
'permissions' => ['any'],
'events' => [],
@@ -366,6 +373,7 @@ return [
'icon' => 'icon-discord',
'id' => 'discord-command-bot',
'name' => 'Discord Command Bot',
'score' => 6,
'tagline' => 'Simple command using Discord Interactions.',
'permissions' => ['any'],
'events' => [],
@@ -429,6 +437,7 @@ return [
'icon' => 'icon-perspective-api',
'id' => 'analyze-with-perspectiveapi',
'name' => 'Analyze with PerspectiveAPI',
'score' => 5,
'tagline' => 'Automate moderation by getting toxicity of messages.',
'permissions' => ['any'],
'events' => [],
@@ -464,6 +473,7 @@ return [
'icon' => 'icon-pangea',
'id' => 'censor-with-redact',
'name' => 'Censor with Redact',
'score' => 5,
'tagline' =>
'Censor sensitive information from a provided text string using Redact API by Pangea.',
'permissions' => ['any'],
@@ -512,6 +522,7 @@ return [
'icon' => 'icon-document',
'id' => 'generate-pdf',
'name' => 'Generate PDF',
'score' => 7,
'tagline' => 'Document containing sample invoice in PDF format.',
'permissions' => ['any'],
'events' => [],
@@ -533,6 +544,7 @@ return [
'icon' => 'icon-github',
'id' => 'github-issue-bot',
'name' => 'GitHub issue bot',
'score' => 4,
'tagline' =>
'Automate the process of responding to newly opened issues in a GitHub repository.',
'permissions' => ['any'],
@@ -577,6 +589,7 @@ return [
'icon' => 'icon-bookmark',
'id' => 'url-shortener',
'name' => 'URL shortener',
'score' => 3,
'tagline' => 'Generate URL with short ID and redirect to the original URL when visited.',
'permissions' => ['any'],
'events' => [],
@@ -628,6 +641,7 @@ return [
'icon' => 'icon-algolia',
'id' => 'sync-with-algolia',
'name' => 'Sync with Algolia',
'score' => 4,
'tagline' => 'Intuitive search bar for any data in Appwrite Databases.',
'permissions' => ['any'],
'events' => [],
@@ -709,6 +723,7 @@ return [
'icon' => 'icon-meilisearch',
'id' => 'sync-with-meilisearch',
'name' => 'Sync with Meilisearch',
'score' => 4,
'tagline' => 'Intuitive search bar for any data in Appwrite Databases.',
'permissions' => ['any'],
'events' => [],
@@ -802,6 +817,7 @@ return [
'icon' => 'icon-vonage',
'id' => 'whatsapp-with-vonage',
'name' => 'WhatsApp with Vonage',
'score' => 6,
'tagline' => 'Simple bot to answer WhatsApp messages.',
'permissions' => ['any'],
'events' => [],
@@ -888,6 +904,7 @@ return [
'icon' => 'icon-bell',
'id' => 'push-notification-with-fcm',
'name' => 'Push notification with FCM',
'score' => 4,
'tagline' => 'Send push notifications to your users using Firebase Cloud Messaging (FCM).',
'permissions' => ['any'],
'events' => [],
@@ -944,6 +961,7 @@ return [
'icon' => 'icon-mail',
'id' => 'email-contact-form',
'name' => 'Email contact form',
'score' => 7,
'tagline' => 'Sends an email with the contents of a HTML form.',
'permissions' => ['any'],
'events' => [],
@@ -1027,6 +1045,7 @@ return [
'icon' => 'icon-stripe',
'id' => 'subscriptions-with-stripe',
'name' => 'Subscriptions with Stripe',
'score' => 6,
'tagline' => 'Receive recurring card payments and grant subscribers extra permissions.',
'permissions' => ['any'],
'events' => [],
@@ -1068,6 +1087,7 @@ return [
'icon' => 'icon-stripe',
'id' => 'payments-with-stripe',
'name' => 'Payments with Stripe',
'score' => 8,
'tagline' => 'Receive card payments and store paid orders.',
'permissions' => ['any'],
'events' => [],
@@ -1125,6 +1145,7 @@ return [
'icon' => 'icon-chat',
'id' => 'text-generation-with-huggingface',
'name' => 'Text generation',
'score' => 5,
'tagline' => 'Generate text using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => [],
@@ -1159,6 +1180,7 @@ return [
'icon' => 'icon-translate',
'id' => 'language-translation-with-huggingface',
'name' => 'Language translation',
'score' => 5,
'tagline' => 'Translate text using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => [],
@@ -1193,6 +1215,7 @@ return [
'icon' => 'icon-eye',
'id' => 'image-classification-with-huggingface',
'name' => 'Image classification',
'score' => 5,
'tagline' => 'Classify images using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => ['buckets.*.files.*.create'],
@@ -1251,6 +1274,7 @@ return [
'icon' => 'icon-eye',
'id' => 'object-detection-with-huggingface',
'name' => 'Object detection',
'score' => 5,
'tagline' => 'Detect objects in images using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => ['buckets.*.files.*.create'],
@@ -1309,6 +1333,7 @@ return [
'icon' => 'icon-text',
'id' => 'speech-recognition-with-huggingface',
'name' => 'Speech recognition',
'score' => 5,
'tagline' => 'Transcribe audio to text using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => ['buckets.*.files.*.create'],
@@ -1367,6 +1392,7 @@ return [
'icon' => 'icon-chat',
'id' => 'text-to-speech-with-huggingface',
'name' => 'Text to speech',
'score' => 5,
'tagline' => 'Convert text to speech using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => ['databases.*.collections.*.documents.*.create'],
@@ -1425,6 +1451,7 @@ return [
'icon' => 'icon-chip',
'id' => 'generate-with-replicate',
'name' => 'Generate with Replicate',
'score' => 5,
'tagline' => "Generate text, audio and images using Replicate's API.",
'permissions' => ['any'],
'events' => [],
@@ -1460,6 +1487,7 @@ return [
'icon' => 'icon-chip',
'id' => 'generate-with-together-ai',
'name' => 'Generate with Together AI',
'score' => 5,
'tagline' => "Generate text and images using Together AI's API.",
'permissions' => ['any'],
'events' => [],
@@ -1502,6 +1530,7 @@ return [
'icon' => 'icon-chip',
'id' => 'chat-with-perplexity-ai',
'name' => 'Chat with Perplexity AI',
'score' => 5,
'tagline' => 'Create a chatbot using the Perplexity AI API.',
'permissions' => ['any'],
'events' => [],
@@ -1543,6 +1572,7 @@ return [
'icon' => 'icon-chip',
'id' => 'generate-with-replicate',
'name' => 'Generate with Replicate',
'score' => 5,
'tagline' => "Generate text, audio and images using Replicate's API.",
'permissions' => ['any'],
'events' => [],
@@ -1578,6 +1608,7 @@ return [
'icon' => 'icon-document-search',
'id' => 'sync-with-pinecone',
'name' => 'Sync with Pinecone',
'score' => 4,
'tagline' => "Sync your Appwrite database with Pinecone's vector database.",
'permissions' => ['any'],
'events' => [],
@@ -1641,6 +1672,7 @@ return [
'icon' => 'icon-chip',
'id' => 'rag-with-langchain',
'name' => 'RAG with LangChain',
'score' => 6,
'tagline' => 'Generate text using a LangChain RAG model',
'permissions' => ['any'],
'events' => [],
@@ -1704,6 +1736,7 @@ return [
'icon' => 'icon-chat',
'id' => 'speak-with-elevenlabs',
'name' => 'Speak with ElevenLabs',
'score' => 5,
'tagline' => 'Convert text to speech using the ElevenLabs API.',
'permissions' => ['any'],
'cron' => '',
@@ -1759,6 +1792,7 @@ return [
'icon' => 'icon-chip',
'id' => 'speak-with-lmnt',
'name' => 'Speak with LMNT',
'score' => 5,
'tagline' => 'Convert text to speech using the LMNT API.',
'permissions' => ['any'],
'cron' => '',
@@ -1800,6 +1834,7 @@ return [
'icon' => 'icon-chip',
'id' => 'chat-with-anyscale',
'name' => 'Chat with AnyScale',
'score' => 5,
'tagline' => 'Create a chatbot using the AnyScale API.',
'permissions' => ['any'],
'cron' => '',
@@ -1841,6 +1876,7 @@ return [
'icon' => 'icon-music-note',
'id' => 'music-generation-with-huggingface',
'name' => 'Music generation',
'score' => 4,
'tagline' => 'Generate music from a text prompt using the Hugging Face inference API.',
'permissions' => ['any'],
'events' => [],
@@ -1883,6 +1919,7 @@ return [
'icon' => 'icon-chip',
'id' => 'generate-with-fal-ai',
'name' => 'Generate with fal.ai',
'score' => 5,
'tagline' => "Generate images using fal.ai's API.",
'permissions' => ['any'],
'events' => [],
@@ -1918,6 +1955,7 @@ return [
'icon' => 'icon-currency-dollar',
'id' => 'subscriptions-with-lemon-squeezy',
'name' => 'Subscriptions with Lemon Squeezy',
'score' => 6,
'tagline' => 'Receive recurring card payments and grant subscribers extra permissions.',
'permissions' => ['any'],
'events' => [],
@@ -1973,6 +2011,7 @@ return [
'icon' => 'icon-currency-dollar',
'id' => 'payments-with-lemon-squeezy',
'name' => 'Payments with Lemon Squeezy',
'score' => 6,
'tagline' => 'Receive card payments and store paid orders.',
'permissions' => ['any'],
'events' => [],
+499 -102
View File
@@ -16,6 +16,16 @@ if (System::getEnv('_APP_ENV') === 'development') {
$url = $protocol . '://' . $hostname;
class UseCases
{
public const PORTFOLIO = 'portfolio';
public const STARTER = 'starter';
public const EVENTS = 'events';
public const ECOMMERCE = 'ecommerce';
public const DOCUMENTATION = 'documentation';
public const BLOG = 'blog';
}
const TEMPLATE_FRAMEWORKS = [
'SVELTEKIT' => [
'key' => 'sveltekit',
@@ -77,15 +87,6 @@ const TEMPLATE_FRAMEWORKS = [
'adapter' => 'static',
'fallbackFile' => '',
],
'OTHER' => [
'key' => 'other',
'name' => 'Other',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'fallbackFile' => 'index.html',
],
'VITE' => [
'key' => 'vite',
'name' => 'Vite',
@@ -115,6 +116,15 @@ const TEMPLATE_FRAMEWORKS = [
'outputDirectory' => './dist/angular/browser',
'fallbackFile' => 'index.html',
],
'ANALOG' => [
'key' => 'analog',
'name' => 'Analog',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'ssr',
'outputDirectory' => './dist/analog',
],
'VUE' => [
'key' => 'vue',
'name' => 'Vue.js',
@@ -125,6 +135,25 @@ const TEMPLATE_FRAMEWORKS = [
'outputDirectory' => './dist',
'fallbackFile' => 'index.html',
],
'OTHER' => [
'key' => 'other',
'name' => 'Other',
'installCommand' => '',
'buildCommand' => '',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './',
],
'LYNX' => [
'key' => 'lynx',
'name' => 'Lynx',
'installCommand' => 'npm install && cd web && npm install && cd ..',
'buildCommand' => 'npm run build && cd web && npm run build && cd ..',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './web/dist',
'fallbackFile' => 'index.html',
],
];
function getFramework(string $frameworkEnum, array $overrides)
@@ -135,14 +164,180 @@ function getFramework(string $frameworkEnum, array $overrides)
return [
[
'key' => 'template-for-onelink',
'name' => 'Onelink template',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/template-for-onelink-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-onelink-light.png',
'key' => 'template-for-documentation',
'name' => 'Documentation template',
'tagline' => 'Modern site to store your knowledge with a clean design, full-text search, dark mode, and more.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::DOCUMENTATION],
'screenshotDark' => $url . '/images/sites/templates/template-for-documentation-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-documentation-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'template-for-documentation',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => []
],
[
'key' => 'lynx-starter',
'name' => 'Lynx Starter',
'tagline' => 'Sample application built with Lynx, a cross-platform framework focused on performance.',
'score' => 1, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::STARTER],
'screenshotDark' => $url . '/images/sites/templates/lynx-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/lynx-starter-light.png',
'frameworks' => [
getFramework('LYNX', [
'providerRootDirectory' => './lynx/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'vitepress',
'name' => 'Vitepress',
'tagline' => 'Platform for documentation and knowledge sharing powered by Vite.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::DOCUMENTATION],
'screenshotDark' => $url . '/images/sites/templates/vitepress-dark.png',
'screenshotLight' => $url . '/images/sites/templates/vitepress-light.png',
'frameworks' => [
getFramework('VITE', [
'providerRootDirectory' => './vite/vitepress',
'outputDirectory' => '404.html',
'installCommand' => 'npm i vitepress && npm install',
'buildCommand' => 'npm run docs:build',
'outputDirectory' => './.vitepress/dist',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'vuepress',
'name' => 'Vuepress',
'tagline' => 'Platform for documentation and knowledge sharing powered by Vue.',
'score' => 4, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::DOCUMENTATION],
'screenshotDark' => $url . '/images/sites/templates/vuepress-dark.png',
'screenshotLight' => $url . '/images/sites/templates/vuepress-light.png',
'frameworks' => [
getFramework('VUE', [
'providerRootDirectory' => './vue/vuepress',
'outputDirectory' => '404.html',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './src/.vuepress/dist',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'docusaurus',
'name' => 'Docusaurus',
'tagline' => 'Platform for documentation and knowledge sharing powered by React.',
'score' => 4, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::DOCUMENTATION],
'screenshotDark' => $url . '/images/sites/templates/docusaurus-dark.png',
'screenshotLight' => $url . '/images/sites/templates/docusaurus-light.png',
'frameworks' => [
getFramework('REACT', [
'providerRootDirectory' => './react/docusaurus',
'outputDirectory' => '404.html',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './build',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'nxt-lnk',
'name' => 'Nxt Lnk',
'tagline' => 'Personal website for creators to merge all URLs to social profiles.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/nxt-lnk-dark.png',
'screenshotLight' => $url . '/images/sites/templates/nxt-lnk-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './nextjs/nxtlnk',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'magic-portfolio',
'name' => 'Magic Portfolio',
'tagline' => 'Complex personal website to showcase your projects, articles, and more.',
'score' => 7, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/magic-portfolio-dark.png',
'screenshotLight' => $url . '/images/sites/templates/magic-portfolio-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './nextjs/magic-portfolio',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'littlelink',
'name' => 'LittleLink',
'tagline' => 'Personal website for creators to merge all URLs to social profiles.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/littlelink-dark.png',
'screenshotLight' => $url . '/images/sites/templates/littlelink-light.png',
'frameworks' => [
getFramework('OTHER', [
'providerRootDirectory' => './other/littlelink',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'logspot',
'name' => 'Logspot',
'tagline' => 'Website to publish changelogs of your application.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::BLOG],
'screenshotDark' => $url . '/images/sites/templates/logspot-dark.png',
'screenshotLight' => $url . '/images/sites/templates/logspot-light.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './onelink',
'providerRootDirectory' => './nuxt/logspot',
'buildCommand' => 'npm run generate',
'outputDirectory' => './dist',
'adapter' => 'static',
@@ -150,20 +345,128 @@ return [
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'Meldiron',
'providerVersion' => '0.1.*',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'astro-nano',
'name' => 'Astro Nano',
'tagline' => 'Minimal personal website to showcase your projects, articles, and more.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/astro-nano-dark.png',
'screenshotLight' => $url . '/images/sites/templates/astro-nano-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './astro/nano',
'outputDirectory' => './dist',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'astro-starlight',
'name' => 'Astro Starlight',
'tagline' => 'Platform for documentation and knowledge sharing powered by Astro.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::DOCUMENTATION],
'screenshotDark' => $url . '/images/sites/templates/astro-starlight-dark.png',
'screenshotLight' => $url . '/images/sites/templates/astro-starlight-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './astro/starlight',
'outputDirectory' => './dist',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'astro-sphere',
'name' => 'Astro Sphere',
'tagline' => 'Modern personal website to showcase your projects, articles, and more.',
'score' => 7, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/astro-sphere-dark.png',
'screenshotLight' => $url . '/images/sites/templates/astro-sphere-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './astro/sphere',
'outputDirectory' => './dist',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'astro-starlog',
'name' => 'Astro Starlog',
'tagline' => 'Platform for publishing written content and media powered by Astro.',
'score' => 5, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::BLOG],
'screenshotDark' => $url . '/images/sites/templates/astro-starlog-dark.png',
'screenshotLight' => $url . '/images/sites/templates/astro-starlog-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './astro/starlog',
'outputDirectory' => './dist',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'onelink',
'name' => 'Onelink',
'tagline' => 'Personal website for creators to merge all URLs to social profiles.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/onelink-dark.png',
'screenshotLight' => $url . '/images/sites/templates/onelink-light.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './nuxt/onelink',
'buildCommand' => 'npm run generate',
'outputDirectory' => './dist',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
[
'key' => 'starter-for-flutter',
'name' => 'Flutter starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Flutter application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-flutter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-flutter-light.png',
'frameworks' => [
getFramework('FLUTTER', [
'providerRootDirectory' => './',
'buildCommand' => 'sh build.sh',
'buildCommand' => 'bash build.sh',
]),
],
'vcsProvider' => 'github',
@@ -200,7 +503,9 @@ return [
[
'key' => 'starter-for-js',
'name' => 'JavaScript starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple JavaScript application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-js-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-js-light.png',
'frameworks' => [
@@ -242,14 +547,16 @@ return [
[
'key' => 'starter-for-angular',
'name' => 'Angular starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Angular application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-angular-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-angular-light.png',
'frameworks' => [
getFramework('ANGULAR', [
'providerRootDirectory' => './',
'outputDirectory' => './dist/angular-starter-kit-for-appwrite/browser',
'buildCommand' => 'sh prepare-env.sh && npm run build'
'buildCommand' => 'bash prepare-env.sh && npm run build'
]),
],
'vcsProvider' => 'github',
@@ -283,10 +590,145 @@ return [
],
]
],
[
'key' => 'starter-for-astro',
'name' => 'Astro starter',
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Astro application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-astro-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-astro-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-astro',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'PUBLIC_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'PUBLIC_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'PUBLIC_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-analog',
'name' => 'Analog starter',
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Analog application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-analog-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-analog-light.png',
'frameworks' => [
getFramework('ANALOG', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-analog',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'VITE_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-remix',
'name' => 'Remix starter',
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Remix application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-remix-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-remix-light.png',
'frameworks' => [
getFramework('REMIX', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-remix',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'VITE_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-svelte',
'name' => 'Svelte starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Svelte application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-svelte-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-svelte-light.png',
'frameworks' => [
@@ -328,7 +770,9 @@ return [
[
'key' => 'starter-for-react',
'name' => 'React starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple React application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-react-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-react-light.png',
'frameworks' => [
@@ -370,7 +814,9 @@ return [
[
'key' => 'starter-for-vue',
'name' => 'Vue starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Vue application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-vue-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-vue-light.png',
'frameworks' => [
@@ -412,7 +858,9 @@ return [
[
'key' => 'starter-for-react-native',
'name' => 'React Native starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple React Native application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-react-native-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-react-native-light.png',
'frameworks' => [
@@ -455,7 +903,9 @@ return [
[
'key' => 'starter-for-nextjs',
'name' => 'Next.js starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Next.js application integrated with Appwrite SDK.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-nextjs-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-nextjs-light.png',
'frameworks' => [
@@ -497,7 +947,9 @@ return [
[
'key' => 'starter-for-nuxt',
'name' => 'Nuxt starter',
'useCases' => ['starter'],
'useCases' => [UseCases::STARTER],
'tagline' => 'Simple Nuxt application integrated with Appwrite SDK.',
'score' => 3, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'screenshotDark' => $url . '/images/sites/templates/starter-for-nuxt-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-nuxt-light.png',
'frameworks' => [
@@ -539,7 +991,9 @@ return [
[
'key' => 'template-for-event',
'name' => 'Event template',
'useCases' => ['starter'],
'tagline' => 'Hackathon landing page with support for project submissions.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::EVENTS],
'screenshotDark' => $url . '/images/sites/templates/template-for-event-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-event-light.png',
'frameworks' => [
@@ -575,7 +1029,9 @@ return [
[
'key' => 'template-for-portfolio',
'name' => 'Portfolio template',
'useCases' => ['starter'],
'tagline' => 'Simple personal website to showcase your projects, articles, and more.',
'score' => 6, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::PORTFOLIO],
'screenshotDark' => $url . '/images/sites/templates/template-for-portfolio-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-portfolio-light.png',
'frameworks' => [
@@ -592,7 +1048,9 @@ return [
[
'key' => 'template-for-store',
'name' => 'Store template',
'useCases' => ['starter'],
'tagline' => 'E-commerce platform for selling products with Stripe integration.',
'score' => 7, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::ECOMMERCE],
'screenshotDark' => $url . '/images/sites/templates/template-for-store-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-store-light.png',
'frameworks' => [
@@ -634,7 +1092,9 @@ return [
[
'key' => 'template-for-blog',
'name' => 'Blog template',
'useCases' => ['starter'],
'tagline' => 'Platform for publishing written content and media.',
'score' => 7, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::BLOG],
'screenshotDark' => $url . '/images/sites/templates/template-for-blog-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-blog-light.png',
'frameworks' => [
@@ -648,10 +1108,13 @@ return [
'providerVersion' => '0.1.*',
'variables' => []
],
// TODO: Remove astro starter eventually, or add all frameworks's starters
[
'key' => 'astro-starter',
'name' => 'Astro starter',
'useCases' => ['starter'],
'tagline' => 'Sample application built with Astro, a content-driven web framework.',
'score' => 1, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::STARTER],
'screenshotDark' => $url . '/images/sites/templates/astro-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/astro-starter-light.png',
'frameworks' => [
@@ -668,7 +1131,9 @@ return [
[
'key' => 'remix-starter',
'name' => 'Remix starter',
'useCases' => ['starter'],
'tagline' => 'Sample application built with Remix, a React meta-framework.',
'score' => 1, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::STARTER],
'screenshotDark' => $url . '/images/sites/templates/remix-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/remix-starter-light.png',
'frameworks' => [
@@ -682,72 +1147,4 @@ return [
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'flutter-starter',
'name' => 'Flutter starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/flutter-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/flutter-starter-light.png',
'frameworks' => [
getFramework('FLUTTER', [
'providerRootDirectory' => './flutter/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'nextjs-starter',
'name' => 'Next.js starter website',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/nextjs-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/nextjs-starter-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './nextjs/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'nuxt-starter',
'name' => 'Nuxt starter website',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/nuxt-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/nuxt-starter-light.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './nuxt/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'sveltekit-starter',
'name' => 'SvelteKit starter website',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/sveltekit-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/sveltekit-starter-light.png',
'frameworks' => [
getFramework('SVELTEKIT', [
'providerRootDirectory' => './sveltekit/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
];
+143 -10
View File
@@ -45,7 +45,16 @@ return [
],
[
'name' => '_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS',
'description' => 'Allows you to force HTTPS connection to function domains. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443.',
'description' => 'Deprecated since 1.7.0. Allows you to force HTTPS connection to function domains. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443.',
'introduction' => '',
'default' => 'disabled',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_OPTIONS_ROUTER_FORCE_HTTPS',
'description' => 'Allows you to force HTTPS connection to function and site domains. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443.',
'introduction' => '',
'default' => 'disabled',
'required' => false,
@@ -90,13 +99,40 @@ return [
],
[
'name' => '_APP_DOMAIN_TARGET',
'description' => 'A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite \'_APP_DOMAIN\' variable. The default value is \'localhost\'.',
'description' => 'Deprecated since 1.7.0. A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite \'_APP_DOMAIN\' variable. The default value is \'localhost\'.',
'introduction' => '',
'default' => 'localhost',
'required' => true,
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.' . PHP_EOL . 'You can use the same value as used for the Appwrite hostname.',
'filter' => 'domainTarget'
],
[
'name' => '_APP_DOMAIN_TARGET_CNAME',
'description' => 'A domain that can be used as DNS CNAME record to point to instance of Appwrite server.',
'introduction' => '',
'default' => 'localhost',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_DOMAIN_TARGET_AAAA',
'description' => 'An IPv6 that can be used as DNS AAAA record to point to instance of Appwrite server.',
'introduction' => '',
'default' => '::1',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_DOMAIN_TARGET_A',
'description' => 'An IPV4 that can be used as DNS A record to point to instance of Appwrite server.',
'introduction' => '',
'default' => '127.0.0.1',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_CONSOLE_WHITELIST_ROOT',
'description' => 'This option allows you to disable the creation of new users on the Appwrite console. When enabled only 1 user will be able to use the registration form. New users can be added by inviting them to your project. By default this option is enabled.',
@@ -746,13 +782,22 @@ return [
'variables' => [
[
'name' => '_APP_FUNCTIONS_SIZE_LIMIT',
'description' => 'The maximum size of a function in bytes. The default value is 30MB.',
'description' => 'Deprecated since 1.7.0. The maximum size of a function in bytes. The default value is 30MB.',
'introduction' => '0.13.0',
'default' => '30000000',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_SIZE_LIMIT',
'description' => 'The maximum size of a function and site deployments in bytes. The default value is 30MB.',
'introduction' => '1.7.0',
'default' => '30000000',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_FUNCTIONS_BUILD_SIZE_LIMIT',
'description' => 'The maximum size of a built deployment in bytes. The default value is 2,000,000,000 (2GB), and the maximum value is 4,294,967,295 (4.2GB).',
@@ -773,13 +818,22 @@ return [
],
[
'name' => '_APP_FUNCTIONS_BUILD_TIMEOUT',
'description' => 'The maximum number of seconds allowed as a timeout value when building a new function. The default value is 900 seconds.',
'description' => 'Deprecated since 1.7.0. The maximum number of seconds allowed as a timeout value when building a new function. The default value is 900 seconds.',
'introduction' => '0.13.0',
'default' => '900',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_BUILD_TIMEOUT',
'description' => 'The maximum number of seconds allowed as a timeout value when building a new function or site. The default value is 900 seconds.',
'introduction' => '1.7.0',
'default' => '900',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_FUNCTIONS_CONTAINERS',
'description' => 'Deprecated since 1.2.0. Runtimes now timeout by inactivity using \'_APP_FUNCTIONS_INACTIVE_THRESHOLD\'.',
@@ -791,22 +845,40 @@ return [
],
[
'name' => '_APP_FUNCTIONS_CPUS',
'description' => 'The maximum number of CPU core a single cloud function is allowed to use. Please note that setting a value higher than available cores will result in a function error, which might result in an error. The default value is empty. When it\'s empty, CPU limit will be disabled.',
'description' => 'Deprecated since 1.7.0. The maximum number of CPU core a single cloud function is allowed to use. Please note that setting a value higher than available cores will result in a function error, which might result in an error. The default value is empty. When it\'s empty, CPU limit will be disabled.',
'introduction' => '0.7.0',
'default' => '0',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_CPUS',
'description' => 'The maximum number of CPU core a single cloud function or a site is allowed to use. Please note that setting a value higher than available cores might result in an error. The default value is empty. When it\'s empty, CPU limit will be disabled.',
'introduction' => '1.7.0',
'default' => '0',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_FUNCTIONS_MEMORY',
'description' => 'The maximum amount of memory a single cloud function is allowed to use in megabytes. The default value is empty. When it\'s empty, memory limit will be disabled.',
'description' => 'Deprecated since 1.7.0. The maximum amount of memory a single cloud function is allowed to use in megabytes. The default value is empty. When it\'s empty, memory limit will be disabled.',
'introduction' => '0.7.0',
'default' => '0',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_MEMORY',
'description' => 'The maximum amount of memory a single function or site is allowed to use in megabytes. The default value is empty. When it\'s empty, memory limit will be disabled.',
'introduction' => '1.7.0',
'default' => '0',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_FUNCTIONS_MEMORY_SWAP',
'description' => 'Deprecated since 1.2.0. High use of swap memory is not recommended to preserve harddrive health.',
@@ -864,13 +936,22 @@ return [
],
[
'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD',
'description' => 'The minimum time a function must be inactive before it can be shut down and cleaned up. This feature is intended to clean up unused containers. Containers may remain active for longer than the interval before being shut down, as Appwrite only cleans up unused containers every hour. If no value is provided, the default is 60 seconds.',
'description' => 'Deprecated since 1.7.0. The minimum time a function must be inactive before it can be shut down and cleaned up. This feature is intended to clean up unused containers. Containers may remain active for longer than the interval before being shut down, as Appwrite only cleans up unused containers every hour. If no value is provided, the default is 60 seconds.',
'introduction' => '0.13.0',
'default' => '60',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_INACTIVE_THRESHOLD',
'description' => 'The minimum time a function or site must be inactive before it can be shut down and cleaned up. This feature is intended to clean up unused containers. Containers may remain active for longer than the interval before being shut down, as Appwrite only cleans up unused containers every hour. If no value is provided, the default is 60 seconds.',
'introduction' => '1.7.0',
'default' => '60',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => 'DOCKERHUB_PULL_USERNAME',
'description' => 'Deprecated with 1.2.0, use \'_APP_DOCKER_HUB_USERNAME\' instead.',
@@ -909,13 +990,22 @@ return [
],
[
'name' => '_APP_FUNCTIONS_RUNTIMES_NETWORK',
'description' => 'The docker network used for communication between the executor and runtimes.',
'description' => 'Deprecated since 1.7.0. The docker network used for communication between the executor and runtimes.',
'introduction' => '1.2.0',
'default' => 'runtimes',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_RUNTIMES_NETWORK',
'description' => 'The docker network used for communication between the executor and runtimes for sites and functions.',
'introduction' => '1.7.0',
'default' => 'runtimes',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_DOCKER_HUB_USERNAME',
'description' => 'The username for hub.docker.com. This variable is used to pull images from hub.docker.com.',
@@ -936,7 +1026,7 @@ return [
],
[
'name' => '_APP_FUNCTIONS_MAINTENANCE_INTERVAL',
'description' => 'Interval value containing the number of seconds that the executor should wait before checking for inactive runtimes. The default value is 3600 seconds (1 hour).',
'description' => 'Deprecated since 1.7.0. Interval value containing the number of seconds that the executor should wait before checking for inactive runtimes. The default value is 3600 seconds (1 hour).',
'introduction' => '1.4.0',
'default' => '3600',
'required' => false,
@@ -944,8 +1034,42 @@ return [
'question' => '',
'filter' => ''
],
[
'name' => '_APP_COMPUTE_MAINTENANCE_INTERVAL',
'description' => 'Interval value containing the number of seconds that the executor should wait before checking for inactive runtimes of functions and sites. The default value is 3600 seconds (1 hour).',
'introduction' => '1.7.0',
'default' => '3600',
'required' => false,
'overwrite' => true,
'question' => '',
'filter' => ''
],
],
],
[
'category' => 'Sites',
'description' => '',
'variables' => [
[
'name' => '_APP_SITES_TIMEOUT',
'description' => 'The maximum number of seconds allowed as a timeout value when creating a new site. The default value is 900 seconds. This is the global limit, timeout for individual functions are configured in the sites\'s settings or in appwrite.json.',
'introduction' => '1.7.0',
'default' => '900',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_SITES_RUNTIMES',
'description' => "This option allows you to enable or disable runtime environments for Sites. Disable unused runtimes to save disk space.\n\nTo enable cloud site runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: " . \implode(', ', \array_keys(Config::getParam('runtimes'))),
'introduction' => '1.7.0',
'default' => 'static-1,node-22,flutter-3.29',
'required' => false,
'question' => '',
'filter' => ''
],
]
],
[
'category' => 'VCS (Version Control System)',
'description' => '',
@@ -1048,13 +1172,22 @@ return [
],
[
'name' => '_APP_MAINTENANCE_RETENTION_AUDIT',
'description' => 'IThe maximum duration (in seconds) upto which to retain audit logs. The default value is 1209600 seconds (14 days).',
'description' => 'The maximum duration (in seconds) upto which to retain audit logs. The default value is 1209600 seconds (14 days).',
'introduction' => '0.7.0',
'default' => '1209600',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE',
'description' => 'The maximum duration (in seconds) upto which to retain console audit logs. The default value is 15778800 seconds (6 months).',
'introduction' => '1.6.2',
'default' => '15778800',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_MAINTENANCE_RETENTION_ABUSE',
'description' => 'The maximum duration (in seconds) upto which to retain abuse logs. The default value is 86400 seconds (1 day).',
+7 -7
View File
@@ -1188,8 +1188,8 @@ App::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('success', '', fn ($clients) => new Host($clients), '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, ['clients'])
->param('failure', '', fn ($clients) => new Host($clients), '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, ['clients'])
->param('success', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), '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, ['clients', 'devKey'])
->param('failure', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), '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, ['clients', 'devKey'])
->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)
->inject('request')
->inject('response')
@@ -1784,8 +1784,8 @@ App::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('success', '', fn ($clients) => new Host($clients), '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, ['clients'])
->param('failure', '', fn ($clients) => new Host($clients), '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, ['clients'])
->param('success', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), '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, ['clients', 'devKey'])
->param('failure', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), '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, ['clients', 'devKey'])
->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)
->inject('request')
->inject('response')
@@ -1864,7 +1864,7 @@ App::post('/v1/account/tokens/magic-url')
->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}'])
->param('userId', '', new CustomId(), 'Unique 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.')
->param('email', '', new Email(), 'User email.')
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project 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, ['clients'])
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project 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, ['clients', 'devKey'])
->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true)
->inject('request')
->inject('response')
@@ -3159,7 +3159,7 @@ App::post('/v1/account/recovery')
->label('abuse-limit', 10)
->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}'])
->param('email', '', new Email(), 'User email.')
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project 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.', false, ['clients'])
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project 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.', false, ['clients', 'devKey'])
->inject('request')
->inject('response')
->inject('user')
@@ -3434,7 +3434,7 @@ App::post('/v1/account/verification')
))
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{userId}')
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project 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.', false, ['clients']) // TODO add built-in confirm page
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project 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.', false, ['clients', 'devKey']) // TODO add built-in confirm page
->inject('request')
->inject('response')
->inject('project')
+2 -1
View File
@@ -496,6 +496,7 @@ App::get('/v1/avatars/qr')
'addQuietzone' => true,
'quietzoneSize' => $margin,
'outputType' => QRCode::OUTPUT_IMAGICK,
'scale' => 15,
]);
$qrcode = new QRCode($options);
@@ -510,7 +511,7 @@ App::get('/v1/avatars/qr')
$response
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->setContentType('image/png')
->send($image->output('png', 9));
->send($image->output('png', 90));
});
App::get('/v1/avatars/initials')
+21 -5
View File
@@ -8,7 +8,9 @@ use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Database\Document;
use Utopia\Domains\Domain;
use Utopia\System\System;
use Utopia\Validator\IP;
use Utopia\Validator\Text;
App::init()
@@ -40,10 +42,21 @@ App::get('/v1/console/variables')
))
->inject('response')
->action(function (Response $response) {
$isDomainEnabled = !empty(System::getEnv('_APP_DOMAIN', ''))
&& !empty(System::getEnv('_APP_DOMAIN_TARGET', ''))
&& System::getEnv('_APP_DOMAIN', '') !== 'localhost'
&& System::getEnv('_APP_DOMAIN_TARGET', '') !== 'localhost';
$validator = new Domain(System::getEnv('_APP_DOMAIN'));
$isDomainValid = !empty(System::getEnv('_APP_DOMAIN', '')) && $validator->isKnown() && !$validator->isTest();
$validator = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME'));
$isCNAMEValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_CNAME', '')) && $validator->isKnown() && !$validator->isTest();
$validator = new IP(IP::V4);
$isAValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_A', '')) && ($validator->isValid(System::getEnv('_APP_DOMAIN_TARGET_A')));
$validator = new IP(IP::V6);
$isAAAAValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_AAAA', '')) && $validator->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA'));
$isDomainEnabled = $isDomainValid && (
$isAAAAValid || $isAValid || $isCNAMEValid
);
$isVcsEnabled = !empty(System::getEnv('_APP_VCS_GITHUB_APP_NAME', ''))
&& !empty(System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY', ''))
@@ -54,7 +67,9 @@ App::get('/v1/console/variables')
$isAssistantEnabled = !empty(System::getEnv('_APP_ASSISTANT_OPENAI_API_KEY', ''));
$variables = new Document([
'_APP_DOMAIN_TARGET' => System::getEnv('_APP_DOMAIN_TARGET'),
'_APP_DOMAIN_TARGET_CNAME' => System::getEnv('_APP_DOMAIN_TARGET_CNAME'),
'_APP_DOMAIN_TARGET_AAAA' => System::getEnv('_APP_DOMAIN_TARGET_AAAA'),
'_APP_DOMAIN_TARGET_A' => System::getEnv('_APP_DOMAIN_TARGET_A'),
'_APP_STORAGE_LIMIT' => +System::getEnv('_APP_STORAGE_LIMIT'),
'_APP_COMPUTE_SIZE_LIMIT' => +System::getEnv('_APP_COMPUTE_SIZE_LIMIT'),
'_APP_USAGE_STATS' => System::getEnv('_APP_USAGE_STATS'),
@@ -62,6 +77,7 @@ App::get('/v1/console/variables')
'_APP_DOMAIN_ENABLED' => $isDomainEnabled,
'_APP_ASSISTANT_ENABLED' => $isAssistantEnabled,
'_APP_DOMAIN_SITES' => System::getEnv('_APP_DOMAIN_SITES'),
'_APP_DOMAIN_FUNCTIONS' => System::getEnv('_APP_DOMAIN_FUNCTIONS'),
'_APP_OPTIONS_FORCE_HTTPS' => System::getEnv('_APP_OPTIONS_FORCE_HTTPS'),
'_APP_DOMAINS_NAMESERVERS' => System::getEnv('_APP_DOMAINS_NAMESERVERS'),
]);
+4 -4
View File
@@ -3355,7 +3355,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$processDocument($collection, $document);
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations)
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
@@ -3520,7 +3520,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
}
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_READS, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_READS, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -3661,7 +3661,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$processDocument($collection, $document);
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_READS, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_READS, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -3959,7 +3959,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$setCollection($collection, $newDocument);
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations);
$response->addHeader('X-Debug-Operations', $operations);
+6 -6
View File
@@ -2936,7 +2936,7 @@ App::post('/v1/messaging/messages/email')
break;
case MessageStatus::SCHEDULED:
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3058,7 +3058,7 @@ App::post('/v1/messaging/messages/sms')
break;
case MessageStatus::SCHEDULED:
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3275,7 +3275,7 @@ App::post('/v1/messaging/messages/push')
break;
case MessageStatus::SCHEDULED:
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3661,7 +3661,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3862,7 +3862,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -4035,7 +4035,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
+136 -1
View File
@@ -1,12 +1,15 @@
<?php
use Appwrite\Auth\Auth;
use Appwrite\Event\Event;
use Appwrite\Event\Migration;
use Appwrite\Extend\Exception;
use Appwrite\OpenSSL\OpenSSL;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Validator\CompoundUID;
use Appwrite\Utopia\Database\Validator\Queries\Migrations;
use Appwrite\Utopia\Response;
use Utopia\App;
@@ -15,12 +18,21 @@ use Utopia\Database\Document;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\UID;
use Utopia\Migration\Resource;
use Utopia\Migration\Sources\Appwrite;
use Utopia\Migration\Sources\CSV;
use Utopia\Migration\Sources\Firebase;
use Utopia\Migration\Sources\NHost;
use Utopia\Migration\Sources\Supabase;
use Utopia\Migration\Transfer;
use Utopia\Storage\Compression\Algorithms\GZIP;
use Utopia\Storage\Compression\Algorithms\Zstd;
use Utopia\Storage\Compression\Compression;
use Utopia\Storage\Device;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Integer;
use Utopia\Validator\Text;
@@ -89,7 +101,6 @@ App::post('/v1/migrations/appwrite')
->dynamic($migration, Response::MODEL_MIGRATION);
});
App::post('/v1/migrations/firebase')
->groups(['api', 'migrations'])
->desc('Migrate Firebase data')
@@ -290,6 +301,130 @@ App::post('/v1/migrations/nhost')
->dynamic($migration, Response::MODEL_MIGRATION);
});
App::post('/v1/migrations/csv')
->groups(['api', 'migrations'])
->desc('Import documents from a CSV')
->label('scope', 'migrations.write')
->label('event', 'migrations.[migrationId].create')
->label('audits.event', 'migration.create')
->label('sdk', new Method(
namespace: 'migrations',
name: 'createCsvMigration',
description: '/docs/references/migrations/migration-csv.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_ACCEPTED,
model: Response::MODEL_MIGRATION,
)
]
))
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).')
->param('fileId', '', new UID(), 'File ID.')
->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.')
->inject('response')
->inject('dbForProject')
->inject('project')
->inject('deviceForFiles')
->inject('deviceForImports')
->inject('queueForEvents')
->inject('queueForMigrations')
->action(function (string $bucketId, string $fileId, string $resourceId, Response $response, Database $dbForProject, Document $project, Device $deviceForFiles, Device $deviceForImports, Event $queueForEvents, Migration $queueForMigrations) {
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
if ($bucket->isEmpty() || (!$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
$path = $file->getAttribute('path', '');
if (!$deviceForFiles->exists($path)) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
}
// no encryption, compression on files above 20MB.
$hasEncryption = !empty($file->getAttribute('openSSLCipher'));
$compression = $file->getAttribute('algorithm', Compression::NONE);
$hasCompression = $compression !== Compression::NONE;
$migrationId = ID::unique();
$newPath = $deviceForImports->getPath('/' . $migrationId . '_' . $fileId . '.csv');
if ($hasEncryption || $hasCompression) {
$source = $deviceForFiles->read($path);
// 1. decrypt
if ($hasEncryption) {
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('openSSLCipher'),
System::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
0,
hex2bin($file->getAttribute('openSSLIV')),
hex2bin($file->getAttribute('openSSLTag'))
);
}
// 2. decompress
if ($hasCompression) {
switch ($compression) {
case Compression::ZSTD:
$source = (new Zstd())->decompress($source);
break;
case Compression::GZIP:
$source = (new GZIP())->decompress($source);
break;
}
}
// manual write after decryption and/or decompression
if (! $deviceForImports->write($newPath, $source, 'text/csv')) {
throw new \Exception("Unable to copy file");
}
} elseif (! $deviceForFiles->transfer($path, $newPath, $deviceForImports)) {
throw new \Exception("Unable to copy file");
}
$fileSize = $deviceForImports->getFileSize($newPath);
$resources = Transfer::extractServices([Transfer::GROUP_DATABASES]);
$migration = $dbForProject->createDocument('migrations', new Document([
'$id' => $migrationId,
'status' => 'pending',
'stage' => 'init',
'source' => CSV::getName(),
'destination' => Appwrite::getName(),
'resources' => $resources,
'resourceId' => $resourceId,
'resourceType' => Resource::TYPE_DATABASE,
'statusCounters' => [],
'resourceData' => [],
'errors' => [],
'options' => [
'path' => $newPath,
'size' => $fileSize,
],
]));
$queueForEvents->setParam('migrationId', $migration->getId());
$queueForMigrations
->setMigration($migration)
->setProject($project)
->trigger();
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($migration, Response::MODEL_MIGRATION);
});
App::get('/v1/migrations')
->groups(['api', 'migrations'])
->desc('List migrations')
+7 -7
View File
@@ -149,7 +149,7 @@ App::get('/v1/project/usage')
$executionsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -165,7 +165,7 @@ App::get('/v1/project/usage')
$executionsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -181,7 +181,7 @@ App::get('/v1/project/usage')
$buildsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -230,13 +230,13 @@ App::get('/v1/project/usage')
$functionsStorageBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$deploymentMetric = str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $function->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE);
$deploymentMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE);
$deploymentValue = $dbForProject->findOne('stats', [
Query::equal('metric', [$deploymentMetric]),
Query::equal('period', ['inf'])
]);
$buildMetric = str_replace(['{functionInternalId}'], [$function->getInternalId()], METRIC_FUNCTION_ID_BUILDS_STORAGE);
$buildMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE);
$buildValue = $dbForProject->findOne('stats', [
Query::equal('metric', [$buildMetric]),
Query::equal('period', ['inf'])
@@ -254,7 +254,7 @@ App::get('/v1/project/usage')
$executionsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -270,7 +270,7 @@ App::get('/v1/project/usage')
$buildsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
+25 -6
View File
@@ -4,7 +4,7 @@ use Appwrite\Event\Certificate;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\CNAME;
use Appwrite\Network\Validator\DNS;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@@ -21,6 +21,8 @@ use Utopia\Database\Validator\UID;
use Utopia\Domains\Domain;
use Utopia\Logger\Log;
use Utopia\System\System;
use Utopia\Validator\AnyOf;
use Utopia\Validator\IP;
use Utopia\Validator\Text;
App::get('/v1/proxy/rules')
@@ -208,17 +210,27 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
throw new Exception(Exception::RULE_NOT_FOUND);
}
$target = new Domain(System::getEnv('_APP_DOMAIN_TARGET', ''));
$validators = [];
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
if (!$targetCNAME->isKnown() || $targetCNAME->isTest()) {
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
}
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
}
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
}
if (!$target->isKnown() || $target->isTest()) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Domain target must be configured as environment variable.');
if (empty($validators)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'At least one of domain targets environment variable must be configured.');
}
if ($rule->getAttribute('verification') === true) {
return $response->dynamic($rule, Response::MODEL_PROXY_RULE);
}
$validator = new CNAME($target->get()); // Verify Domain with DNS records
$validator = new AnyOf($validators, AnyOf::TYPE_STRING);
$domain = new Domain($rule->getAttribute('domain', ''));
$validationStart = \microtime(true);
@@ -226,7 +238,14 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
$log->addExtra('dnsTiming', \strval(\microtime(true) - $validationStart));
$log->addTag('dnsDomain', $domain->get());
$error = $validator->getLogs();
$errors = [];
foreach ($validators as $validator) {
if (!empty($validator->getLogs())) {
$errors[] = $validator->getLogs();
}
}
$error = \implode("\n", $errors);
$log->addExtra('dnsResponse', \is_array($error) ? \json_encode($error) : \strval($error));
throw new Exception(Exception::RULE_VERIFICATION_FAILED);
+10 -3
View File
@@ -936,9 +936,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
->inject('response')
->inject('dbForProject')
->inject('resourceToken')
->inject('deviceForFiles')
->inject('deviceForLocal')
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Response $response, Database $dbForProject, Device $deviceForFiles, Device $deviceForLocal) {
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal) {
if (!\extension_loaded('imagick')) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
@@ -953,19 +954,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
if (!$fileSecurity && !$valid) {
if (!$fileSecurity && !$valid && !$isToken) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
if ($fileSecurity && !$valid) {
if ($fileSecurity && !$valid && !$isToken) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
@@ -1765,6 +1771,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
$response->noContent();
});
/** Storage usage */
App::get('/v1/storage/usage')
->desc('Get storage usage stats')
->groups(['api', 'storage'])
+23 -4
View File
@@ -51,6 +51,7 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Host;
use Utopia\Validator\Text;
use Utopia\Validator\URL;
use Utopia\Validator\WhiteList;
App::post('/v1/teams')
@@ -455,7 +456,7 @@ App::post('/v1/teams/:teamId/memberships')
}
return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
}, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project 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, ['clients']) // TODO add our own built-in confirm page
->param('url', '', fn ($clients, $devKey) => $devKey->isEmpty() ? new Host($clients) : new URL(), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project 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, ['clients', 'devKey']) // TODO add our own built-in confirm page
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
->inject('response')
->inject('project')
@@ -615,7 +616,10 @@ App::post('/v1/teams/:teamId/memberships')
$membership = ($isPrivilegedUser || $isAppUser) ?
Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)) :
$dbForProject->createDocument('memberships', $membership);
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
if ($isPrivilegedUser || $isAppUser) {
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
}
} elseif ($membership->getAttribute('confirm') === false) {
$membership->setAttribute('secret', Auth::hash($secret));
@@ -1031,7 +1035,6 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
->param('membershipId', '', new UID(), 'Membership ID.')
->param('roles', [], function (Document $project) {
if ($project->getId() === 'console') {
;
$roles = array_keys(Config::getParam('roles', []));
array_filter($roles, function ($role) {
return !in_array($role, [Auth::USER_ROLE_APPS, Auth::USER_ROLE_GUESTS, Auth::USER_ROLE_USERS]);
@@ -1043,9 +1046,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
->inject('request')
->inject('response')
->inject('user')
->inject('project')
->inject('dbForProject')
->inject('queueForEvents')
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
@@ -1066,6 +1070,21 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
$isAppUser = Auth::isAppUser(Authorization::getRoles());
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
if ($project->getId() === 'console') {
// Quick check: fetch up to 2 owners to determine if only one exists
$ownersCount = $dbForProject->count(
collection: 'memberships',
queries: [Query::contains('roles', ['owner'])],
max: 2
);
// Prevent role change if there's only one owner left,
// the requester is that owner, and the new `$roles` no longer include 'owner'!
if ($ownersCount === 1 && $isOwner && !\in_array('owner', $roles)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'There must be at least one owner in the organization.');
}
}
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles');
}
+18 -2
View File
@@ -21,6 +21,7 @@ use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Database\Validator\Queries\Identities;
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
use Appwrite\Utopia\Database\Validator\Queries\Targets;
use Appwrite\Utopia\Database\Validator\Queries\Users;
use Appwrite\Utopia\Request;
@@ -799,9 +800,11 @@ App::get('/v1/users/:userId/memberships')
]
))
->param('userId', '', new UID(), 'User ID.')
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
->action(function (string $userId, Response $response, Database $dbForProject) {
->action(function (string $userId, array $queries, string $search, Response $response, Database $dbForProject) {
$user = $dbForProject->getDocument('users', $userId);
@@ -809,6 +812,19 @@ App::get('/v1/users/:userId/memberships')
throw new Exception(Exception::USER_NOT_FOUND);
}
try {
$queries = Query::parseQueries($queries);
} catch (QueryException $e) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
if (!empty($search)) {
$queries[] = Query::search('search', $search);
}
// Set internal queries
$queries[] = Query::equal('userInternalId', [$user->getInternalId()]);
$memberships = array_map(function ($membership) use ($dbForProject, $user) {
$team = $dbForProject->getDocument('teams', $membership->getAttribute('teamId'));
@@ -818,7 +834,7 @@ App::get('/v1/users/:userId/memberships')
->setAttribute('userEmail', $user->getAttribute('email'));
return $membership;
}, $user->getAttribute('memberships', []));
}, $dbForProject->find('memberships', $queries));
$response->dynamic(new Document([
'memberships' => $memberships,
+14 -5
View File
@@ -134,12 +134,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '', '');
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
} else {
$comment = new Comment();
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '', '');
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
$latestCommentId = \strval($github->createComment($owner, $repositoryName, $providerPullRequestId, $comment->generateComment()));
if (!empty($latestCommentId)) {
@@ -176,7 +176,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$latestCommentId = $comment->getAttribute('providerCommentId', '');
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '', '');
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
}
@@ -219,7 +219,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$commands[] = $resource->getAttribute('commands', '');
}
$deployment = $dbForProject->createDocument('deployments', new Document([
$deployment = Authorization::skip(fn () => $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$permissions' => [
Permission::read(Role::any()),
@@ -232,6 +232,8 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
'entrypoint' => $resource->getAttribute('entrypoint', ''),
'buildCommands' => \implode(' && ', $commands),
'buildOutput' => $resource->getAttribute('outputDirectory', ''),
'adapter' => $resource->getAttribute('adapter', ''),
'fallbackFile' => $resource->getAttribute('fallbackFile', ''),
'type' => 'vcs',
'installationId' => $installationId,
'installationInternalId' => $installationInternalId,
@@ -251,7 +253,14 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
'providerBranch' => $providerBranch,
'search' => implode(' ', [$deploymentId, $resource->getAttribute('entrypoint', '')]),
'activate' => $activate,
]));
])));
$resource = $resource
->setAttribute('latestDeploymentId', $deployment->getId())
->setAttribute('latestDeploymentInternalId', $deployment->getInternalId())
->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt())
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
Authorization::skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource));
if ($resource->getCollection() === 'sites') {
$projectId = $project->getId();
+188 -60
View File
@@ -56,10 +56,8 @@ Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey)
function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey)
{
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
$host = $request->getHostname() ?? '';
if (!empty($previewHostname)) {
$host = $previewHostname;
@@ -77,24 +75,28 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
)[0] ?? new Document();
}
$errorView = __DIR__ . '/../views/general/error.phtml';
$url = (System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https') . '://' . System::getEnv('_APP_DOMAIN', '');
if ($rule->isEmpty()) {
if ($host === System::getEnv('_APP_DOMAIN_FUNCTIONS', '') || $host === System::getEnv('_APP_DOMAIN_SITES', '')) {
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain cannot be used for security reasons. Please use any subdomain instead.');
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain cannot be used for security reasons. Please use any subdomain instead.', view: $errorView);
}
if (\str_ends_with($host, System::getEnv('_APP_DOMAIN_FUNCTIONS', '')) || \str_ends_with($host, System::getEnv('_APP_DOMAIN_SITES', ''))) {
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain is not connected to any Appwrite resource yet. Please configure custom domain or function domain to allow this request.');
$exception = new AppwriteException(AppwriteException::RULE_NOT_FOUND, 'This domain is not connected to any Appwrite resources. Visit domains tab under function/site settings to configure it.', view: $errorView);
$exception->addCTA('Start with this domain', $url . '/console');
throw $exception;
}
if (System::getEnv('_APP_OPTIONS_ROUTER_PROTECTION', 'disabled') === 'enabled') {
if ($host !== 'localhost' && $host !== APP_HOSTNAME_INTERNAL && $host !== System::getEnv('_APP_CONSOLE_DOMAIN', '')) {
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite over this domain. Please add it as custom domain to your project or disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.');
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite over this domain. Please add it as custom domain to your project or disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.', view: $errorView);
}
}
// Act as API - no Proxy logic
$utopia->getRoute()?->label('error', '');
return false;
}
@@ -104,7 +106,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
);
if (!$project->isEmpty() && $project->getId() !== 'console') {
$accessedAt = $project->getAttribute('accessedAt', '');
$accessedAt = $project->getAttribute('accessedAt', 0);
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) {
$project->setAttribute('accessedAt', DateTime::now());
Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
@@ -114,7 +116,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
if (array_key_exists('proxy', $project->getAttribute('services', []))) {
$status = $project->getAttribute('services', [])['proxy'];
if (!$status) {
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED, view: $errorView);
}
}
@@ -127,10 +129,10 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$type = $rule->getAttribute('type', '');
if ($type === 'deployment') {
if (System::getEnv('_APP_OPTIONS_COMPUTE_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
if (System::getEnv('_APP_OPTIONS_ROUTER_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
if ($request->getProtocol() !== 'https' && $request->getHostname() !== APP_HOSTNAME_INTERNAL) {
if ($request->getMethod() !== Request::METHOD_GET) {
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.', view: $errorView);
}
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
}
@@ -139,6 +141,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
/** @var Database $dbForProject */
$dbForProject = $getProjectDB($project);
/** @var Document $deployment */
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId')));
if ($deployment->getAttribute('resourceType', '') === 'functions') {
@@ -147,6 +150,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$type = 'site';
}
if ($deployment->isEmpty()) {
$resourceType = $rule->getAttribute('deploymentResourceType', '');
$resourceId = $rule->getAttribute('deploymentResourceId', '');
$type = ($resourceType === 'site') ? 'sites' : 'functions';
$exception = new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, view: $errorView);
$exception->addCTA('View deployments', $url . '/console/project-' . $projectId . '/' . $type . '/' . $resourceType . '-' . $resourceId);
throw $exception;
}
$resource = $type === 'function' ?
Authorization::skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) :
Authorization::skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', '')));
@@ -239,11 +251,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$requestHeaders = $request->getHeaders();
if ($resource->isEmpty() || !$resource->getAttribute('enabled')) {
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
if ($type === 'functions') {
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND, view: $errorView);
} else {
throw new AppwriteException(AppwriteException::SITE_NOT_FOUND, view: $errorView);
}
}
if ($isResourceBlocked($project, $type === 'function' ? RESOURCE_TYPE_FUNCTIONS : RESOURCE_TYPE_SITES, $resource->getId())) {
throw new AppwriteException(AppwriteException::GENERAL_RESOURCE_BLOCKED);
throw new AppwriteException(AppwriteException::GENERAL_RESOURCE_BLOCKED, view: $errorView);
}
$version = match ($type) {
@@ -261,22 +277,45 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
};
// Static site enforced runtime
if ($resource->getAttribute('adapter', '') === 'static') {
if ($deployment->getAttribute('adapter', '') === 'static') {
$runtime = $runtimes['static-1'] ?? null;
}
if (\is_null($runtime)) {
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported');
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported', view: $errorView);
}
if ($deployment->getAttribute('status') !== 'ready') {
throw new AppwriteException(AppwriteException::BUILD_NOT_READY);
$allowAnyStatus = !\is_null($apiKey) && $apiKey->isDeploymentStatusIgnored();
if (!$allowAnyStatus && $deployment->getAttribute('status') !== 'ready') {
$status = $deployment->getAttribute('status');
switch ($status) {
case 'failed':
$exception = new AppwriteException(AppwriteException::BUILD_FAILED, view: $errorView);
$ctaUrl = '/console/project-' . $project->getId() . '/sites/site-' . $resource->getId() . '/deployments/deployment-' . $deployment->getId();
$exception->addCTA('View logs', $url . $ctaUrl);
break;
case 'canceled':
$exception = new AppwriteException(AppwriteException::BUILD_CANCELED, view: $errorView);
$ctaUrl = '/console/project-' . $project->getId() . '/sites/site-' . $resource->getId() . '/deployments';
$exception->addCTA('View deployments', $url . $ctaUrl);
break;
default:
$exception = new AppwriteException(AppwriteException::BUILD_NOT_READY, view: $errorView);
$ctaUrl = '/console/project-' . $project->getId() . '/sites/site-' . $resource->getId() . '/deployments/deployment-' . $deployment->getId();
$exception->addCTA('Reload', '/');
$exception->addCTA('View logs', $url . $ctaUrl);
break;
}
throw $exception;
}
if ($type === 'function') {
$permissions = $resource->getAttribute('execute');
if (!(\in_array('any', $permissions)) && !(\in_array('guests', $permissions))) {
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
$exception = new AppwriteException(AppwriteException::FUNCTION_EXECUTE_PERMISSION_MISSING, view: $errorView);
$exception->addCTA('View settings', $url . '/console/project-' . $project->getId() . '/functions/function-' . $resource->getId() . '/settings');
throw $exception;
}
}
@@ -410,12 +449,11 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
]);
// SPA fallbackFile override
if ($resource->getAttribute('adapter', '') === 'static' && $resource->getAttribute('fallbackFile', '') !== '') {
$vars['OPEN_RUNTIMES_STATIC_FALLBACK'] = $resource->getAttribute('fallbackFile', '');
if ($deployment->getAttribute('adapter', '') === 'static' && $deployment->getAttribute('fallbackFile', '') !== '') {
$vars['OPEN_RUNTIMES_STATIC_FALLBACK'] = $deployment->getAttribute('fallbackFile', '');
}
/** Execute function */
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
try {
$version = match ($type) {
'function' => $resource->getAttribute('version', 'v2'),
@@ -438,7 +476,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$startCommand = $runtime['startCommand'];
if (!is_null($framework)) {
$adapter = ($framework['adapters'] ?? [])[$resource->getAttribute('adapter', '')] ?? null;
$adapter = ($framework['adapters'] ?? [])[$deployment->getAttribute('adapter', '')] ?? null;
if (!is_null($adapter) && isset($adapter['startCommand'])) {
$startCommand = $adapter['startCommand'];
}
@@ -473,29 +511,51 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
);
// Branded 404 override
if ($executionResponse['statusCode'] === 404 && $resource->getAttribute('adapter', '') === 'static') {
$isResponseBranded = false;
if ($executionResponse['statusCode'] === 404 && $deployment->getAttribute('adapter', '') === 'static') {
$layout = new View(__DIR__ . '/../views/general/404.phtml');
$executionResponse['body'] = $layout->render();
$executionResponse['headers']['content-length'] = \strlen($executionResponse['body']);
$isResponseBranded = true;
}
// Branded banner for previews
if (\is_null($apiKey) || $apiKey->isBannerDisabled() === false) {
$transformation = new Transformation();
$transformation->addAdapter(new Preview());
$transformation->setInput($executionResponse['body']);
$transformation->setTraits($executionResponse['headers']);
if ($isPreview && $transformation->transform()) {
$executionResponse['body'] = $transformation->getOutput();
if (!$isResponseBranded) {
if (\is_null($apiKey) || $apiKey->isBannerDisabled() === false) {
$transformation = new Transformation();
$transformation->addAdapter(new Preview());
$transformation->setInput($executionResponse['body']);
$transformation->setTraits($executionResponse['headers']);
if ($isPreview && $transformation->transform()) {
$executionResponse['body'] = $transformation->getOutput();
foreach ($executionResponse['headers'] as $key => $value) {
if (\strtolower($key) === 'content-length') {
$executionResponse['headers'][$key] = \strlen($executionResponse['body']);
foreach ($executionResponse['headers'] as $key => $value) {
if (\strtolower($key) === 'content-length') {
$executionResponse['headers'][$key] = \strlen($executionResponse['body']);
}
}
}
}
}
// Branded error pages (when developer left body empty)
if ($executionResponse['statusCode'] >= 400 && empty($executionResponse['body'])) {
$layout = new View($errorView);
$layout
->setParam('title', $project->getAttribute('name') . ' - Error')
->setParam('type', 'proxy_error_override')
->setParam('code', $executionResponse['statusCode']);
$executionResponse['body'] = $layout->render();
foreach ($executionResponse['headers'] as $key => $value) {
if (\strtolower($key) === 'content-length') {
$executionResponse['headers'][$key] = \strlen($executionResponse['body']);
} elseif (\strtolower($key) === 'content-type') {
$executionResponse['headers'][$key] = 'text/html';
}
}
}
$headersFiltered = [];
foreach ($executionResponse['headers'] as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
@@ -577,22 +637,67 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
}
if (!empty($apiKey) && !empty($apiKey->getDisabledMetrics())) {
foreach ($apiKey->getDisabledMetrics() as $key) {
$queueForStatsUsage->disableMetric($key);
}
}
$metricTypeExecutions = str_replace(['{resourceType}'], [$deployment->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_EXECUTIONS);
$metricTypeIdExecutions = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
$metricTypeExecutionsCompute = str_replace(['{resourceType}'], [$deployment->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_EXECUTIONS_COMPUTE);
$metricTypeIdExecutionsCompute = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_COMPUTE);
$metricTypeExecutionsMbSeconds = str_replace(['{resourceType}'], [$deployment->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_EXECUTIONS_MB_SECONDS);
$metricTypeIdExecutionsMBSeconds = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
if ($deployment->getAttribute('resourceType') === 'sites') {
$queueForStatsUsage
->disableMetric(METRIC_NETWORK_REQUESTS)
->disableMetric(METRIC_NETWORK_INBOUND)
->disableMetric(METRIC_NETWORK_OUTBOUND);
if ($resource->getAttribute('adapter') !== 'ssr') {
$queueForStatsUsage
->disableMetric(METRIC_EXECUTIONS)
->disableMetric(METRIC_EXECUTIONS_COMPUTE)
->disableMetric(METRIC_EXECUTIONS_MB_SECONDS)
->disableMetric($metricTypeExecutions)
->disableMetric($metricTypeIdExecutions)
->disableMetric($metricTypeExecutionsCompute)
->disableMetric($metricTypeIdExecutionsCompute)
->disableMetric($metricTypeExecutionsMbSeconds)
->disableMetric($metricTypeIdExecutionsMBSeconds);
}
$queueForStatsUsage
->addMetric(METRIC_SITES_REQUESTS, 1)
->addMetric(METRIC_SITES_INBOUND, $request->getSize() + $fileSize)
->addMetric(METRIC_SITES_OUTBOUND, $response->getSize())
->addMetric(str_replace('{siteInternalId}', $resource->getInternalId(), METRIC_SITES_ID_REQUESTS), 1)
->addMetric(str_replace('{siteInternalId}', $resource->getInternalId(), METRIC_SITES_ID_INBOUND), $request->getSize() + $fileSize)
->addMetric(str_replace('{siteInternalId}', $resource->getInternalId(), METRIC_SITES_ID_OUTBOUND), $response->getSize())
;
}
$compute = (int)($execution->getAttribute('duration') * 1000);
$mbSeconds = (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT));
$queueForStatsUsage
->addMetric(METRIC_NETWORK_REQUESTS, 1)
->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize)
->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize())
->addMetric(METRIC_EXECUTIONS, 1)
->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function
->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT)))
->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT)))
->addMetric($metricTypeExecutions, 1)
->addMetric($metricTypeIdExecutions, 1)
->addMetric(METRIC_EXECUTIONS_COMPUTE, $compute) // per project
->addMetric($metricTypeExecutionsCompute, $compute) // per function
->addMetric($metricTypeIdExecutionsCompute, $compute) // per function
->addMetric(METRIC_EXECUTIONS_MB_SECONDS, $mbSeconds)
->addMetric($metricTypeExecutionsMbSeconds, $mbSeconds)
->addMetric($metricTypeIdExecutionsMBSeconds, $mbSeconds)
->setProject($project)
->trigger();
return true;
} elseif ($type === 'api') {
$utopia->getRoute()?->label('error', '');
return false;
} elseif ($type === 'redirect') {
$url = $rule->getAttribute('redirectUrl', '');
@@ -605,10 +710,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$response->redirect($url, \intval($rule->getAttribute('redirectStatusCode', 301)));
return true;
} else {
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type);
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type, view: $errorView);
}
$utopia->getRoute()?->label('error', '');
return false;
}
@@ -653,10 +757,12 @@ App::init()
->inject('queueForEvents')
->inject('queueForCertificates')
->inject('queueForFunctions')
->inject('executor')
->inject('isResourceBlocked')
->inject('previewHostname')
->inject('devKey')
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey) {
/*
* Appwrite Router
*/
@@ -664,7 +770,7 @@ App::init()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -889,6 +995,10 @@ App::init()
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true');
if (!$devKey->isEmpty()) {
$response->addHeader('Access-Control-Allow-Origin', '*');
}
/*
* Validate Client Domain - Check to avoid CSRF attack
* Adding Appwrite API domains to allow XDOMAIN communication
@@ -899,6 +1009,7 @@ App::init()
if (
!$originValidator->isValid($origin)
&& $devKey->isEmpty()
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
&& $route->getLabel('origin', false) !== '*'
&& empty($request->getHeader('x-appwrite-key', ''))
@@ -917,12 +1028,14 @@ App::options()
->inject('queueForEvents')
->inject('queueForStatsUsage')
->inject('queueForFunctions')
->inject('executor')
->inject('geodb')
->inject('isResourceBlocked')
->inject('previewHostname')
->inject('project')
->inject('devKey')
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, ?Key $apiKey) {
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey) {
/*
* Appwrite Router
*/
@@ -930,7 +1043,7 @@ App::options()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -946,6 +1059,10 @@ App::options()
->addHeader('Access-Control-Allow-Credentials', 'true')
->noContent();
if (!$devKey->isEmpty()) {
$response->addHeader('Access-Control-Allow-Origin', '*');
}
/** OPTIONS requests in utopia do not execute shutdown handlers, as a result we need to track the OPTIONS requests explicitly
* @see https://github.com/utopia-php/http/blob/0.33.16/src/App.php#L825-L855
*/
@@ -966,6 +1083,7 @@ App::error()
->inject('logger')
->inject('log')
->inject('queueForStatsUsage')
->inject('devKey')
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$route = $utopia->getRoute();
@@ -1047,17 +1165,18 @@ App::error()
if (!empty($providerConfig) && $error->getCode() >= 400 && $error->getCode() < 500) {
// Register error logger
try {
$loggingProvider = new DSN($providerConfig ?? '');
$loggingProvider = new DSN($providerConfig);
$providerName = $loggingProvider->getScheme();
if (!empty($providerName) && $providerName === 'sentry') {
$key = $loggingProvider->getPassword();
$projectId = $loggingProvider->getUser() ?? '';
$host = 'https://' . $loggingProvider->getHost();
$sampleRate = $loggingProvider->getParam('sample', 0.01);
$adapter = new Sentry($projectId, $key, $host);
$logger = new Logger($adapter);
$logger->setSample(0.01);
$logger->setSample($sampleRate);
$publish = true;
} else {
throw new \Exception('Invalid experimental logging provider');
@@ -1179,7 +1298,7 @@ App::error()
$type = $error->getType();
$output = ((App::isDevelopment())) ? [
$output = App::isDevelopment() ? [
'message' => $message,
'code' => $code,
'file' => $file,
@@ -1200,9 +1319,14 @@ App::error()
->addHeader('Pragma', 'no-cache')
->setStatusCode($code);
$template = ($route) ? $route->getLabel('error', null) : null;
$template = $error->getView() ?? (($route) ? $route->getLabel('error', null) : null);
if ($template) {
// TODO: Ideally use group 'api' here, but all wildcard routes seem to have 'api' at the moment
if (!\str_starts_with($route->getPath(), '/v1')) {
$template = __DIR__ . '/../views/general/error.phtml';
}
if (!empty($template)) {
$layout = new View($template);
$layout
@@ -1213,7 +1337,8 @@ App::error()
->setParam('message', $output['message'] ?? '')
->setParam('type', $output['type'] ?? '')
->setParam('code', $output['code'] ?? '')
->setParam('trace', $output['trace'] ?? []);
->setParam('trace', $output['trace'] ?? [])
->setParam('exception', $error);
$response->html($layout->render());
return;
@@ -1238,11 +1363,12 @@ App::get('/robots.txt')
->inject('queueForEvents')
->inject('queueForStatsUsage')
->inject('queueForFunctions')
->inject('executor')
->inject('geodb')
->inject('isResourceBlocked')
->inject('previewHostname')
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -1250,7 +1376,7 @@ App::get('/robots.txt')
$template = new View(__DIR__ . '/../views/general/robots.phtml');
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1269,11 +1395,12 @@ App::get('/humans.txt')
->inject('queueForEvents')
->inject('queueForStatsUsage')
->inject('queueForFunctions')
->inject('executor')
->inject('geodb')
->inject('isResourceBlocked')
->inject('previewHostname')
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -1281,7 +1408,7 @@ App::get('/humans.txt')
$template = new View(__DIR__ . '/../views/general/humans.phtml');
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1428,11 +1555,12 @@ foreach (Config::getParam('services', []) as $service) {
}
}
// Modules
$platform = new Appwrite();
$platform->init(Service::TYPE_HTTP);
// Check for any errors found while we were initialising the SDK Methods.
if (!empty(Method::getErrors())) {
throw new \Exception('Errors found during SDK initialization:' . PHP_EOL . implode(PHP_EOL, Method::getErrors()));
}
// Modules
$platform = new Appwrite();
$platform->init(Service::TYPE_HTTP);
+33 -14
View File
@@ -175,8 +175,10 @@ $usageDatabaseListener = function (string $event, Document $document, StatsUsage
$queueForStatsUsage
->addMetric(METRIC_DEPLOYMENTS, $value) // per project
->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value) // per function
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);
->addMetric(str_replace(['{resourceType}'], [$document->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_DEPLOYMENTS), $value) // per function
->addMetric(str_replace(['{resourceType}'], [$document->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value)
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS), $value) // per function
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);
break;
default:
break;
@@ -248,7 +250,7 @@ App::init()
);
if ($dbKey) {
$accessedAt = $dbKey->getAttribute('accessedAt', '');
$accessedAt = $dbKey->getAttribute('accessedAt', 0);
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) {
$dbKey->setAttribute('accessedAt', DateTime::now());
@@ -259,7 +261,7 @@ App::init()
$sdkValidator = new WhiteList($servers, true);
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
if ($sdkValidator->isValid($sdk)) {
if ($sdk !== 'UNKNOWN' && $sdkValidator->isValid($sdk)) {
$sdks = $dbKey->getAttribute('sdks', []);
if (!in_array($sdk, $sdks)) {
@@ -309,7 +311,7 @@ App::init()
// Update project last activity
if (!$project->isEmpty() && $project->getId() !== 'console') {
$accessedAt = $project->getAttribute('accessedAt', '');
$accessedAt = $project->getAttribute('accessedAt', 0);
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) {
$project->setAttribute('accessedAt', DateTime::now());
Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
@@ -318,7 +320,7 @@ App::init()
// Update user last activity
if (!empty($user->getId())) {
$accessedAt = $user->getAttribute('accessedAt', '');
$accessedAt = $user->getAttribute('accessedAt', 0);
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCESS)) > $accessedAt) {
$user->setAttribute('accessedAt', DateTime::now());
@@ -397,9 +399,12 @@ App::init()
->inject('queueForStatsUsage')
->inject('dbForProject')
->inject('timelimit')
->inject('resourceToken')
->inject('mode')
->inject('apiKey')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, string $mode, ?Key $apiKey) use ($usageDatabaseListener, $eventDatabaseListener) {
->inject('plan')
->inject('devKey')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey) use ($usageDatabaseListener, $eventDatabaseListener) {
$route = $utopia->getRoute();
@@ -466,6 +471,7 @@ App::init()
$enabled // Abuse is enabled
&& !$isAppUser // User is not API key
&& !$isPrivilegedUser // User is not an admin
&& $devKey->isEmpty() // request doesn't not contain development key
&& $abuse->check() // Route is rate-limited
) {
throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED);
@@ -529,6 +535,10 @@ App::init()
$useCache = $route->getLabel('cache', false);
if ($useCache) {
$route = $utopia->match($request);
$isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview';
$isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser(Authorization::getRoles());
$key = md5($request->getURI() . '*' . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER);
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
$cache = new Cache(
@@ -541,10 +551,14 @@ App::init()
$parts = explode('/', $cacheLog->getAttribute('resourceType'));
$type = $parts[0] ?? null;
if ($type === 'bucket') {
if ($type === 'bucket' && (!$isImageTransformation || !$isDisabled)) {
$bucketId = $parts[1] ?? null;
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@@ -552,20 +566,23 @@ App::init()
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
if (!$fileSecurity && !$valid) {
if (!$fileSecurity && !$valid && !$isToken) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
$parts = explode('/', $cacheLog->getAttribute('resource'));
$fileId = $parts[1] ?? null;
if ($fileSecurity && !$valid) {
if ($fileSecurity && !$valid && !$isToken) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
@@ -582,8 +599,10 @@ App::init()
$response
->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp))
->addHeader('X-Appwrite-Cache', 'hit')
->setContentType($cacheLog->getAttribute('mimeType'))
->send($data);
->setContentType($cacheLog->getAttribute('mimeType'));
if (!$isImageTransformation || !$isDisabled) {
$response->send($data);
}
} else {
$response
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
@@ -789,7 +808,7 @@ App::shutdown()
$key = md5($request->getURI() . '*' . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER);
$signature = md5($data['payload']);
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
$accessedAt = $cacheLog->getAttribute('accessedAt', 0);
$now = DateTime::now();
if ($cacheLog->isEmpty()) {
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
+34 -31
View File
@@ -50,6 +50,7 @@ const APP_STORAGE_SITES = '/storage/sites';
const APP_STORAGE_FUNCTIONS = '/storage/functions';
const APP_STORAGE_BUILDS = '/storage/builds';
const APP_STORAGE_CACHE = '/storage/cache';
const APP_STORAGE_IMPORTS = '/storage/imports'; // Temporary storage for csv imports
const APP_STORAGE_CERTIFICATES = '/storage/certificates';
const APP_STORAGE_CONFIG = '/storage/config';
const APP_STORAGE_READ_BUFFER = 20 * (1000 * 1000); //20MB other names `APP_STORAGE_MEMORY_LIMIT`, `APP_STORAGE_MEMORY_BUFFER`, `APP_STORAGE_READ_LIMIT`, `APP_STORAGE_BUFFER_LIMIT`
@@ -195,36 +196,35 @@ const METRIC_BUILDS_COMPUTE = 'builds.compute';
const METRIC_BUILDS_COMPUTE_SUCCESS = 'builds.compute.success';
const METRIC_BUILDS_COMPUTE_FAILED = 'builds.compute.failed';
const METRIC_BUILDS_MB_SECONDS = 'builds.mbSeconds';
const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds';
const METRIC_FUNCTION_ID_BUILDS_SUCCESS = '{functionInternalId}.builds.success';
const METRIC_FUNCTION_ID_BUILDS_FAILED = '{functionInternalId}.builds.failed';
const METRIC_FUNCTION_ID_BUILDS_STORAGE = '{functionInternalId}.builds.storage';
const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute';
const METRIC_FUNCTION_ID_BUILDS_COMPUTE_SUCCESS = '{functionInternalId}.builds.compute.success';
const METRIC_FUNCTION_ID_BUILDS_COMPUTE_FAILED = '{functionInternalId}.builds.compute.failed';
const METRIC_FUNCTION_ID_BUILDS_MB_SECONDS = '{functionInternalId}.builds.mbSeconds';
const METRIC_SITES_ID_BUILDS = 'sites.{siteInternalId}.builds';
const METRIC_SITES_ID_BUILDS_SUCCESS = 'sites.{siteInternalId}.builds.success';
const METRIC_SITES_ID_BUILDS_FAILED = 'sites.{siteInternalId}.builds.failed';
const METRIC_SITES_ID_BUILDS_STORAGE = 'sites.{siteInternalId}.builds.storage';
const METRIC_SITES_ID_BUILDS_COMPUTE = 'sites.{siteInternalId}.builds.compute';
const METRIC_SITES_ID_BUILDS_COMPUTE_SUCCESS = 'sites.{siteInternalId}.builds.compute.success';
const METRIC_SITES_ID_BUILDS_COMPUTE_FAILED = 'sites.{siteInternalId}.builds.compute.failed';
const METRIC_SITES_ID_BUILDS_MB_SECONDS = 'sites.{siteInternalId}.builds.mbSeconds';
const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
const METRIC_EXECUTIONS = 'executions';
const METRIC_EXECUTIONS_COMPUTE = 'executions.compute';
const METRIC_EXECUTIONS_MB_SECONDS = 'executions.mbSeconds';
const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions';
const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute';
const METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS = '{functionInternalId}.executions.mbSeconds';
const METRIC_SITE_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
const METRIC_SITE_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
const METRIC_SITE_ID_BUILDS = '{siteInternalId}.builds';
const METRIC_SITE_ID_BUILDS_STORAGE = '{siteInternalId}.builds.storage';
const METRIC_SITE_ID_BUILDS_COMPUTE = '{siteInternalId}.builds.compute';
const METRIC_SITE_ID_BUILDS_MB_SECONDS = '{siteInternalId}.builds.mbSeconds';
const METRIC_RESOURCE_TYPE_ID_EXECUTIONS = '{resourceType}.{resourceInternalId}.executions';
const METRIC_RESOURCE_TYPE_ID_EXECUTIONS_COMPUTE = '{resourceType}.{resourceInternalId}.executions.compute';
const METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS = '{resourceType}.{resourceInternalId}.executions.mbSeconds';
const METRIC_RESOURCE_TYPE_ID_BUILDS_SUCCESS = '{resourceType}.{resourceInternalId}.builds.success';
const METRIC_RESOURCE_TYPE_ID_BUILDS_FAILED = '{resourceType}.{resourceInternalId}.builds.failed';
const METRIC_RESOURCE_TYPE_ID_BUILDS_COMPUTE = '{resourceType}.{resourceInternalId}.builds.compute';
const METRIC_RESOURCE_TYPE_ID_BUILDS_COMPUTE_SUCCESS = '{resourceType}.{resourceInternalId}.builds.compute.success';
const METRIC_RESOURCE_TYPE_ID_BUILDS_COMPUTE_FAILED = '{resourceType}.{resourceInternalId}.builds.compute.failed';
const METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS = '{resourceType}.{resourceInternalId}.builds.mbSeconds';
const METRIC_RESOURCE_TYPE_ID_BUILDS = '{resourceType}.{resourceInternalId}.builds';
const METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE = '{resourceType}.{resourceInternalId}.builds.storage';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
const METRIC_RESOURCE_TYPE_EXECUTIONS = '{resourceType}.executions';
const METRIC_RESOURCE_TYPE_EXECUTIONS_COMPUTE = '{resourceType}.executions.compute';
const METRIC_RESOURCE_TYPE_EXECUTIONS_MB_SECONDS = '{resourceType}.executions.mbSeconds';
const METRIC_RESOURCE_TYPE_BUILDS_SUCCESS = '{resourceType}.builds.success';
const METRIC_RESOURCE_TYPE_BUILDS_FAILED = '{resourceType}.builds.failed';
const METRIC_RESOURCE_TYPE_BUILDS_COMPUTE = '{resourceType}.builds.compute';
const METRIC_RESOURCE_TYPE_BUILDS_COMPUTE_SUCCESS = '{resourceType}.builds.compute.success';
const METRIC_RESOURCE_TYPE_BUILDS_COMPUTE_FAILED = '{resourceType}.builds.compute.failed';
const METRIC_RESOURCE_TYPE_BUILDS_MB_SECONDS = '{resourceType}.builds.mbSeconds';
const METRIC_RESOURCE_TYPE_BUILDS = '{resourceType}.builds';
const METRIC_RESOURCE_TYPE_BUILDS_STORAGE = '{resourceType}.builds.storage';
const METRIC_RESOURCE_TYPE_DEPLOYMENTS = '{resourceType}.deployments';
const METRIC_RESOURCE_TYPE_DEPLOYMENTS_STORAGE = '{resourceType}.deployments.storage';
const METRIC_NETWORK_REQUESTS = 'network.requests';
const METRIC_NETWORK_INBOUND = 'network.inbound';
const METRIC_NETWORK_OUTBOUND = 'network.outbound';
@@ -238,10 +238,13 @@ const METRIC_TOPICS = 'topics';
const METRIC_TARGETS = 'targets';
const METRIC_PROVIDER_TYPE_TARGETS = '{providerType}.targets';
const METRIC_KEYS = 'keys';
const METRIC_RESOURCE_TYPE_ID_BUILDS = '{resourceType}.{resourceInternalId}.builds';
const METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE = '{resourceType}.{resourceInternalId}.builds.storage';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
const METRIC_DOMAINS = 'domains';
const METRIC_SITES_REQUESTS = 'sites.requests';
const METRIC_SITES_INBOUND = 'sites.inbound';
const METRIC_SITES_OUTBOUND = 'sites.outbound';
const METRIC_SITES_ID_REQUESTS = 'sites.{siteInternalId}.requests';
const METRIC_SITES_ID_INBOUND = 'sites.{siteInternalId}.inbound';
const METRIC_SITES_ID_OUTBOUND = 'sites.{siteInternalId}.outbound';
// Resource types
+14
View File
@@ -133,6 +133,20 @@ Database::addFilter(
}
);
Database::addFilter(
'subQueryDevKeys',
function (mixed $value) {
return;
},
function (mixed $value, Document $document, Database $database) {
return $database
->find('devKeys', [
Query::equal('projectInternalId', [$document->getInternalId()]),
Query::limit(APP_LIMIT_SUBQUERY),
]);
}
);
Database::addFilter(
'subQueryWebhooks',
function (mixed $value) {
+1 -1
View File
@@ -217,7 +217,7 @@ $register->set('pools', function () {
return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array(
PDO::ATTR_TIMEOUT => 3, // Seconds
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_STRINGIFY_FETCHES => true
+108 -2
View File
@@ -21,6 +21,7 @@ use Appwrite\Extend\Exception;
use Appwrite\GraphQL\Schema;
use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Request;
use Executor\Executor;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\App;
use Utopia\Cache\Adapter\Sharding;
@@ -28,6 +29,7 @@ use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime as DatabaseDateTime;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
@@ -38,6 +40,7 @@ use Utopia\Logger\Log;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
use Utopia\Storage\Device;
use Utopia\Storage\Device\AWS;
use Utopia\Storage\Device\Backblaze;
use Utopia\Storage\Device\DOSpaces;
use Utopia\Storage\Device\Linode;
@@ -47,6 +50,7 @@ use Utopia\Storage\Device\Wasabi;
use Utopia\Storage\Storage;
use Utopia\System\System;
use Utopia\Validator\Hostname;
use Utopia\Validator\WhiteList;
use Utopia\VCS\Adapter\Git\GitHub as VcsGitHub;
// Runtime Execution
@@ -510,6 +514,10 @@ App::setResource('deviceForSites', function ($project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForImports', function (Document $project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForFunctions', function ($project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
@@ -544,7 +552,12 @@ function getDevice(string $root, string $connection = ''): Device
switch ($device) {
case Storage::DEVICE_S3:
return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl, $url);
if (!empty($url)) {
return new S3($root, $accessKey, $accessSecret, $url, $region, $acl);
} else {
return new AWS($root, $accessKey, $accessSecret, $bucket, $region, $acl);
}
// no break
case STORAGE::DEVICE_DO_SPACES:
$device = new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl);
$device->setHttpVersion(S3::HTTP_VERSION_1_1);
@@ -571,7 +584,12 @@ function getDevice(string $root, string $connection = ''): Device
$s3Bucket = System::getEnv('_APP_STORAGE_S3_BUCKET', '');
$s3Acl = 'private';
$s3EndpointUrl = System::getEnv('_APP_STORAGE_S3_ENDPOINT', '');
return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl, $s3EndpointUrl);
if (!empty($s3EndpointUrl)) {
return new S3($root, $s3AccessKey, $s3SecretKey, $s3EndpointUrl, $s3Region, $s3Acl);
} else {
return new AWS($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
}
// no break
case Storage::DEVICE_DO_SPACES:
$doSpacesAccessKey = System::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', '');
$doSpacesSecretKey = System::getEnv('_APP_STORAGE_DO_SPACES_SECRET', '');
@@ -773,6 +791,49 @@ App::setResource('smsRates', function () {
return [];
});
App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform) {
$devKey = $request->getHeader('x-appwrite-dev-key', $request->getParam('devKey', ''));
// Check if given key match project's development keys
$key = $project->find('secret', $devKey, 'devKeys');
if (!$key) {
return new Document([]);
}
// check expiration
$expire = $key->getAttribute('expire');
if (!empty($expire) && $expire < DatabaseDateTime::formatTz(DatabaseDateTime::now())) {
return new Document([]);
}
// update access time
$accessedAt = $key->getAttribute('accessedAt', 0);
if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) {
$key->setAttribute('accessedAt', DatabaseDateTime::now());
Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key));
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
}
// add sdk to key
$sdkValidator = new WhiteList($servers, true);
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
if ($sdk !== 'UNKNOWN' && $sdkValidator->isValid($sdk)) {
$sdks = $key->getAttribute('sdks', []);
if (!in_array($sdk, $sdks)) {
$sdks[] = $sdk;
$key->setAttribute('sdks', $sdks);
/** Update access time as well */
$key->setAttribute('accessedAt', DatabaseDateTime::now());
$key = Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key));
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
}
}
return $key;
}, ['request', 'project', 'servers', 'dbForPlatform']);
App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request) {
$teamInternalId = '';
if ($project->getId() !== 'console') {
@@ -834,3 +895,48 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key
return Key::decode($project, $key);
}, ['request', 'project']);
App::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
App::setResource('resourceToken', function ($project, $dbForProject, $request) {
$tokenJWT = $request->getParam('token');
if (!empty($tokenJWT) && !$project->isEmpty()) { // JWT authentication
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
try {
$payload = $jwt->decode($tokenJWT);
} catch (JWTException $error) {
return new Document([]);
}
$tokenId = $payload['tokenId'] ?? '';
$secret = $payload['secret'] ?? '';
if (empty($tokenId) || empty($secret)) {
return new Document([]);
}
$token = Authorization::skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId));
if ($token->isEmpty() || $token->getAttribute('secret') !== $secret) {
return new Document([]);
}
if ($token->getAttribute('resourceType') === 'file') {
$internalIds = explode(':', $token->getAttribute('resourceInternalId'));
$ids = explode(':', $token->getAttribute('resourceId'));
if (count($internalIds) !== 2 || count($ids) !== 2) {
return new Document([]);
}
return new Document([
'bucketId' => $ids[0],
'fileId' => $ids[1],
'bucketInternalId' => $internalIds[0],
'fileInternalId' => $internalIds[1],
]);
}
}
return new Document([]);
}, ['project', 'dbForProject', 'request']);
+6 -4
View File
@@ -7,6 +7,8 @@
<title>404 Not Found</title>
<style>
@import url(https://fonts.bunny.net/css?family=fira-code:400|inter:400);
* {
margin: 0;
padding: 0;
@@ -36,7 +38,7 @@
background: var(--color-overlay-on-neutral, rgba(0, 0, 0, 0.06));
color: var(--color-fgColor-neutral-secondary, #56565C);
text-align: center;
font-family: var(--font-family-sansSerif, Inter);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 400;
@@ -47,7 +49,7 @@
h1 {
color: var(--color-fgColor-neutral-primary, #2D2D31);
text-align: center;
font-family: var(--font-family-sansSerif, Inter);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-XXXL, 32px);
font-style: normal;
font-weight: 400;
@@ -59,7 +61,7 @@
button {
border-radius: var(--border-radius-S, 8px);
font-family: var(--font-family-sansSerif, Inter);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
@@ -88,7 +90,7 @@
}
.brand p {
font-family: var(--font-family-monospace, "Aeonik Fono");
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-XS, 12px);
font-style: normal;
font-weight: 400;
+505 -90
View File
@@ -1,22 +1,112 @@
<?php
use Utopia\System\System;
$development = $this->getParam('development', false);
$type = $this->getParam('type', 'general_server_error');
$code = $this->getParam('code', 500);
$errorID = $this->getParam('errorID', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
$message = $this->getParam('message', '');
$trace = $this->getParam('trace', []);
$projectName = $this->getParam('projectName', '');
$projectURL = $this->getParam('projectURL', '');
$title = $this->getParam('title', '')
$title = $this->getParam('title', 'Error');
$exception = $this->getParam('exception', null);
$isSimpleMessage = true;
$label = '';
$labelClass = '';
$buttons = [];
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
$hostname = System::getEnv('_APP_DOMAIN');
// TODO: remove this later
if (System::getEnv('_APP_ENV') === 'development') {
$hostname = 'localhost';
}
$url = $protocol . '://' . $hostname;
if($exception !== null && method_exists($exception, 'getCTAs')) {
foreach ($exception->getCTAs() as $index => $cta) {
$class = ($index === 0) ? 'bordered-button' : 'button';
$buttons[] = [
'text' => $cta['label'],
'url' => $cta['url'],
'class' => $class
];
}
}
switch ($type) {
case 'proxy_error_override':
$type = '';
$label = 'Error ' . $code;
$message = $code >= 500 ? 'An unexpected server error occured.' : 'An unexpected client error occured.';
switch($code) {
case 401:
$message = 'You must sign in to access this page.';
break;
case 403:
$message = 'You are not authorized to access this page.';
break;
case 404:
$message = 'The page you are looking for does not exist.';
break;
case 504:
$message = 'The server did not respond in time.';
break;
case 501:
$message = 'This page is not implemented yet.';
break;
}
break;
case 'function_execute_permission_missing':
$label = 'Execution not permitted';
$labelClass = 'warning';
break;
case 'build_not_ready':
$label = 'Deployment is still building';
$message = 'The page will update after the build completes.';
$labelClass = 'warning';
break;
case 'build_failed':
$label = 'Deployment build failed';
$message = 'An error occurred during the build process.';
$labelClass = 'error';
break;
case 'rule_not_found':
$label = 'Nothing is here yet';
$message = 'This page is empty, but you can make it yours.';
break;
case 'deployment_not_found':
$label = 'No active deployments';
$message = 'This page is empty, activate a deployment to make it live.';
break;
case 'build_canceled':
$label = 'Deployment build canceled';
$message = 'This build was canceled and won\'t be deployed.';
break;
case 'general_route_not_found':
$label = 'Page not found';
$message = 'The page you\'re looking for doesn\'t exist.';
break;
default:
$label = 'Error ' . $code;
$message = $message;
$isSimpleMessage = false;
break;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="" />
<link rel="icon" href="/favicon.png" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
<link rel="icon" type="image/svg+xml" href="<?php echo $url; ?>/images/logos/appwrite-icon.svg" />
<link rel="mask-icon" type="image/png" href="<?php echo $url; ?>/images/logos/appwrite-icon.png" />
<link
rel="preload"
href="/fonts/inter/inter-v8-latin-600.woff2"
@@ -29,102 +119,427 @@ $title = $this->getParam('title', '')
as="font"
type="font/woff2"
crossorigin />
<link
rel="preload"
href="/fonts/poppins/poppins-v19-latin-500.woff2"
as="font"
type="font/woff2"
crossorigin />
<link
rel="preload"
href="/fonts/poppins/poppins-v19-latin-600.woff2"
as="font"
type="font/woff2"
crossorigin />
<link
rel="preload"
href="/fonts/poppins/poppins-v19-latin-700.woff2"
as="font"
type="font/woff2"
crossorigin />
<link
rel="preload"
href="/fonts/source-code-pro/source-code-pro-v20-latin-regular.woff2"
as="font"
type="font/woff2"
crossorigin />
<link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink" />
<link rel="preload" as="style" type="text/css" href="/fonts/main.css" />
<link rel="stylesheet" href="/fonts/main.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="content-security-policy" content="">
<title><?php echo $this->print($title); ?></title>
<style>
@media(min-width:768px) {
article.card {
padding: 2rem !important;
@import url(https://fonts.bunny.net/css?family=fira-code:400|inter:400);
* {
margin: 0;
padding: 0;
}
body {
background-color: #FFFFFF;
}
.main {
display: flex;
min-height: 100vh;
width: 100vw;
align-items: center;
justify-content: center;
}
.content {
margin-left: auto;
margin-right: auto;
max-width: 400px;
}
span {
padding: var(--space-1, 2px) var(--space-3, 6px);
border-radius: var(--border-radius-XS, 6px);
background: var(--color-overlay-on-neutral, rgba(0, 0, 0, 0.06));
color: var(--color-fgColor-neutral-secondary, #56565C);
text-align: center;
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: -0.063px;
}
h1 {
color: var(--color-fgColor-neutral-primary, #2D2D31);
text-align: center;
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-XXXL, 32px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: -0.144px;
margin-top: 8px;
margin-bottom: 32px;
}
.content h1 {
margin-bottom: 20px;
}
.content.small-error h1 {
font-size: var(--font-size-M, 20px);
}
.content.large-error h1 {
font-size: var(--font-size-XXXL, 32px);
}
.bordered-button {
border-radius: var(--border-radius-S, 8px);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.063px;
padding: var(--space-3, 6px) var(--space-5, 10px);
cursor: pointer;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #D8D8DB);
background: var(--color-bgColor-neutral-primary, #FFF);
color: var(--color-fgColor-neutral-secondary, #56565C);
}
button {
border-radius: var(--border-radius-S, 8px);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.063px;
padding: var(--space-3, 6px) var(--space-5, 10px);
cursor: pointer;
border: var(--border-width-S, 1px) solid transparent;
background: var(--color-bgColor-neutral-primary, #FFF);
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.center {
display: flex;
justify-content: center;
gap: 8px;
}
.brand {
position: absolute;
width: 100%;
bottom: 32px;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
.brand p {
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-XS, 12px);
font-style: normal;
font-weight: 400;
line-height: 130%;
letter-spacing: 0.96px;
text-transform: uppercase;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.brand svg {
height: 20px;
}
.warning {
background: var(--color-overlay-on-neutral, rgba(254, 124, 67, 0.16));
color: var(--color-fgColor-neutral-secondary, #61250A);
}
.error {
background: var(--color-overlay-on-neutral, rgba(255, 69, 58, 0.16));
color: var(--color-fgColor-neutral-secondary, #B31212);
}
.logo-dark {
display: none;
}
.logo-light {
display: block;
}
.type {
padding: var(--space-1, 2px) var(--space-3, 6px);
border-radius: var(--border-radius-XS, 6px);
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #EDEDF0);
background: var(--color-overlay-on-neutral, rgba(250, 250, 251, 1));
color: var(--color-fgColor-neutral-secondary, #56565C);
text-align: center;
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-XS, 12px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: 0px;
}
.error-trace {
max-width: 900px;
padding: 20px;
font-family: var(--font-family-sansSerif, Inter), sans-serif;
}
.back-button {
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
color: var(--color-fgColor-neutral-secondary, #56565C);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.45px;
}
.back-button:hover {
text-decoration: underline;
}
.trace-grid {
display: grid;
grid-template-columns: auto 1fr;
gap: 16px;
background: var(--color-bgColor-neutral-secondary, #FFFFFF);
padding: 10px 12px;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #EDEDF0);
}
.trace-grid-header {
display: flex;
align-items: center;
padding: 10px 12px;
background: var(--color-bgColor-neutral-secondary, #FAFAFB);
border-radius: 8px 8px 0 0;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #EDEDF0);
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
letter-spacing: -0.45px;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.trace-label {
font-family: var(--font-family-sansSerif, Inter), sans-serif;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
letter-spacing: -0.45px;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.trace-value {
color: var(--color-fgColor-neutral-secondary, #56565C);
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
letter-spacing: 0px;
}
.trace-args {
/* grid-column: 1 / -1; */
padding: 10px 12px;
/* white-space: pre-wrap; */
overflow-x: auto;
font-family: var(--font-family-monospace, "Fira Code"), monospace;
font-size: var(--font-size-S, 14px);
font-weight: 400;
line-height: 140%;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
@media (max-width: 768px) {
.content {
margin-left: 16px;
margin-right: 16px;
}
h1 {
font-size: 28px;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #1D1D21;
}
h1 {
color: var(--color-fgColor-neutral-primary, #EDEDF0);
}
span {
background: var(--color-overlay-on-neutral, rgba(255, 255, 255, 0.2));
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.bordered-button {
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #414146);
background: var(--color-bgColor-neutral-primary, #1D1D21);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
button {
background: var(--color-bgColor-neutral-primary, #1D1D21);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.brand p {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.warning {
background: var(--color-overlay-on-neutral, rgba(254, 124, 67, 0.24));
color: var(--color-fgColor-neutral-secondary, #FFD5C2);
}
.error {
background: var(--color-overlay-on-neutral, rgba(255, 69, 58, 0.28));
color: var(--color-fgColor-neutral-secondary, #FFD5D4);
}
.logo-light {
display: none;
}
.logo-dark {
display: block;
}
.type {
background: var(--color-overlay-on-neutral, rgba(25, 25, 28, 1));
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #414146);
}
.back-button {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-grid {
background: var(--color-bgColor-neutral-secondary, #1D1D21);
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #2D2D31);
}
.trace-grid-header {
background: var(--color-bgColor-neutral-secondary, #19191C);
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #2D2D31);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-label {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-value {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.trace-args {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
}
</style>
</head>
<body>
<div class="container u-margin-block-start-24">
<article class="card u-padding-16">
<div class="u-flex u-flex-vertical u-gap-16">
<h1 class="heading-level-4 u-trim-1">Error <?php echo $this->print($code); ?></h1>
<p class="text"><?php echo $this->print($message); ?></p>
<div class="u-flex u-flex-vertical u-gap-8">
<p class="text">Type</p>
<p><code class="inline-code"><?php echo $this->print($type); ?></code></p>
<body x-data="{ page: 'error' }">
<div class="main">
<div x-show="page === 'error'" class="content <?php echo $isSimpleMessage ? 'large-error' : 'small-error' ?>">
<div class="center"><span class="<?php echo $this->print($labelClass); ?>"><?php echo $this->print($label); ?></span></div>
<h1><?php echo $this->print($message); ?></h1>
<?php if (!empty($type)): ?>
<div class="center">
<span class='type'><?php echo $this->print($type); ?></span>
</div>
<?php if ($development) : ?>
<h2 class="heading-level-5 u-trim-1">Error Trace</h2>
<?php foreach ($trace as $log) : ?>
<div class="table-with-scroll">
<div class="table-wrapper">
<table class="table is-remove-outer-styles">
<tbody class="table-tbody">
<?php foreach ($log as $key => $value) : ?>
<tr>
<td class="table-col" style="width: 120px"><?php echo $this->print($key, self::FILTER_ESCAPE); ?></td>
<td class="table-col"><code class="grid-code u-max-height-200 u-overflow-x-auto u-overflow-y-auto">
<?php if (is_array($value)) : ?>
<pre><?php echo $this->print(var_export($value, true), self::FILTER_ESCAPE); ?></pre>
<?php else : ?>
<pre><?php echo $this->print($value, self::FILTER_ESCAPE); ?></pre>
<?php endif; ?>
</code>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<div class="center" style="margin-top: 20px;">
<?php if (!empty($buttons)): ?>
<?php foreach ($buttons as $button): ?>
<a href="<?php echo htmlspecialchars($button['url']); ?>">
<button class="<?php echo htmlspecialchars($button['class']); ?>">
<?php echo htmlspecialchars($button['text']); ?>
</button>
</a>
<?php endforeach; ?>
<?php endif; ?>
<?php if ($development) : ?>
<button class="<?php echo count($buttons) === 0 ? 'bordered-button' : 'button' ?>" x-on:click="page = 'trace'">View error trace</button>
<?php endif; ?>
</div>
</article>
</div>
<div x-show="page === 'trace'" class="error-trace">
<button class="back-button" x-on:click="page = 'error'">
Back
</button>
<div class="trace-grid-header">Error trace</div>
<?php foreach ($trace as $index => $traceItem): ?>
<div class="trace-grid">
<?php if (isset($traceItem['file'])): ?>
<div class="trace-label">file</div>
<div class="trace-value"><?php echo $this->print($traceItem['file']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['line'])): ?>
<div class="trace-label">line</div>
<div class="trace-value"><?php echo $this->print($traceItem['line']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['function'])): ?>
<div class="trace-label">function</div>
<div class="trace-value"><?php echo $this->print($traceItem['function']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['args'])): ?>
<div class="trace-label">args</div>
<div class="trace-args"><pre><?php echo $this->print(\var_export($traceItem['args'], true)); ?></pre></div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div>
<div x-show="page === 'error'" class="brand">
<p>Powered by</p>
<svg class="logo-dark" width="110" height="20" viewBox="0 0 110 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.8649 16.2461C33.6492 16.2461 34.5511 15.3184 34.9433 14.6867H35.1197C35.1981 15.3578 35.6687 15.9895 36.5903 15.9895H38.3353V14.0156H37.8843C37.5706 14.0156 37.4138 13.838 37.4138 13.5617V5.64661H35.1001V6.90986H34.9236C34.4727 6.27823 33.5315 5.39001 31.8061 5.39001C29.0611 5.39001 27.022 7.67965 27.022 10.818C27.022 13.9564 29.1003 16.2461 31.8649 16.2461ZM32.2767 13.9959C30.6493 13.9959 29.3748 12.7919 29.3748 10.8378C29.3748 8.92316 30.6101 7.62044 32.2571 7.62044C33.8256 7.62044 35.1393 8.86395 35.1393 10.8378C35.1393 12.5945 34.0217 13.9959 32.2767 13.9959Z" fill="#EDEDF0" />
<path d="M39.7013 20H42.0149V14.6867H42.1914C42.6227 15.3184 43.5443 16.2461 45.3677 16.2461C48.1127 16.2461 50.1127 13.9169 50.1127 10.818C50.1127 7.69939 47.9755 5.39001 45.2109 5.39001C43.4462 5.39001 42.5835 6.35719 42.1718 6.89012H41.9953V5.63019H39.7013V20ZM44.8776 14.0551C43.2894 14.0551 41.9757 12.8708 41.9757 10.818C41.9757 9.06133 43.0933 7.58096 44.8383 7.58096C46.4657 7.58096 47.7402 8.86395 47.7402 10.818C47.7402 12.7326 46.5049 14.0551 44.8776 14.0551Z" fill="#EDEDF0" />
<path d="M51.3065 20H53.6202V14.6867H53.7966C54.228 15.3184 55.1495 16.2461 56.973 16.2461C59.718 16.2461 61.5273 13.9169 61.5273 10.818C61.5273 7.69939 59.5807 5.39001 56.8161 5.39001C55.0515 5.39001 54.1888 6.35719 53.777 6.89012H53.6005V5.64661H51.3065V20ZM56.4828 14.0551C54.8946 14.0551 53.5809 12.8708 53.5809 10.818C53.5809 9.06133 54.6985 7.58096 56.4436 7.58096C58.071 7.58096 59.3454 8.86395 59.3454 10.818C59.3454 12.7326 58.1102 14.0551 56.4828 14.0551Z" fill="#EDEDF0" />
<path d="M64.5857 16.2296H67.8601L69.7227 8.11721H69.8404L71.7031 16.2296H74.9579L77.5642 5.88678H75.2323L73.3697 14.0189H73.1932L71.3305 5.88678H68.2522L66.3699 14.0189H66.1935L64.3504 5.88678H61.8799L64.5857 16.2296Z" fill="#EDEDF0" />
<path d="M78.7363 16.2296H81.0499V11.1174C81.0499 9.16334 81.9519 7.9593 83.6381 7.9593H84.6576V5.63019H83.893C82.5793 5.63019 81.5793 6.53815 81.1872 7.40663H81.0303V5.88678H78.7363V16.2296Z" fill="#EDEDF0" />
<path d="M96.1391 16.2296H97.943V14.1571H96.1587C95.4529 14.1571 95.1588 13.8413 95.1588 13.111V7.93956H98.0606V5.88678H95.1588V2.98526H92.9628V5.88678H91.0413V7.93956H92.8255V13.1307C92.8255 15.3217 94.1392 16.2296 96.1391 16.2296Z" fill="#EDEDF0" />
<path d="M104.15 16.2461C106.287 16.2461 108.17 15.1802 108.836 13.0287L106.719 12.5155C106.346 13.6603 105.268 14.2525 104.13 14.2525C102.444 14.2525 101.327 13.1472 101.307 11.4102H109.091V10.7588C109.091 7.67965 107.189 5.39001 104.052 5.39001C101.287 5.39001 98.915 7.58096 98.915 10.8378C98.915 13.9959 101.013 16.2461 104.15 16.2461ZM101.327 9.71269C101.464 8.46918 102.581 7.42305 104.052 7.42305C105.464 7.42305 106.621 8.31128 106.738 9.71269H101.327Z" fill="#EDEDF0" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0125 16.2296H87.6989V7.93956H85.895V5.88678H90.0125V16.2296Z" fill="#EDEDF0" />
<path d="M88.6834 4.45145C89.5265 4.45145 90.154 3.81983 90.154 2.99082C90.154 2.18155 89.5265 1.54993 88.6834 1.54993C87.8403 1.54993 87.2129 2.18155 87.2129 2.99082C87.2129 3.81983 87.8403 4.45145 88.6834 4.45145Z" fill="#EDEDF0" />
<path d="M20.2007 13.6935V18.258H8.88588C5.5894 18.258 2.71111 16.4222 1.17116 13.6935C0.947288 13.2968 0.751353 12.8806 0.586995 12.4486C0.26435 11.6021 0.0615332 10.6938 0 9.74603V8.51195C0.0133592 8.30074 0.03441 8.09119 0.0619381 7.88413C0.118209 7.45921 0.203222 7.04343 0.314953 6.63926C1.37195 2.80758 4.8089 0 8.88588 0C12.9629 0 16.3994 2.80758 17.4564 6.63926H12.6184C11.8241 5.39025 10.4493 4.5645 8.88588 4.5645C7.32245 4.5645 5.94767 5.39025 5.15341 6.63926C4.91132 7.01895 4.72349 7.43764 4.60042 7.88413C4.49112 8.27999 4.43282 8.69744 4.43282 9.12899C4.43282 10.4373 4.96962 11.6166 5.83027 12.4486C6.62778 13.2209 7.70299 13.6935 8.88588 13.6935H20.2007Z" fill="#FD366E" />
<path d="M20.2006 7.88412V12.4486H11.9414C12.8021 11.6166 13.3389 10.4373 13.3389 9.12899C13.3389 8.69744 13.2806 8.27999 13.1713 7.88412H20.2006Z" fill="#FD366E" />
</svg>
<svg class="logo-light" width="110" height="20" viewBox="0 0 110 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.8648 16.2461C33.649 16.2461 34.5509 15.3184 34.9431 14.6867H35.1195C35.198 15.3578 35.6685 15.9895 36.5901 15.9895H38.3351V14.0156H37.8841C37.5704 14.0156 37.4136 13.838 37.4136 13.5617V5.64661H35.0999V6.90986H34.9235C34.4725 6.27823 33.5314 5.39001 31.8059 5.39001C29.0609 5.39001 27.0218 7.67965 27.0218 10.818C27.0218 13.9564 29.1001 16.2461 31.8648 16.2461ZM32.2765 13.9959C30.6491 13.9959 29.3746 12.7919 29.3746 10.8378C29.3746 8.92316 30.6099 7.62044 32.2569 7.62044C33.8255 7.62044 35.1391 8.78499 35.1391 10.8378C35.1391 12.5945 34.0215 13.9959 32.2765 13.9959Z" fill="#2D2D31" />
<path d="M39.7011 20H42.0147V14.6867H42.1912C42.6226 15.3184 43.5441 16.2461 45.3676 16.2461C48.1126 16.2461 50.1125 13.9169 50.1125 10.818C50.1125 7.69939 47.9753 5.39001 45.2107 5.39001C43.4461 5.39001 42.5833 6.35719 42.1716 6.89012H41.9951V5.64661H39.7011V20ZM44.8774 14.0551C43.2892 14.0551 41.9755 12.8708 41.9755 10.818C41.9755 9.06133 43.0931 7.58096 44.8382 7.58096C46.4656 7.58096 47.74 8.86395 47.74 10.818C47.74 12.7326 46.5048 14.0551 44.8774 14.0551Z" fill="#2D2D31" />
<path d="M51.3063 20H53.62V14.6867H53.7964C54.2278 15.3184 55.1493 16.2461 56.9728 16.2461C59.7178 16.2461 61.5271 13.9169 61.5271 10.818C61.5271 7.69939 59.5805 5.39001 56.8159 5.39001C55.0513 5.39001 54.1886 6.35719 53.7768 6.89012H53.6004V5.64661H51.3063V20ZM56.4826 14.0551C54.8944 14.0551 53.5808 12.8708 53.5808 10.818C53.5808 9.06133 54.6984 7.58096 56.4434 7.58096C58.0708 7.58096 59.3453 8.86395 59.3453 10.818C59.3453 12.7326 58.11 14.0551 56.4826 14.0551Z" fill="#2D2D31" />
<path d="M64.5855 16.2296H67.8599L69.7226 8.11721H69.8402L71.7029 16.2296H74.9577L77.564 5.88678H75.2322L73.3695 14.0189H73.193L71.3303 5.88678H68.252L66.3697 14.0189H66.1933L64.3502 5.88678H61.8797L64.5855 16.2296Z" fill="#2D2D31" />
<path d="M78.7361 16.2296H81.0498V11.1174C81.0498 9.16334 81.9517 7.9593 83.6379 7.9593H84.6575V5.63019H83.8928C82.5791 5.63019 81.5791 6.53815 81.187 7.40663H81.0301V5.88678H78.7361V16.2296Z" fill="#2D2D31" />
<path d="M96.1389 16.2296H97.9428V14.1571H96.1585C95.4527 14.1571 95.1586 13.8413 95.1586 13.111V7.93956H98.0604V5.88678H95.1586V2.98526H92.9626V5.88678H91.0411V7.93956H92.8253V13.1307C92.8253 15.3217 94.139 16.2296 96.1389 16.2296Z" fill="#2D2D31" />
<path d="M104.15 16.2461C106.287 16.2461 108.169 15.1802 108.836 13.0287L106.718 12.5155C106.346 13.6603 105.268 14.2525 104.13 14.2525C102.444 14.2525 101.326 13.1472 101.307 11.4102H109.091V10.7588C109.091 7.67965 107.189 5.39001 104.052 5.39001C101.287 5.39001 98.9148 7.58096 98.9148 10.8378C98.9148 13.9959 101.013 16.2461 104.15 16.2461ZM101.326 9.71269C101.464 8.46918 102.581 7.42305 104.052 7.42305C105.464 7.42305 106.62 8.31128 106.738 9.71269H101.326Z" fill="#2D2D31" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0123 16.2296H87.6987V7.93956H85.8948V5.88678H90.0123V16.2296Z" fill="#2D2D31" />
<path d="M88.6835 4.45145C89.5266 4.45145 90.154 3.81983 90.154 2.99082C90.154 2.18155 89.5266 1.54993 88.6835 1.54993C87.8404 1.54993 87.213 2.18155 87.213 2.99082C87.213 3.81983 87.8404 4.45145 88.6835 4.45145Z" fill="#2D2D31" />
<path d="M20.2007 13.6935V18.258H8.88588C5.5894 18.258 2.71111 16.4222 1.17116 13.6935C0.947288 13.2968 0.751353 12.8806 0.586995 12.4486C0.26435 11.6021 0.0615332 10.6938 0 9.74603V8.51195C0.0133592 8.30074 0.03441 8.09119 0.0619381 7.88413C0.118209 7.45921 0.203222 7.04343 0.314953 6.63926C1.37195 2.80758 4.8089 0 8.88588 0C12.9629 0 16.3994 2.80758 17.4564 6.63926H12.6184C11.8241 5.39025 10.4493 4.5645 8.88588 4.5645C7.32245 4.5645 5.94767 5.39025 5.15341 6.63926C4.91132 7.01895 4.72349 7.43764 4.60042 7.88413C4.49112 8.27999 4.43282 8.69744 4.43282 9.12899C4.43282 10.4373 4.96962 11.6166 5.83027 12.4486C6.62778 13.2209 7.70299 13.6935 8.88588 13.6935H20.2007Z" fill="#FD366E" />
<path d="M20.2007 7.88412V12.4486H11.9415C12.8022 11.6166 13.339 10.4373 13.339 9.12899C13.339 8.69744 13.2807 8.27999 13.1714 7.88412H20.2007Z" fill="#FD366E" />
</svg>
</div>
<script type="text/javascript">
const app = (JSON.parse(localStorage.getItem('appwrite')) ?? {});
const theme = app.theme ?? 'auto';
if (theme === 'auto') {
const darkThemeMq = window.matchMedia('(prefers-color-scheme: dark)');
if (darkThemeMq.matches) {
document.body.setAttribute('class', `theme-dark`);
} else {
document.body.setAttribute('class', `theme-light`);
}
} else {
document.body.setAttribute('class', `theme-${theme}`);
}
</script>
</body>
</html>
+43 -12
View File
@@ -65,6 +65,8 @@ $image = $this->getParam('image', '');
- appwrite-config:/storage/config:rw
- appwrite-certificates:/storage/certificates:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
depends_on:
- mariadb
- redis
@@ -86,10 +88,12 @@ $image = $this->getParam('image', '');
- _APP_OPTIONS_ABUSE
- _APP_OPTIONS_ROUTER_PROTECTION
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_COMPUTE_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_FUNCTIONS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
@@ -134,12 +138,14 @@ $image = $this->getParam('image', '');
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_COMPUTE_SIZE_LIMIT
- _APP_COMPUTE_TIMEOUT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
- _APP_FUNCTIONS_RUNTIMES
- _APP_SITES_RUNTIMES
- _APP_DOMAIN_SITES
- _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST
- _APP_LOGGING_CONFIG
@@ -149,6 +155,7 @@ $image = $this->getParam('image', '');
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER
@@ -165,7 +172,6 @@ $image = $this->getParam('image', '');
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-console:
<<: *x-logging
container_name: appwrite-console
@@ -300,6 +306,7 @@ $image = $this->getParam('image', '');
- appwrite-uploads:/storage/uploads:rw
- appwrite-cache:/storage/cache:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
- appwrite-certificates:/storage/certificates:rw
environment:
@@ -342,6 +349,7 @@ $image = $this->getParam('image', '');
- _APP_EXECUTOR_HOST
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- _APP_EMAIL_CERTIFICATES
@@ -385,7 +393,9 @@ $image = $this->getParam('image', '');
- mariadb
volumes:
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
- appwrite-uploads:/storage/uploads:rw
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
@@ -405,13 +415,14 @@ $image = $this->getParam('image', '');
- _APP_VCS_GITHUB_APP_NAME
- _APP_VCS_GITHUB_PRIVATE_KEY
- _APP_VCS_GITHUB_APP_ID
- _APP_COMPUTE_TIMEOUT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
- _APP_COMPUTE_SIZE_LIMIT
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_COMPUTE_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_DOMAIN
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
@@ -435,6 +446,7 @@ $image = $this->getParam('image', '');
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_DOMAIN_SITES
appwrite-worker-certificates:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
@@ -455,7 +467,9 @@ $image = $this->getParam('image', '');
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_FUNCTIONS
- _APP_EMAIL_CERTIFICATES
- _APP_REDIS_HOST
@@ -496,7 +510,8 @@ $image = $this->getParam('image', '');
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_COMPUTE_TIMEOUT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
@@ -607,7 +622,9 @@ $image = $this->getParam('image', '');
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_EMAIL_SECURITY
- _APP_REDIS_HOST
- _APP_REDIS_PORT
@@ -636,7 +653,9 @@ $image = $this->getParam('image', '');
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_FUNCTIONS
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
@@ -653,6 +672,7 @@ $image = $this->getParam('image', '');
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
@@ -855,6 +875,14 @@ $image = $this->getParam('image', '');
- appwrite
environment:
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
image: appwrite/browser:0.2.2
container_name: appwrite-browser
<<: *x-logging
restart: unless-stopped
networks:
- appwrite
openruntimes-executor:
container_name: openruntimes-executor
@@ -862,7 +890,7 @@ $image = $this->getParam('image', '');
<<: *x-logging
restart: unless-stopped
stop_signal: SIGINT
image: openruntimes/executor:0.7.0
image: openruntimes/executor:0.7.13
networks:
- appwrite
- runtimes
@@ -870,6 +898,7 @@ $image = $this->getParam('image', '');
- /var/run/docker.sock:/var/run/docker.sock
- appwrite-builds:/storage/builds:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
# Host mount nessessary to share files between executor and runtimes.
# It's not possible to share mount file between 2 containers without host mount (copying is too slow)
- /tmp:/tmp:rw
@@ -880,8 +909,9 @@ $image = $this->getParam('image', '');
- OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
- OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
- OPR_EXECUTOR_ENV=$_APP_ENV
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
- OPR_EXECUTOR_RUNTIME_VERSIONS=v5
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
@@ -962,5 +992,6 @@ volumes:
appwrite-uploads:
appwrite-certificates:
appwrite-functions:
appwrite-sites:
appwrite-builds:
appwrite-config:
+17 -9
View File
@@ -16,10 +16,9 @@ use Appwrite\Event\Migration;
use Appwrite\Event\Realtime;
use Appwrite\Event\StatsUsage;
use Appwrite\Event\StatsUsageDump;
/** remove */
/** /remove */
use Appwrite\Event\Webhook;
use Appwrite\Platform\Appwrite;
use Executor\Executor;
use Swoole\Runtime;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\Cache\Adapter\Sharding;
@@ -215,15 +214,18 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
}, ['pools', 'cache']);
Server::setResource('abuseRetention', function () {
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400);
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400); // 1 day
});
Server::setResource('auditRetention', function () {
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 1209600));
});
Server::setResource('auditRetention', function (Document $project) {
if ($project->getId() === 'console') {
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE', 15778800)); // 6 months
}
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 1209600)); // 14 days
}, ['project']);
Server::setResource('executionRetention', function () {
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', 1209600));
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', 1209600)); // 14 days
});
Server::setResource('cache', function (Registry $register) {
@@ -341,6 +343,10 @@ Server::setResource('deviceForSites', function (Document $project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForImports', function (Document $project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForFunctions', function (Document $project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
@@ -372,7 +378,7 @@ Server::setResource('certificates', function () {
});
Server::setResource('logError', function (Registry $register, Document $project) {
return function (Throwable $error, string $namespace, string $action, ?array $extras) use ($register, $project) {
return function (Throwable $error, string $namespace, string $action, ?array $extras = null) use ($register, $project) {
$logger = $register->get('logger');
if ($logger) {
@@ -394,7 +400,7 @@ Server::setResource('logError', function (Registry $register, Document $project)
$log->addExtra('trace', $error->getTraceAsString());
foreach ($extras as $key => $value) {
foreach (($extras ?? []) as $key => $value) {
$log->addExtra($key, $value);
}
@@ -416,6 +422,8 @@ Server::setResource('logError', function (Registry $register, Document $project)
};
}, ['register', 'project']);
Server::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
$pools = $register->get('pools');
$platform = new Appwrite();
$args = $platform->getEnv('argv');
+6 -6
View File
@@ -44,7 +44,7 @@
"ext-openssl": "*",
"ext-zlib": "*",
"ext-sockets": "*",
"appwrite/php-runtimes": "0.18.*",
"appwrite/php-runtimes": "0.19.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.52.*",
"utopia-php/analytics": "0.10.*",
@@ -53,19 +53,19 @@
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/detector": "0.1.*",
"utopia-php/database": "0.61.*",
"utopia-php/database": "0.66.*",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
"utopia-php/fetch": "0.3.*",
"utopia-php/fetch": "0.4.*",
"utopia-php/image": "0.8.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.16.*",
"utopia-php/migration": "0.6.*",
"utopia-php/migration": "0.9.1",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "0.5.*",
"utopia-php/pools": "0.8.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/queue": "0.9.*",
"utopia-php/registry": "0.5.*",
@@ -74,7 +74,7 @@
"utopia-php/system": "0.9.*",
"utopia-php/telemetry": "0.1.*",
"utopia-php/vcs": "0.10.*",
"utopia-php/websocket": "0.1.*",
"utopia-php/websocket": "0.3.*",
"matomo/device-detector": "6.1.*",
"dragonmantank/cron-expression": "3.3.2",
"phpmailer/phpmailer": "6.9.1",
Generated
+127 -403
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": "eca74b44aa6dc476aa8056344e87f363",
"content-hash": "51959289a3f882160f5a9eeb605d41d7",
"packages": [
{
"name": "adhocore/jwt",
@@ -157,16 +157,16 @@
},
{
"name": "appwrite/php-runtimes",
"version": "0.18.1",
"version": "0.19.0",
"source": {
"type": "git",
"url": "https://github.com/appwrite/runtimes.git",
"reference": "97b5d97ae2c0fc9a2a374769eadff024f95783aa"
"reference": "8d21483efc19b9d977e323188989ee67a188464b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/runtimes/zipball/97b5d97ae2c0fc9a2a374769eadff024f95783aa",
"reference": "97b5d97ae2c0fc9a2a374769eadff024f95783aa",
"url": "https://api.github.com/repos/appwrite/runtimes/zipball/8d21483efc19b9d977e323188989ee67a188464b",
"reference": "8d21483efc19b9d977e323188989ee67a188464b",
"shasum": ""
},
"require": {
@@ -206,9 +206,9 @@
],
"support": {
"issues": "https://github.com/appwrite/runtimes/issues",
"source": "https://github.com/appwrite/runtimes/tree/0.18.1"
"source": "https://github.com/appwrite/runtimes/tree/0.19.0"
},
"time": "2025-03-11T14:05:46+00:00"
"time": "2025-03-25T22:37:51+00:00"
},
{
"name": "beberlei/assert",
@@ -709,16 +709,16 @@
},
{
"name": "google/protobuf",
"version": "v4.30.1",
"version": "v4.30.2",
"source": {
"type": "git",
"url": "https://github.com/protocolbuffers/protobuf-php.git",
"reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24"
"reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/f29ba8a30dfd940efb3a8a75dc44446539101f24",
"reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24",
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/a4c4d8565b40b9f76debc9dfeb221412eacb8ced",
"reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced",
"shasum": ""
},
"require": {
@@ -747,68 +747,9 @@
"proto"
],
"support": {
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.1"
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.2"
},
"time": "2025-03-13T21:08:17+00:00"
},
{
"name": "jean85/pretty-package-versions",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.1.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Jean85\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alessandro Lai",
"email": "alessandro.lai85@gmail.com"
}
],
"description": "A library to get pretty versions strings of installed dependencies",
"keywords": [
"composer",
"package",
"release",
"versions"
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
},
"time": "2024-11-18T16:19:46+00:00"
"time": "2025-03-26T18:01:50+00:00"
},
{
"name": "league/csv",
@@ -968,75 +909,6 @@
},
"time": "2023-10-02T10:01:54+00:00"
},
{
"name": "mongodb/mongodb",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/mongodb/mongo-php-library.git",
"reference": "b0bbd657f84219212487d01a8ffe93a789e1e488"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488",
"reference": "b0bbd657f84219212487d01a8ffe93a789e1e488",
"shasum": ""
},
"require": {
"ext-hash": "*",
"ext-json": "*",
"ext-mongodb": "^1.11.0",
"jean85/pretty-package-versions": "^1.2 || ^2.0.1",
"php": "^7.1 || ^8.0",
"symfony/polyfill-php80": "^1.19"
},
"require-dev": {
"doctrine/coding-standard": "^9.0",
"squizlabs/php_codesniffer": "^3.6",
"symfony/phpunit-bridge": "^5.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.10.x-dev"
}
},
"autoload": {
"files": [
"src/functions.php"
],
"psr-4": {
"MongoDB\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Andreas Braun",
"email": "andreas.braun@mongodb.com"
},
{
"name": "Jeremy Mikola",
"email": "jmikola@gmail.com"
}
],
"description": "MongoDB driver library",
"homepage": "https://jira.mongodb.org/browse/PHPLIB",
"keywords": [
"database",
"driver",
"mongodb",
"persistence"
],
"support": {
"issues": "https://github.com/mongodb/mongo-php-library/issues",
"source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0"
},
"time": "2021-10-20T22:22:37+00:00"
},
{
"name": "mustangostang/spyc",
"version": "0.6.3",
@@ -1493,16 +1365,16 @@
},
{
"name": "open-telemetry/sdk",
"version": "1.2.2",
"version": "1.2.4",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sdk.git",
"reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0"
"reference": "47fcb66ae5328c5a799195247b1dce551d85873e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/37eec0fe47ddd627911f318f29b6cd48196be0c0",
"reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0",
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/47fcb66ae5328c5a799195247b1dce551d85873e",
"reference": "47fcb66ae5328c5a799195247b1dce551d85873e",
"shasum": ""
},
"require": {
@@ -1579,7 +1451,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
"time": "2025-01-29T21:40:28+00:00"
"time": "2025-04-15T07:02:07+00:00"
},
{
"name": "open-telemetry/sem-conv",
@@ -2371,16 +2243,16 @@
},
{
"name": "ramsey/collection",
"version": "2.1.0",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109"
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
"reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
"url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
"shasum": ""
},
"require": {
@@ -2441,9 +2313,9 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/2.1.0"
"source": "https://github.com/ramsey/collection/tree/2.1.1"
},
"time": "2025-03-02T04:48:29+00:00"
"time": "2025-03-22T05:38:12+00:00"
},
{
"name": "ramsey/uuid",
@@ -2932,86 +2804,6 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"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\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php82",
"version": "v1.31.0",
@@ -3173,16 +2965,16 @@
},
{
"name": "tbachert/spi",
"version": "v1.0.2",
"version": "v1.0.3",
"source": {
"type": "git",
"url": "https://github.com/Nevay/spi.git",
"reference": "2ddfaf815dafb45791a61b08170de8d583c16062"
"reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nevay/spi/zipball/2ddfaf815dafb45791a61b08170de8d583c16062",
"reference": "2ddfaf815dafb45791a61b08170de8d583c16062",
"url": "https://api.github.com/repos/Nevay/spi/zipball/506a79c98e1a51522e76ee921ccb6c62d52faf3a",
"reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a",
"shasum": ""
},
"require": {
@@ -3219,9 +3011,9 @@
],
"support": {
"issues": "https://github.com/Nevay/spi/issues",
"source": "https://github.com/Nevay/spi/tree/v1.0.2"
"source": "https://github.com/Nevay/spi/tree/v1.0.3"
},
"time": "2024-10-04T16:36:12+00:00"
"time": "2025-04-02T19:38:14+00:00"
},
{
"name": "thecodingmachine/safe",
@@ -3559,16 +3351,16 @@
},
{
"name": "utopia-php/cli",
"version": "0.15.1",
"version": "0.15.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cli.git",
"reference": "d69bbe51a6a94dc4e5bcdd542b5938038b985a65"
"reference": "da00ff6b8b29a826a1794002ae43442cdf3a0f5f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/cli/zipball/d69bbe51a6a94dc4e5bcdd542b5938038b985a65",
"reference": "d69bbe51a6a94dc4e5bcdd542b5938038b985a65",
"url": "https://api.github.com/repos/utopia-php/cli/zipball/da00ff6b8b29a826a1794002ae43442cdf3a0f5f",
"reference": "da00ff6b8b29a826a1794002ae43442cdf3a0f5f",
"shasum": ""
},
"require": {
@@ -3602,9 +3394,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cli/issues",
"source": "https://github.com/utopia-php/cli/tree/0.15.1"
"source": "https://github.com/utopia-php/cli/tree/0.15.2"
},
"time": "2024-10-04T13:55:36+00:00"
"time": "2025-04-15T10:08:48+00:00"
},
{
"name": "utopia-php/compression",
@@ -3705,16 +3497,16 @@
},
{
"name": "utopia-php/database",
"version": "0.61.2",
"version": "0.66.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "349fbdf4bc088f7775c7dfb8b80239a617a88436"
"reference": "67d2ab418efba31dc76b3564cf043e2b3f98d027"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/349fbdf4bc088f7775c7dfb8b80239a617a88436",
"reference": "349fbdf4bc088f7775c7dfb8b80239a617a88436",
"url": "https://api.github.com/repos/utopia-php/database/zipball/67d2ab418efba31dc76b3564cf043e2b3f98d027",
"reference": "67d2ab418efba31dc76b3564cf043e2b3f98d027",
"shasum": ""
},
"require": {
@@ -3723,7 +3515,7 @@
"php": ">=8.1",
"utopia-php/cache": "0.12.*",
"utopia-php/framework": "0.33.*",
"utopia-php/mongo": "0.3.*"
"utopia-php/pools": "0.8.*"
},
"require-dev": {
"fakerphp/faker": "1.23.*",
@@ -3755,22 +3547,22 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.61.2"
"source": "https://github.com/utopia-php/database/tree/0.66.0"
},
"time": "2025-03-15T11:47:42+00:00"
"time": "2025-04-16T07:10:27+00:00"
},
{
"name": "utopia-php/detector",
"version": "0.1.2",
"version": "0.1.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/detector.git",
"reference": "8617ea205738743ef3363ad95791139e82ae44d5"
"reference": "895a4147463965b5f9cbc083b764b6476f547879"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/detector/zipball/8617ea205738743ef3363ad95791139e82ae44d5",
"reference": "8617ea205738743ef3363ad95791139e82ae44d5",
"url": "https://api.github.com/repos/utopia-php/detector/zipball/895a4147463965b5f9cbc083b764b6476f547879",
"reference": "895a4147463965b5f9cbc083b764b6476f547879",
"shasum": ""
},
"require": {
@@ -3800,9 +3592,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/detector/issues",
"source": "https://github.com/utopia-php/detector/tree/0.1.2"
"source": "https://github.com/utopia-php/detector/tree/0.1.4"
},
"time": "2025-03-11T13:01:25+00:00"
"time": "2025-04-09T11:50:45+00:00"
},
{
"name": "utopia-php/domains",
@@ -3913,16 +3705,16 @@
},
{
"name": "utopia-php/fetch",
"version": "0.3.1",
"version": "0.4.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/fetch.git",
"reference": "524dd50afa8c64670c4fb18f1df4db9b5bb4b3d0"
"reference": "65095dac14037db0c822fb5e209e5bd3187a0303"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/fetch/zipball/524dd50afa8c64670c4fb18f1df4db9b5bb4b3d0",
"reference": "524dd50afa8c64670c4fb18f1df4db9b5bb4b3d0",
"url": "https://api.github.com/repos/utopia-php/fetch/zipball/65095dac14037db0c822fb5e209e5bd3187a0303",
"reference": "65095dac14037db0c822fb5e209e5bd3187a0303",
"shasum": ""
},
"require": {
@@ -3946,9 +3738,9 @@
"description": "A simple library that provides an interface for making HTTP Requests.",
"support": {
"issues": "https://github.com/utopia-php/fetch/issues",
"source": "https://github.com/utopia-php/fetch/tree/0.3.1"
"source": "https://github.com/utopia-php/fetch/tree/0.4.1"
},
"time": "2025-03-05T18:08:55+00:00"
"time": "2025-04-14T07:34:27+00:00"
},
{
"name": "utopia-php/framework",
@@ -3999,16 +3791,16 @@
},
{
"name": "utopia-php/image",
"version": "0.8.0",
"version": "0.8.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/image.git",
"reference": "dcae5b1c6deb3ff6865f4e68f012b3709c289bca"
"reference": "6c736965177f9a9e71311e22b80cfa88511768e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/image/zipball/dcae5b1c6deb3ff6865f4e68f012b3709c289bca",
"reference": "dcae5b1c6deb3ff6865f4e68f012b3709c289bca",
"url": "https://api.github.com/repos/utopia-php/image/zipball/6c736965177f9a9e71311e22b80cfa88511768e9",
"reference": "6c736965177f9a9e71311e22b80cfa88511768e9",
"shasum": ""
},
"require": {
@@ -4042,9 +3834,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/image/issues",
"source": "https://github.com/utopia-php/image/tree/0.8.0"
"source": "https://github.com/utopia-php/image/tree/0.8.2"
},
"time": "2025-02-20T11:49:03+00:00"
"time": "2025-04-08T11:31:45+00:00"
},
{
"name": "utopia-php/locale",
@@ -4204,16 +3996,16 @@
},
{
"name": "utopia-php/migration",
"version": "0.6.22",
"version": "0.9.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "a0269746bd318ff0993f5aa008675b971689d5b5"
"reference": "f8b54727c7b0abe416a74a2a4c9fa4350c7a59a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/a0269746bd318ff0993f5aa008675b971689d5b5",
"reference": "a0269746bd318ff0993f5aa008675b971689d5b5",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/f8b54727c7b0abe416a74a2a4c9fa4350c7a59a3",
"reference": "f8b54727c7b0abe416a74a2a4c9fa4350c7a59a3",
"shasum": ""
},
"require": {
@@ -4221,7 +4013,7 @@
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=8.1",
"utopia-php/database": "0.61.*",
"utopia-php/database": "0.*.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
@@ -4254,69 +4046,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.6.22"
"source": "https://github.com/utopia-php/migration/tree/0.9.1"
},
"time": "2025-03-13T07:35:55+00:00"
},
{
"name": "utopia-php/mongo",
"version": "0.3.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/mongo.git",
"reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee",
"reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee",
"shasum": ""
},
"require": {
"ext-mongodb": "*",
"mongodb/mongodb": "1.10.0",
"php": ">=8.0"
},
"require-dev": {
"fakerphp/faker": "^1.14",
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.8.*",
"phpunit/phpunit": "^9.4",
"swoole/ide-helper": "4.8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\Mongo\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
},
{
"name": "Wess",
"email": "wess@appwrite.io"
}
],
"description": "A simple library to manage Mongo database",
"keywords": [
"database",
"mongo",
"php",
"upf",
"utopia"
],
"support": {
"issues": "https://github.com/utopia-php/mongo/issues",
"source": "https://github.com/utopia-php/mongo/tree/0.3.1"
},
"time": "2023-09-01T17:25:28+00:00"
"time": "2025-04-17T05:18:58+00:00"
},
{
"name": "utopia-php/orchestration",
@@ -4420,25 +4152,26 @@
},
{
"name": "utopia-php/pools",
"version": "0.5.0",
"version": "0.8.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/pools.git",
"reference": "6f716a213a08db95eda1b5dddfa90983c1834817"
"reference": "05c67aba42eb68ac65489cc1e7fc5db83db2dd4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/pools/zipball/6f716a213a08db95eda1b5dddfa90983c1834817",
"reference": "6f716a213a08db95eda1b5dddfa90983c1834817",
"url": "https://api.github.com/repos/utopia-php/pools/zipball/05c67aba42eb68ac65489cc1e7fc5db83db2dd4d",
"reference": "05c67aba42eb68ac65489cc1e7fc5db83db2dd4d",
"shasum": ""
},
"require": {
"php": ">=8.0"
"php": ">=8.3",
"utopia-php/telemetry": "0.1.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.8.*",
"phpunit/phpunit": "^9.3"
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "11.*"
},
"type": "library",
"autoload": {
@@ -4465,9 +4198,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/pools/issues",
"source": "https://github.com/utopia-php/pools/tree/0.5.0"
"source": "https://github.com/utopia-php/pools/tree/0.8.2"
},
"time": "2024-04-19T11:11:54+00:00"
"time": "2025-04-17T02:04:54+00:00"
},
{
"name": "utopia-php/preloader",
@@ -4524,23 +4257,23 @@
},
{
"name": "utopia-php/queue",
"version": "0.9.0",
"version": "0.9.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/queue.git",
"reference": "077075f1d57afa430f76c35ed3bf4616e0eee8e7"
"reference": "32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/077075f1d57afa430f76c35ed3bf4616e0eee8e7",
"reference": "077075f1d57afa430f76c35ed3bf4616e0eee8e7",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32",
"reference": "32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32",
"shasum": ""
},
"require": {
"php": ">=8.3",
"php-amqplib/php-amqplib": "^3.7",
"utopia-php/cli": "0.15.*",
"utopia-php/fetch": "^0.3.0",
"utopia-php/fetch": "0.4.*",
"utopia-php/framework": "0.33.*",
"utopia-php/telemetry": "0.1.*"
},
@@ -4583,9 +4316,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/queue/issues",
"source": "https://github.com/utopia-php/queue/tree/0.9.0"
"source": "https://github.com/utopia-php/queue/tree/0.9.1"
},
"time": "2025-03-13T12:22:41+00:00"
"time": "2025-03-28T19:49:36+00:00"
},
{
"name": "utopia-php/registry",
@@ -4698,16 +4431,16 @@
},
{
"name": "utopia-php/swoole",
"version": "0.8.2",
"version": "0.8.3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/swoole.git",
"reference": "5fa9d42c608ad46a4ce42a6d2b2eae00592fccd4"
"reference": "1af73dd3e73987cf729c7db399054e4a70befd99"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/swoole/zipball/5fa9d42c608ad46a4ce42a6d2b2eae00592fccd4",
"reference": "5fa9d42c608ad46a4ce42a6d2b2eae00592fccd4",
"url": "https://api.github.com/repos/utopia-php/swoole/zipball/1af73dd3e73987cf729c7db399054e4a70befd99",
"reference": "1af73dd3e73987cf729c7db399054e4a70befd99",
"shasum": ""
},
"require": {
@@ -4743,9 +4476,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/swoole/issues",
"source": "https://github.com/utopia-php/swoole/tree/0.8.2"
"source": "https://github.com/utopia-php/swoole/tree/0.8.3"
},
"time": "2024-02-01T14:54:12+00:00"
"time": "2025-03-26T10:09:05+00:00"
},
{
"name": "utopia-php/system",
@@ -4904,27 +4637,28 @@
},
{
"name": "utopia-php/websocket",
"version": "0.1.0",
"version": "0.3.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/websocket.git",
"reference": "51fcb86171400d8aa40d76c54593481fd273dab5"
"reference": "629e53640b108eab43c7cc9ab375efade8622d43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/websocket/zipball/51fcb86171400d8aa40d76c54593481fd273dab5",
"reference": "51fcb86171400d8aa40d76c54593481fd273dab5",
"url": "https://api.github.com/repos/utopia-php/websocket/zipball/629e53640b108eab43c7cc9ab375efade8622d43",
"reference": "629e53640b108eab43c7cc9ab375efade8622d43",
"shasum": ""
},
"require": {
"php": ">=8.0"
},
"require-dev": {
"laravel/pint": "^1.15",
"phpstan/phpstan": "^1.12",
"phpunit/phpunit": "^9.5.5",
"swoole/ide-helper": "4.6.6",
"swoole/ide-helper": "5.1.2",
"textalk/websocket": "1.5.2",
"vimeo/psalm": "^4.8.1",
"workerman/workerman": "^4.0"
"workerman/workerman": "4.1.*"
},
"type": "library",
"autoload": {
@@ -4936,16 +4670,6 @@
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
},
{
"name": "Torsten Dittmann",
"email": "torsten@appwrite.io"
}
],
"description": "A simple abstraction for WebSocket servers.",
"keywords": [
"framework",
@@ -4956,9 +4680,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/websocket/issues",
"source": "https://github.com/utopia-php/websocket/tree/0.1.0"
"source": "https://github.com/utopia-php/websocket/tree/0.3.0"
},
"time": "2021-12-20T10:50:09+00:00"
"time": "2025-03-28T01:11:13+00:00"
},
{
"name": "webmozart/assert",
@@ -5087,16 +4811,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.40.9",
"version": "0.40.13",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "dbb45a5db22cdc3368fe2573c07ba6088f188fa4"
"reference": "c4bc0ff4589969252b99354368743a99997f0428"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/dbb45a5db22cdc3368fe2573c07ba6088f188fa4",
"reference": "dbb45a5db22cdc3368fe2573c07ba6088f188fa4",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/c4bc0ff4589969252b99354368743a99997f0428",
"reference": "c4bc0ff4589969252b99354368743a99997f0428",
"shasum": ""
},
"require": {
@@ -5132,9 +4856,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/0.40.9"
"source": "https://github.com/appwrite/sdk-generator/tree/0.40.13"
},
"time": "2025-03-17T18:39:14+00:00"
"time": "2025-04-23T11:59:44+00:00"
},
{
"name": "doctrine/annotations",
@@ -5361,16 +5085,16 @@
},
{
"name": "laravel/pint",
"version": "v1.21.2",
"version": "v1.22.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "370772e7d9e9da087678a0edf2b11b6960e40558"
"reference": "7ddfaa6523a675fae5c4123ee38fc6bfb8ee4f36"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/370772e7d9e9da087678a0edf2b11b6960e40558",
"reference": "370772e7d9e9da087678a0edf2b11b6960e40558",
"url": "https://api.github.com/repos/laravel/pint/zipball/7ddfaa6523a675fae5c4123ee38fc6bfb8ee4f36",
"reference": "7ddfaa6523a675fae5c4123ee38fc6bfb8ee4f36",
"shasum": ""
},
"require": {
@@ -5381,9 +5105,9 @@
"php": "^8.2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.72.0",
"friendsofphp/php-cs-fixer": "^3.75.0",
"illuminate/view": "^11.44.2",
"larastan/larastan": "^3.2.0",
"larastan/larastan": "^3.3.1",
"laravel-zero/framework": "^11.36.1",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3",
@@ -5423,7 +5147,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2025-03-14T22:31:42+00:00"
"time": "2025-04-08T22:11:45+00:00"
},
{
"name": "matthiasmullie/minify",
@@ -7525,16 +7249,16 @@
},
{
"name": "symfony/console",
"version": "v7.2.1",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3"
"reference": "e51498ea18570c062e7df29d05a7003585b19b88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
"url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88",
"reference": "e51498ea18570c062e7df29d05a7003585b19b88",
"shasum": ""
},
"require": {
@@ -7598,7 +7322,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.2.1"
"source": "https://github.com/symfony/console/tree/v7.2.5"
},
"funding": [
{
@@ -7614,7 +7338,7 @@
"type": "tidelift"
}
],
"time": "2024-12-11T03:49:26+00:00"
"time": "2025-03-12T08:11:12+00:00"
},
{
"name": "symfony/filesystem",
@@ -8129,16 +7853,16 @@
},
{
"name": "symfony/process",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf"
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d",
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d",
"shasum": ""
},
"require": {
@@ -8170,7 +7894,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.2.4"
"source": "https://github.com/symfony/process/tree/v7.2.5"
},
"funding": [
{
@@ -8186,7 +7910,7 @@
"type": "tidelift"
}
],
"time": "2025-02-05T08:33:46+00:00"
"time": "2025-03-13T12:21:46+00:00"
},
{
"name": "symfony/string",
+37 -15
View File
@@ -72,6 +72,7 @@ services:
- traefik.http.routers.appwrite_api_https.tls=true
volumes:
- appwrite-uploads:/storage/uploads:rw
- appwrite-imports:/storage/imports:rw
- appwrite-cache:/storage/cache:rw
- appwrite-config:/storage/config:rw
- appwrite-certificates:/storage/certificates:rw
@@ -112,10 +113,12 @@ services:
- _APP_OPTIONS_ABUSE
- _APP_OPTIONS_ROUTER_PROTECTION
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_COMPUTE_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_FUNCTIONS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
@@ -160,7 +163,8 @@ services:
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_COMPUTE_SIZE_LIMIT
- _APP_COMPUTE_TIMEOUT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
@@ -175,6 +179,7 @@ services:
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER
@@ -201,11 +206,13 @@ services:
- _APP_DATABASE_SHARED_TABLES_V1
- _APP_DATABASE_SHARED_NAMESPACE
- _APP_FUNCTIONS_CREATION_ABUSE_LIMIT
extra_hosts:
- "host.docker.internal:host-gateway"
appwrite-console:
<<: *x-logging
container_name: appwrite-console
image: appwrite/console:5.3.0-sites-rc.27
image: appwrite/console:5.3.0-sites-rc.40
restart: unless-stopped
networks:
- appwrite
@@ -394,6 +401,8 @@ services:
- _APP_DATABASE_SHARED_TABLES
- _APP_DATABASE_SHARED_TABLES_V1
- _APP_EMAIL_CERTIFICATES
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
appwrite-worker-databases:
entrypoint: worker-databases
@@ -462,13 +471,14 @@ services:
- _APP_VCS_GITHUB_APP_NAME
- _APP_VCS_GITHUB_PRIVATE_KEY
- _APP_VCS_GITHUB_APP_ID
- _APP_COMPUTE_TIMEOUT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
- _APP_COMPUTE_SIZE_LIMIT
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_COMPUTE_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_DOMAIN
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
@@ -494,6 +504,8 @@ services:
- _APP_STORAGE_WASABI_BUCKET
- _APP_DATABASE_SHARED_TABLES
- _APP_DOMAIN_SITES
extra_hosts:
- "host.docker.internal:host-gateway"
appwrite-worker-certificates:
entrypoint: worker-certificates
@@ -515,7 +527,9 @@ services:
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_FUNCTIONS
- _APP_EMAIL_CERTIFICATES
- _APP_REDIS_HOST
@@ -559,7 +573,8 @@ services:
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_COMPUTE_TIMEOUT
- _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
@@ -670,6 +685,7 @@ services:
networks:
- appwrite
volumes:
- appwrite-imports:/storage/imports:rw
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
- ./tests:/usr/src/code/tests
@@ -680,7 +696,9 @@ services:
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_EMAIL_SECURITY
- _APP_REDIS_HOST
- _APP_REDIS_PORT
@@ -712,7 +730,9 @@ services:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_DOMAIN
- _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_FUNCTIONS
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
@@ -729,6 +749,7 @@ services:
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_MAINTENANCE_DELAY
@@ -764,7 +785,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-resources:
entrypoint: worker-stats-resources
<<: *x-logging
@@ -795,7 +816,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-stats-usage:
entrypoint: worker-stats-usage
<<: *x-logging
@@ -858,7 +879,7 @@ services:
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_USAGE_DUAL_WRITING_DBS
appwrite-task-scheduler-functions:
entrypoint: schedule-functions
<<: *x-logging
@@ -961,7 +982,7 @@ services:
hostname: exc1
<<: *x-logging
stop_signal: SIGINT
image: openruntimes/executor:0.7.10
image: openruntimes/executor:0.7.13
restart: unless-stopped
networks:
- appwrite
@@ -1140,8 +1161,9 @@ volumes:
appwrite-redis:
appwrite-cache:
appwrite-uploads:
appwrite-imports:
appwrite-certificates:
appwrite-functions:
appwrite-sites:
appwrite-builds:
appwrite-config:
appwrite-config:
@@ -0,0 +1 @@
Import documents from a CSV file into your Appwrite database. This endpoint allows you to import documents from a CSV file uploaded to Appwrite Storage bucket.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

+11
View File
@@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_28_719)">
<path d="M24.4429 17.4322V22.9096H10.7519C6.76318 22.9096 3.28044 20.7067 1.4171 17.4322C1.14622 16.9561 0.909137 16.4567 0.710264 15.9383C0.319864 14.9225 0.0744552 13.8325 0 12.6952V11.2143C0.0161646 10.9609 0.0416361 10.7094 0.0749451 10.4609C0.143032 9.95105 0.245898 9.45211 0.381093 8.96711C1.66006 4.36909 5.81877 1 10.7519 1C15.6851 1 19.8433 4.36909 21.1223 8.96711H15.2682C14.3072 7.4683 12.6437 6.4774 10.7519 6.4774C8.86017 6.4774 7.19668 7.4683 6.23562 8.96711C5.9427 9.42274 5.71542 9.92516 5.56651 10.4609C5.43425 10.936 5.36371 11.4369 5.36371 11.9548C5.36371 13.5248 6.01324 14.94 7.05463 15.9383C8.01961 16.865 9.32061 17.4322 10.7519 17.4322H24.4429Z" fill="#FD366E" />
<path d="M24.4429 10.4609V15.9383H14.4492C15.4906 14.94 16.1401 13.5248 16.1401 11.9548C16.1401 11.4369 16.0696 10.936 15.9373 10.4609H24.4429Z" fill="#FD366E" />
</g>
<defs>
<clipPath id="clip0_28_719">
<rect width="24" height="24" fill="white" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

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