1
0
Fork 0
mirror of synced 2024-06-02 10:54:44 +12:00

Merge branch 'feat-265-realtime' of https://github.com/appwrite/appwrite into feat-265-realtime-usage

This commit is contained in:
Torsten Dittmann 2021-07-01 10:46:24 +02:00
commit 81cf991695
80 changed files with 2377 additions and 8283 deletions

View file

@ -2,26 +2,47 @@
## Features
- Added file created date to file info on the console
- Added file size to file info on the console
- Refactored Devices page in Console:
- Added support for Android
- Added a new gravity option when croping storage images using the file preview endpoint (#1260)
- Upgraded GEOIP DB file to Jun 2021 release (#1256)
- Added file created date to file info on the console (#1183)
- Added file size to file info on the console (#1183)
- Added internal support for connection pools for improved performance (#1278)
- Added new abstraction for workers executable files (#1276)
- Added a new API in the Users API to allow you to force update your user verification status (#1223)
- Using a fixed commit to avoid breaking changes for imagemagick extenstion (#1274)
- Updated the design of all the email templates (#1225)
- Refactored Devices page in Console: (#1167)
- Renamed *Devices* to *Sessions*
- Add Provider Icon to each Session
- Add Anonymous Account Placeholder
- Upgraded phpmailer version to 6.5.0 (#1317)
- Upgraded telegraf docker image version to v1.2.0
- Added new environment variables to the `telegraf` service:
- Added new environment variables to the `telegraf` service: (#1202)
- _APP_INFLUXDB_HOST
- _APP_INFLUXDB_PORT
- Added new endpoint to get a session based on it's ID (#1294)
## Breaking Changes (Read before upgrading!)
- Renamed `env` param on `/v1/functions` to `runtime` (#1314)
- Renamed `deleteUser` method in all SDKs to `delete` (#1216)
## Bugs
- Fixed bug when removing a project member on the Appwrite console (#1214)
- Fixed bug causing runtimes conflict and hanging executions when max Functions containers limit passed (#1288)
- Fixed 404 error when removing a project member on the Appwrite console (#1214)
- Fixed Swoole buffer output size to allow downloading files bigger than allowed size (#1189)
- Fixed ClamAV status when anti virus is not running (#1188)
- Fixed deleteSession which was removing cookieFallback from the localstorage on any logout instead of current session (#1206)
- Fixed Nepal flag (#1173)
- Fixed a bug in the Twitch OAuth adapter (#1209)
- Fixed missing session object when OAuth session creation event is triggered (#1208)
- Fixed bug where we didn't ignore the email case, converted all emails to lowercase internally (#1243)
- Fixed a console bug where you can't click a user with no name, added a placehoder for anonyomous users (#1220)
## Security
- Fixed potential XSS injection on the console
# Version 0.8.0

View file

@ -15,7 +15,7 @@ RUN composer update --ignore-platform-reqs --optimize-autoloader \
FROM php:8.0-cli-alpine as step1
ENV PHP_REDIS_VERSION=5.3.4 \
PHP_SWOOLE_VERSION=v4.6.6 \
PHP_SWOOLE_VERSION=v4.6.7 \
PHP_IMAGICK_VERSION=master \
PHP_YAML_VERSION=2.2.1 \
PHP_MAXMINDDB_VERSION=v1.10.1

View file

@ -1,6 +1,6 @@
<?php
require_once __DIR__.'/init.php';
require_once __DIR__.'/workers.php';
use Utopia\App;
use Utopia\CLI\CLI;

View file

@ -1481,8 +1481,8 @@ $collections = [
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Env',
'key' => 'env',
'label' => 'Runtime',
'key' => 'runtime',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,7 @@ return [
'introduction' => '',
'default' => 'localhost',
'required' => true,
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.\nYou can use the same value as used for the Appwrite hostname.',
'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' => ''
],
[

View file

@ -254,9 +254,13 @@ App::post('/v1/account/sessions')
$countries = $locale->getText('countries');
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
? $countries[strtoupper($session->getAttribute('countryCode'))]
: $locale->getText('locale.country.unknown');
$session
->setAttribute('current', true)
->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown'))
->setAttribute('countryName', $countryName)
;
$response->dynamic($session, Response::MODEL_SESSION);
@ -753,9 +757,13 @@ App::post('/v1/account/sessions/anonymous')
->setStatusCode(Response::STATUS_CODE_CREATED)
;
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
? $countries[strtoupper($session->getAttribute('countryCode'))]
: $locale->getText('locale.country.unknown');
$session
->setAttribute('current', true)
->setAttribute('countryName', (isset($countries[$session->getAttribute('countryCode')])) ? $countries[$session->getAttribute('countryCode')] : $locale->getText('locale.country.unknown'))
->setAttribute('countryName', $countryName)
;
$response->dynamic($session, Response::MODEL_SESSION);
@ -878,9 +886,11 @@ App::get('/v1/account/sessions')
foreach ($sessions as $key => $session) {
/** @var Document $session */
$session->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
? $countries[strtoupper($session->getAttribute('countryCode'))]
: $locale->getText('locale.country.unknown'));
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
? $countries[strtoupper($session->getAttribute('countryCode'))]
: $locale->getText('locale.country.unknown');
$session->setAttribute('countryName', $countryName);
$session->setAttribute('current', ($current == $session->getId()) ? true : false);
$sessions[$key] = $session;
@ -904,19 +914,20 @@ App::get('/v1/account/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->inject('response')
->inject('register')
->inject('project')
->inject('user')
->inject('locale')
->inject('geodb')
->action(function ($response, $register, $project, $user, $locale, $geodb) {
->inject('app')
->action(function ($response, $project, $user, $locale, $geodb, $app) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Document $user */
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */
/** @var Utopia\App $app */
$adapter = new AuditAdapter($register->get('db'));
$adapter = new AuditAdapter($app->getResource('db'));
$adapter->setNamespace('app_'.$project->getId());
$audit = new Audit($adapter);
@ -968,6 +979,47 @@ App::get('/v1/account/logs')
$response->dynamic(new Document(['logs' => $output]), Response::MODEL_LOG_LIST);
});
App::get('/v1/account/sessions/:sessionId')
->desc('Get Session By ID')
->groups(['api', 'account'])
->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'getSession')
->label('sdk.description', '/docs/references/account/get-session.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_SESSION)
->param('sessionId', null, new UID(), 'Session unique ID. Use the string \'current\' to get the current device session.')
->inject('response')
->inject('user')
->inject('locale')
->inject('projectDB')
->action(function ($sessionId, $response, $user, $locale, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
/** @var Utopia\Locale\Locale $locale */
/** @var Appwrite\Database\Database $projectDB */
$sessionId = ($sessionId === 'current')
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
: $sessionId;
$session = $projectDB->getDocument($sessionId); // get user by session ID
if ($session->isEmpty() || Database::SYSTEM_COLLECTION_SESSIONS != $session->getCollection()) {
throw new Exception('Session not found', 404);
};
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
? $countries[strtoupper($session->getAttribute('countryCode'))]
: $locale->getText('locale.country.unknown');
$session->setAttribute('countryName', $countryName);
$response->dynamic($session, Response::MODEL_SESSION);
});
App::patch('/v1/account/name')
->desc('Update Account Name')
->groups(['api', 'account'])

View file

@ -39,14 +39,14 @@ App::post('/v1/functions')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new ArrayList(new Text(64)), 'An array of strings with execution permissions. By default no user is granted with any execute permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('env', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution enviornment.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
->param('vars', [], new Assoc(), 'Key-value JSON object.', true)
->param('events', [], new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)), 'Events list.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, 900), 'Function maximum execution time in seconds.', true)
->inject('response')
->inject('projectDB')
->action(function ($name, $execute, $env, $vars, $events, $schedule, $timeout, $response, $projectDB) {
->action(function ($name, $execute, $runtime, $vars, $events, $schedule, $timeout, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@ -59,7 +59,7 @@ App::post('/v1/functions')
'dateUpdated' => time(),
'status' => 'disabled',
'name' => $name,
'env' => $env,
'runtime' => $runtime,
'tag' => '',
'vars' => $vars,
'events' => $events,

View file

@ -42,12 +42,11 @@ App::get('/v1/health/db')
->label('sdk.method', 'getDB')
->label('sdk.description', '/docs/references/health/get-db.md')
->inject('response')
->inject('register')
->action(function ($response, $register) {
->inject('app')
->action(function ($response, $app) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Registry\Registry $register */
$register->get('db'); /* @var $db PDO */
/** @var Utopia\App $app */
$app->getResource('db');
$response->json(['status' => 'OK']);
});
@ -61,11 +60,11 @@ App::get('/v1/health/cache')
->label('sdk.method', 'getCache')
->label('sdk.description', '/docs/references/health/get-cache.md')
->inject('response')
->inject('register')
->action(function ($response, $register) {
->inject('app')
->action(function ($response, $app) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Registry\Registry $register */
$register->get('cache'); /* @var $cache Predis\Client */
/** @var Utopia\App $register */
$app->getResource('cache');
$response->json(['status' => 'OK']);
});

View file

@ -242,7 +242,7 @@ App::get('/v1/storage/files/:fileId/preview')
->param('fileId', '', new UID(), 'File unique ID')
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
->param('gravity', Image::GRAVITY_CENTER, new WhiteList([Image::GRAVITY_CENTER, Image::GRAVITY_NORTH, Image::GRAVITY_NORTHWEST, Image::GRAVITY_NORTHEAST, Image::GRAVITY_WEST, Image::GRAVITY_EAST, Image::GRAVITY_SOUTHWEST, Image::GRAVITY_SOUTH, Image::GRAVITY_SOUTHEAST]), 'Image crop gravity', true)
->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of ' . implode(",", Image::getGravityTypes()), true)
->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true)
->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true)

View file

@ -218,7 +218,8 @@ App::delete('/v1/teams/:teamId')
->inject('response')
->inject('projectDB')
->inject('events')
->action(function ($teamId, $response, $projectDB, $events) {
->inject('deletes')
->action(function ($teamId, $response, $projectDB, $events, $deletes) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Appwrite\Event\Event $events */
@ -229,25 +230,15 @@ App::delete('/v1/teams/:teamId')
throw new Exception('Team not found', 404);
}
$memberships = $projectDB->getCollection([
'limit' => 2000, // TODO add members limit
'offset' => 0,
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId='.$teamId,
],
]);
foreach ($memberships as $member) {
if (!$projectDB->deleteDocument($member->getId())) {
throw new Exception('Failed to remove membership for team from DB', 500);
}
}
if (!$projectDB->deleteDocument($teamId)) {
throw new Exception('Failed to remove team from DB', 500);
}
$deletes
->setParam('type', DELETE_TYPE_DOCUMENT)
->setParam('document', $team)
;
$events
->setParam('eventData', $response->output($team, Response::MODEL_TEAM))
;

View file

@ -232,18 +232,18 @@ App::get('/v1/users/:userId/logs')
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('userId', '', new UID(), 'User unique ID.')
->inject('response')
->inject('register')
->inject('project')
->inject('projectDB')
->inject('locale')
->inject('geodb')
->action(function ($userId, $response, $register, $project, $projectDB, $locale, $geodb) {
->inject('app')
->action(function ($userId, $response, $project, $projectDB, $locale, $geodb, $app) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Registry\Registry $register */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */
/** @var Utopia\App $app */
$user = $projectDB->getDocument($userId);
@ -251,7 +251,7 @@ App::get('/v1/users/:userId/logs')
throw new Exception('User not found', 404);
}
$adapter = new AuditAdapter($register->get('db'));
$adapter = new AuditAdapter($app->getResource('db'));
$adapter->setNamespace('app_'.$project->getId());
$audit = new Audit($adapter);

View file

@ -236,26 +236,15 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
$role = Auth::USER_ROLE_APP;
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
Authorization::setRole('role:'.Auth::USER_ROLE_APP);
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
}
}
if ($user->getId()) {
Authorization::setRole('user:'.$user->getId());
foreach (Auth::getRoles($user) as $role) {
Authorization::setRole($role);
}
Authorization::setRole('role:'.$role);
\array_map(function ($node) {
if (isset($node['teamId']) && isset($node['roles'])) {
Authorization::setRole('team:'.$node['teamId']);
foreach ($node['roles'] as $nodeRole) { // Set all team roles
Authorization::setRole('team:'.$node['teamId'].'/'.$nodeRole);
}
}
}, $user->getAttribute('memberships', []));
// TDOO Check if user is root
if (!\in_array($scope, $scopes)) {

View file

@ -1,7 +1,9 @@
<?php
use Appwrite\Auth\Auth;
use Appwrite\Database\Document;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Messaging\Adapter\Realtime;
use Utopia\App;
use Utopia\Exception;
use Utopia\Abuse\Abuse;
@ -9,7 +11,7 @@ use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Storage\Device\Local;
use Utopia\Storage\Storage;
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes) {
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $db) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
@ -21,6 +23,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var Appwrite\Event\Event $functions */
/** @var PDO $db */
Storage::setDevice('files', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId()));
Storage::setDevice('functions', new Local(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId()));
@ -34,9 +37,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
/*
* Abuse Check
*/
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), function () use ($register) {
return $register->get('db');
});
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $db);
$timeLimit->setNamespace('app_'.$project->getId());
$timeLimit
->setParam('{userId}', $user->getId())
@ -111,7 +112,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
->setParam('projectId', $project->getId())
;
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes'], 'api');
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'db'], 'api');
App::init(function ($utopia, $request, $response, $project, $user) {
/** @var Utopia\App $utopia */
@ -167,7 +168,7 @@ App::init(function ($utopia, $request, $response, $project, $user) {
}, ['utopia', 'request', 'response', 'project', 'user'], 'auth');
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $realtime, $mode) {
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $mode) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
@ -176,8 +177,6 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var Appwrite\Event\Realtime $realtime */
/** @var Appwrite\Event\Event $functions */
/** @var bool $mode */
if (!empty($events->getParam('event'))) {
@ -199,12 +198,20 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
->trigger();
if ($project->getId() !== 'console') {
$realtime
->setEvent($events->getParam('event'))
->setUserId($events->getParam('userId'))
->setProject($project->getId())
->setPayload($response->getPayload())
->trigger();
$payload = new Document($response->getPayload());
$target = Realtime::fromPayload($events->getParam('event'), $payload);
Realtime::send(
$project->getId(),
$response->getPayload(),
$events->getParam('event'),
$target['channels'],
$target['permissions'],
[
'permissionsChanged' => $target['permissionsChanged'],
'userId' => $events->getParam('userId')
]
);
}
}
@ -229,4 +236,4 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
;
}
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'realtime', 'mode'], 'api');
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'mode'], 'api');

View file

@ -4,14 +4,14 @@ require_once __DIR__.'/../vendor/autoload.php';
use Appwrite\Database\Validator\Authorization;
use Appwrite\Utopia\Response;
use Utopia\Swoole\Files;
use Utopia\Swoole\Request;
use Swoole\Process;
use Swoole\Http\Server;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Swoole\Files;
use Utopia\Swoole\Request;
$http = new Server("0.0.0.0", App::getEnv('PORT', 80));
@ -75,18 +75,22 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
return;
}
$app = new App('UTC');
$db = $register->get('dbPool')->get();
$redis = $register->get('redisPool')->get();
$register->set('db', function () use (&$db) {
App::setResource('db', function () use (&$db) {
return $db;
});
$register->set('cache', function () use (&$redis) {
App::setResource('cache', function () use (&$redis) {
return $redis;
});
$app = new App('UTC');
App::setResource('app', function() use (&$app) {
return $app;
});
try {
Authorization::cleanRoles();

View file

@ -24,8 +24,6 @@ use Appwrite\Database\Database;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Document;
use Appwrite\Database\Pool\PDOPool;
use Appwrite\Database\Pool\RedisPool;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Event\Event;
use Appwrite\Event\Realtime;
@ -37,6 +35,10 @@ use Utopia\Locale\Locale;
use Utopia\Registry\Registry;
use MaxMind\Db\Reader;
use PHPMailer\PHPMailer\PHPMailer;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Database\RedisConfig;
use Swoole\Database\RedisPool;
const APP_NAME = 'Appwrite';
const APP_DOMAIN = 'appwrite.io';
@ -155,10 +157,21 @@ Database::addFilter('encrypt',
*/
$register->set('dbPool', function () { // Register DB connection
$dbHost = App::getEnv('_APP_DB_HOST', '');
$dbPort = App::getEnv('_APP_DB_PORT', '');
$dbUser = App::getEnv('_APP_DB_USER', '');
$dbPass = App::getEnv('_APP_DB_PASS', '');
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
$pool = new PDOPool(10, $dbHost, $dbScheme, $dbUser, $dbPass);
$pool = new PDOPool((new PDOConfig())
->withHost($dbHost)
->withPort($dbPort)
// ->withUnixSocket('/tmp/mysql.sock')
->withDbName($dbScheme)
->withCharset('utf8mb4')
->withUsername($dbUser)
->withPassword($dbPass)
);
return $pool;
});
@ -167,16 +180,18 @@ $register->set('redisPool', function () {
$redisPort = App::getEnv('_APP_REDIS_PORT', '');
$redisUser = App::getEnv('_APP_REDIS_USER', '');
$redisPass = App::getEnv('_APP_REDIS_PASS', '');
$redisAuth = [];
$redisAuth = '';
if ($redisUser) {
$redisAuth[] = $redisUser;
}
if ($redisPass) {
$redisAuth[] = $redisPass;
if ($redisUser && $redisPass) {
$redisAuth = $redisUser.':'.$redisPass;
}
$pool = new RedisPool(10, $redisHost, $redisPort, $redisAuth);
$pool = new RedisPool((new RedisConfig)
->withHost($redisHost)
->withPort($redisPort)
->withAuth($redisAuth)
->withDbIndex(0)
);
return $pool;
});
@ -327,10 +342,6 @@ App::setResource('events', function($register) {
return new Event('', '');
}, ['register']);
App::setResource('realtime', function($register) {
return new Realtime('', '', []);
}, ['register']);
App::setResource('audits', function($register) {
return new Event(Event::AUDITS_QUEUE_NAME, Event::AUDITS_CLASS_NAME);
}, ['register']);
@ -418,10 +429,9 @@ App::setResource('user', function($mode, $project, $console, $request, $response
if (APP_MODE_ADMIN !== $mode) {
$user = $projectDB->getDocument(Auth::$unique);
}
else {
} else {
$user = $consoleDB->getDocument(Auth::$unique);
$user
->setAttribute('$id', 'admin-'.$user->getAttribute('$id'))
;
@ -436,8 +446,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
if (APP_MODE_ADMIN === $mode) {
if (!empty($user->search('teamId', $project->getAttribute('teamId'), $user->getAttribute('memberships')))) {
Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
}
else {
} else {
$user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]);
}
}
@ -486,23 +495,23 @@ App::setResource('console', function($consoleDB) {
return $consoleDB->getDocument('console');
}, ['consoleDB']);
App::setResource('consoleDB', function($register) {
App::setResource('consoleDB', function($db, $cache) {
$consoleDB = new Database();
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$consoleDB->setNamespace('app_console'); // Should be replaced with param if we want to have parent projects
$consoleDB->setMocks(Config::getParam('collections', []));
return $consoleDB;
}, ['register']);
}, ['db', 'cache']);
App::setResource('projectDB', function($register, $project) {
App::setResource('projectDB', function($db, $cache, $project) {
$projectDB = new Database();
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$projectDB->setNamespace('app_'.$project->getId());
$projectDB->setMocks(Config::getParam('collections', []));
return $projectDB;
}, ['register', 'project']);
}, ['db', 'cache', 'project']);
App::setResource('mode', function($request) {
/** @var Utopia\Swoole\Request $request */

View file

@ -32,6 +32,7 @@ foreach ([
realpath(__DIR__ . '/../vendor/psr/log'),
realpath(__DIR__ . '/../vendor/matomo'),
realpath(__DIR__ . '/../vendor/symfony'),
realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload
] as $key => $value) {
if($value !== false) {
$preloader->ignore($value);

View file

@ -1,39 +1,317 @@
<?php
use Appwrite\Extend\PDO;
use Appwrite\Realtime\Server;
use Appwrite\Auth\Auth;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Database;
use Appwrite\Event\Event;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Network\Validator\Origin;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
use Swoole\Runtime;
use Swoole\Table;
use Swoole\Timer;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Swoole\Request;
use Utopia\Swoole\Response;
use Utopia\WebSocket\Server;
use Utopia\WebSocket\Adapter;
require_once __DIR__ . '/init.php';
Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
$config = [
'package_max_length' => 64000 // Default maximum Package Size (64kb)
];
$adapter = new Adapter\Swoole(port: App::getEnv('PORT', 80));
$adapter->setPackageMaxLength(64000); // Default maximum Package Size (64kb)
$register->set('db', function () {
$dbHost = App::getEnv('_APP_DB_HOST', '');
$dbUser = App::getEnv('_APP_DB_USER', '');
$dbPass = App::getEnv('_APP_DB_PASS', '');
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
$subscriptions = [];
$connections = [];
$pdo = new PDO("mysql:host={$dbHost};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
PDO::ATTR_TIMEOUT => 3, // Seconds
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
));
$stats = new Table(4096, 1);
$stats->column('projectId', Table::TYPE_STRING, 64);
$stats->column('connections', Table::TYPE_INT);
$stats->column('connectionsTotal', Table::TYPE_INT);
$stats->column('messages', Table::TYPE_INT);
$stats->create();
return $pdo;
});
$register->set('cache', function () { // Register cache connection
$redis = new Redis();
$redis->pconnect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
$server = new Server($adapter);
return $redis;
$realtime = new Realtime();
$server->onStart(function () use ($stats) {
Console::success('Server started succefully');
Timer::tick(10000, function () use ($stats) {
foreach ($stats as $projectId => $value) {
if (empty($value['connections']) && empty($value['messages'])) {
continue;
}
$connections = $value['connections'];
$messages = $value['messages'];
$usage = new Event('v1-usage', 'UsageV1');
$usage
->setParam('projectId', $projectId)
->setParam('realtimeConnections', $connections)
->setParam('realtimeMessages', $messages)
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0);
$stats->set($projectId, [
'projectId' => $projectId,
'messages' => 0,
'connections' => 0
]);
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
$usage->trigger();
}
}
});
});
$realtimeServer = new Server($register, port: App::getEnv('PORT', 80), config: $config);
$server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime) {
Console::success('Worker ' . $workerId . ' started succefully');
$attempts = 0;
$start = time();
$redisPool = $register->get('redisPool');
/**
* Sending current connections to project channels on the console project every 5 seconds.
*/
Timer::tick(5000, function () use ($server, $stats, $realtime) {
if ($realtime->hasSubscriber('console', 'role:member', 'project')) {
$payload = [];
foreach ($stats as $projectId => $value) {
$payload[$projectId] = $value['connectionsTotal'];
}
$event = [
'event' => 'stats.connections',
'channels' => ['project'],
'permissions' => ['role:member'],
'timestamp' => time(),
'payload' => $payload
];
$server->send($realtime->getReceivers($event), json_encode($event));
}
});
while ($attempts < 300) {
try {
if ($attempts > 0) {
Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . ').
Attempting restart in 5 seconds (attempt #' . $attempts . ')');
sleep(5); // 5 sec delay between connection attempts
}
$start = time();
/** @var Redis $redis */
$redis = $redisPool->get();
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
if ($redis->ping(true)) {
$attempts = 0;
Console::success('Pub/sub connection established (worker: ' . $workerId . ')');
} else {
Console::error('Pub/sub failed (worker: ' . $workerId . ')');
}
$redis->subscribe(['realtime'], function ($redis, $channel, $payload) use ($server, $workerId, $stats, $register, $realtime) {
$event = json_decode($payload, true);
if ($event['permissionsChanged'] && isset($event['userId'])) {
$projectId = $event['project'];
$userId = $event['userId'];
if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) {
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
} else {
return;
}
$db = $register->get('dbPool')->get();
$cache = $register->get('redisPool')->get();
$projectDB = new Database();
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$projectDB->setNamespace('app_' . $projectId);
$projectDB->setMocks(Config::getParam('collections', []));
$user = $projectDB->getDocument($userId);
$roles = Auth::getRoles($user);
$realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
$register->get('dbPool')->put($db);
$register->get('redisPool')->put($cache);
}
$receivers = $realtime->getReceivers($event);
// Temporarily print debug logs by default for Alpha testing.
// if (App::isDevelopment() && !empty($receivers)) {
if (!empty($receivers)) {
Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers));
Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers));
Console::log("[Debug][Worker {$workerId}] Event: " . $payload);
}
$server->send(
$receivers,
json_encode($event['data'])
);
if (($num = count($receivers)) > 0) {
$stats->incr($event['project'], 'messages', $num);
}
});
} catch (\Throwable $th) {
Console::error('Pub/sub error: ' . $th->getMessage());
$redisPool->put($redis);
$attempts++;
continue;
}
$attempts++;
}
Console::error('Failed to restart pub/sub...');
});
$server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $register, $stats, &$realtime) {
$app = new App('UTC');
$request = new Request($request);
/** @var PDO $db */
$db = $register->get('dbPool')->get();
/** @var Redis $redis */
$redis = $register->get('redisPool')->get();
Console::info("Connection open (user: {$connection})");
App::setResource('db', function () use (&$db) {
return $db;
});
App::setResource('cache', function () use (&$redis) {
return $redis;
});
App::setResource('request', function () use ($request) {
return $request;
});
App::setResource('response', function () {
return new Response(new SwooleResponse());
});
try {
/** @var \Appwrite\Database\Document $user */
$user = $app->getResource('user');
/** @var \Appwrite\Database\Document $project */
$project = $app->getResource('project');
/** @var \Appwrite\Database\Document $console */
$console = $app->getResource('console');
/*
* Project Check
*/
if (empty($project->getId())) {
throw new Exception('Missing or unknown project ID', 1008);
}
/*
* Abuse Check
*
* Abuse limits are connecting 128 times per minute and ip address.
*/
$timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $db);
$timeLimit
->setNamespace('app_' . $project->getId())
->setParam('{ip}', $request->getIP())
->setParam('{url}', $request->getURI());
$abuse = new Abuse($timeLimit);
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
throw new Exception('Too many requests', 1013);
}
/*
* Validate Client Domain - Check to avoid CSRF attack.
* Adding Appwrite API domains to allow XDOMAIN communication.
* Skip this check for non-web platforms which are not required to send an origin header.
*/
$origin = $request->getOrigin();
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
if (!$originValidator->isValid($origin) && $project->getId() !== 'console') {
throw new Exception($originValidator->getDescription(), 1008);
}
$roles = Auth::getRoles($user);
$channels = Realtime::convertChannels($request->getQuery('channels', []), $user);
/**
* Channels Check
*/
if (empty($channels)) {
throw new Exception('Missing channels', 1008);
}
$realtime->subscribe($project->getId(), $connection, $roles, $channels);
$server->send([$connection], json_encode($channels));
$stats->incr($project->getId(), 'connections');
$stats->incr($project->getId(), 'connectionsTotal');
} catch (\Throwable $th) {
$response = [
'code' => $th->getCode(),
'message' => $th->getMessage()
];
// Temporarily print debug logs by default for Alpha testing.
//if (App::isDevelopment()) {
Console::error("[Error] Connection Error");
Console::error("[Error] Code: " . $response['code']);
Console::error("[Error] Message: " . $response['message']);
//}
$server->send([$connection], json_encode($response));
$server->close($connection, $th->getCode());
} finally {
/**
* Put used PDO and Redis Connections back into their pools.
*/
$register->get('dbPool')->put($db);
$register->get('redisPool')->put($redis);
}
});
$server->onMessage(function (int $connection, string $message) use ($server) {
$server->send([$connection], 'Sending messages is not allowed.');
$server->close($connection, 1003);
});
$server->onClose(function (int $connection) use ($realtime, $stats) {
if (array_key_exists($connection, $realtime->connections)) {
$stats->decr($realtime->connections[$connection]['projectId'], 'connectionsTotal');
}
$realtime->unsubscribe($connection);
Console::info('Connection close: ' . $connection);
});
$server->start();

View file

@ -17,13 +17,13 @@ $cli
$consoleDB = new Database();
$consoleDB
->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register))
->setAdapter(new RedisAdapter(new MySQLAdapter($register->get('db'), $register->get('cache')), $register->get('cache')))
->setNamespace('app_console') // Main DB
->setMocks(Config::getParam('collections', []));
$projectDB = new Database();
$projectDB
->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register))
->setAdapter(new RedisAdapter(new MySQLAdapter($register->get('db'), $register->get('cache')), $register->get('cache')))
->setMocks(Config::getParam('collections', []));
$console = $consoleDB->getDocument('console');

View file

@ -28,7 +28,7 @@ $cli
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x'])) {
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x'])) {
throw new Exception('Unknown version given');
}

View file

@ -99,7 +99,8 @@
<input type="hidden" id="collection-read" name="read" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
<input type="hidden" id="collection-write" name="write" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
<input type="hidden" id="collection-rules" name="rules" required data-cast-to="json" value="{}" />
<hr />
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

View file

@ -46,9 +46,9 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
<div class="box margin-bottom-large">
<div class="text-align-center">
<img src="" data-ls-attrs="src=/images/runtimes/{{project-function.env|envLogo}}" alt="Function Env." class="avatar huge margin-top-negative-xxl" />
<img src="" data-ls-attrs="src=/images/runtimes/{{project-function.runtime|runtimeLogo}}" alt="Function Runtime" class="avatar huge margin-top-negative-xxl" />
<p class="text-fade margin-bottom-small" data-ls-bind="{{project-function.env|envName}} {{project-function.env|envVersion}}">
<p class="text-fade margin-bottom-small" data-ls-bind="{{project-function.runtime|runtimeName}} {{project-function.runtime|runtimeVersion}}">
</p>
<div data-ls-if="{{project-function.tag}} !== ''" class="margin-top">
<button data-ls-ui-trigger="execute-now">Execute Now</button> &nbsp; <a data-ls-attrs="href=/console/functions/function/logs?id={{router.params.id}}&project={{router.params.project}}" class="button reverse" style="vertical-align: top;">View Logs</a>

View file

@ -40,14 +40,14 @@ $runtimes = $this->getParam('runtimes', []);
<ul data-ls-loop="project-functions.functions" data-ls-as="function" class="list">
<li class="clear">
<div class="pull-start margin-end avatar-container">
<img src="" data-ls-attrs="src=/images/runtimes/{{function.env|envLogo}}?v=<?php echo APP_CACHE_BUSTER; ?>" alt="Function Env." class="avatar" loading="lazy" width="60" height="60" />
<img src="" data-ls-attrs="src=/images/runtimes/{{function.runtime|runtimeLogo}}?v=<?php echo APP_CACHE_BUSTER; ?>" alt="Function Runtime" class="avatar" loading="lazy" width="60" height="60" />
</div>
<a data-ls-attrs="href=/console/functions/function?id={{function.$id}}&project={{router.params.project}}" class="button pull-end">Settings</a>
<span data-ls-bind="{{function.name}}"></span>
<p class="text-fade margin-bottom-no" data-ls-bind="{{function.env|envName}} {{function.env|envVersion}}"></p>
<p class="text-fade margin-bottom-no" data-ls-bind="{{function.runtime|runtimeName}} {{function.runtime|runtimeVersion}}"></p>
</li>
</ul>
</div>
@ -109,13 +109,15 @@ $runtimes = $this->getParam('runtimes', []);
<label for="name">Name</label>
<input type="text" id="name" name="name" required autocomplete="off" class="margin-bottom" maxlength="128" />
<label for="env">Runtimes</label>
<select name="env" id="env" required class="margin-bottom-xl">
<label for="runtime">Runtimes</label>
<select name="runtime" id="runtime" required class="margin-bottom-xl">
<?php foreach($runtimes as $key => $runtime): ?>
<option value="<?php echo $this->escape($key); ?>"><?php echo $this->escape($runtime['name']); ?> <?php echo $this->escape($runtime['version']); ?></option>
<?php endforeach; ?>
</select>
<input id="execute" name="execute" value="" hidden/>
<footer>
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</footer>

View file

@ -28,8 +28,11 @@ class CertificatesV1 extends Worker
{
global $register;
$db = $register->get('db');
$cache = $register->get('cache');
$consoleDB = new Database();
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$consoleDB->setNamespace('app_console'); // Main DB
$consoleDB->setMocks(Config::getParam('collections', []));

View file

@ -31,7 +31,7 @@ class DeletesV1 extends Worker
public function run(): void
{
$projectId = isset($this->args['projectId']) ? $this->args['projectId'] : '';
$projectId = isset($this->args['projectId']) ? $this->args['projectId'] : '';
$type = $this->args['type'];
switch (strval($type)) {
@ -51,6 +51,9 @@ class DeletesV1 extends Worker
case Database::SYSTEM_COLLECTION_COLLECTIONS:
$this->deleteDocuments($document, $projectId);
break;
case Database::SYSTEM_COLLECTION_TEAMS:
$this->deleteMemberships($document, $projectId);
break;
default:
Console::error('No lazy delete operation available for document of type: '.$document->getCollection());
break;
@ -99,6 +102,14 @@ class DeletesV1 extends Worker
], $this->getProjectDB($projectId));
}
protected function deleteMemberships(Document $document, $projectId) {
// Delete Memberships
$this->deleteByGroup([
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'teamId='.$document->getId(),
], $this->getProjectDB($projectId));
}
protected function deleteProject(Document $document)
{
// Delete all DBs
@ -169,9 +180,7 @@ class DeletesV1 extends Worker
throw new Exception('Failed to delete audit logs. No timestamp provided');
}
$timeLimit = new TimeLimit("", 0, 1, function () use ($register) {
return $register->get('db');
});
$timeLimit = new TimeLimit("", 0, 1, $register->get('db'));
$this->deleteForProjectIds(function($projectId) use ($timeLimit, $timestamp){
$timeLimit->setNamespace('app_'.$projectId);
@ -229,7 +238,7 @@ class DeletesV1 extends Worker
Console::success('Delete code tag: '.$document->getAttribute('path', ''));
}
else {
Console::error('Dailed to delete code tag: '.$document->getAttribute('path', ''));
Console::error('Failed to delete code tag: '.$document->getAttribute('path', ''));
}
});
@ -277,7 +286,6 @@ class DeletesV1 extends Worker
Authorization::disable();
$projects = $this->getConsoleDB()->getCollection([
'limit' => $limit,
'offset' => $count,
'orderType' => 'ASC',
'orderCast' => 'string',
'filters' => [
@ -320,7 +328,6 @@ class DeletesV1 extends Worker
$results = $database->getCollection([
'limit' => $limit,
'offset' => $count,
'orderField' => '$id',
'orderType' => 'ASC',
'orderCast' => 'string',
@ -366,9 +373,12 @@ class DeletesV1 extends Worker
{
global $register;
$db = $register->get('db');
$cache = $register->get('cache');
if($this->consoleDB === null) {
$this->consoleDB = new Database();
$this->consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$this->consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));;
$this->consoleDB->setNamespace('app_console'); // Main DB
$this->consoleDB->setMocks(Config::getParam('collections', []));
}
@ -382,9 +392,12 @@ class DeletesV1 extends Worker
protected function getProjectDB($projectId): Database
{
global $register;
$db = $register->get('db');
$cache = $register->get('cache');
$projectDB = new Database();
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$projectDB->setNamespace('app_'.$projectId); // Main DB
$projectDB->setMocks(Config::getParam('collections', []));

View file

@ -6,8 +6,9 @@ use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Event\Event;
use Appwrite\Event\Realtime;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Resque\Worker;
use Appwrite\Utopia\Response\Model\Execution;
use Cron\CronExpression;
use Swoole\Runtime;
use Utopia\App;
@ -72,9 +73,6 @@ Console::success('Finished warmup in '.$warmupTime.' seconds');
$stdout = '';
$stderr = '';
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
, '', $stdout, $stderr, 30);
$executionStart = \microtime(true);
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
@ -141,6 +139,9 @@ class FunctionsV1 extends Worker
{
global $register;
$db = $register->get('db');
$cache = $register->get('cache');
$projectId = $this->args['projectId'] ?? '';
$functionId = $this->args['functionId'] ?? '';
$webhooks = $this->args['webhooks'] ?? [];
@ -154,7 +155,7 @@ class FunctionsV1 extends Worker
$jwt = $this->args['jwt'] ?? '';
$database = new Database();
$database->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$database->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$database->setNamespace('app_'.$projectId);
$database->setMocks(Config::getParam('collections', []));
@ -332,12 +333,12 @@ class FunctionsV1 extends Worker
Authorization::reset();
$runtime = (isset($runtimes[$function->getAttribute('env', '')]))
? $runtimes[$function->getAttribute('env', '')]
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')]))
? $runtimes[$function->getAttribute('runtime', '')]
: null;
if(\is_null($runtime)) {
throw new Exception('Environment "'.$function->getAttribute('env', '').' is not supported');
throw new Exception('Runtime "'.$function->getAttribute('runtime', '').' is not supported');
}
$vars = \array_merge($function->getAttribute('vars', []), [
@ -481,6 +482,7 @@ class FunctionsV1 extends Worker
throw new Exception('Failed saving execution to DB', 500);
}
$executionModel = new Execution();
$executionUpdate = new Event('v1-webhooks', 'WebhooksV1');
$executionUpdate
@ -488,13 +490,19 @@ class FunctionsV1 extends Worker
->setParam('userId', $userId)
->setParam('webhooks', $webhooks)
->setParam('event', 'functions.executions.update')
->setParam('payload', $execution->getArrayCopy());
->setParam('eventData', $execution->getArrayCopy(array_keys($executionModel->getRules())));
$executionUpdate->trigger();
$realtimeUpdate = new Realtime($projectId, 'functions.executions.update', $execution->getArrayCopy());
$target = Realtime::fromPayload('functions.executions.update', $execution);
$realtimeUpdate->trigger();
Realtime::send(
$projectId,
$execution->getArrayCopy(),
'functions.executions.update',
$target['channels'],
$target['permissions']
);
$usage = new Event('v1-usage', 'UsageV1');
@ -531,7 +539,7 @@ class FunctionsV1 extends Worker
if(\count($list) > $max) {
Console::info('Starting containers cleanup');
\usort($list, function ($item1, $item2) {
\uasort($list, function ($item1, $item2) {
return (int)($item1['appwrite-created'] ?? 0) <=> (int)($item2['appwrite-created'] ?? 0);
});

View file

@ -30,8 +30,11 @@ class TasksV1 extends Worker
{
global $register;
$db = $register->get('db');
$cache = $register->get('cache');
$consoleDB = new Database();
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
$consoleDB->setNamespace('app_console'); // Main DB
$consoleDB->setMocks(Config::getParam('collections', []));

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
REDIS_BACKEND=$REDIS_BACKEND RESQUE_PHP='/usr/src/code/vendor/autoload.php' php /usr/src/code/vendor/bin/resque-scheduler
INTERVAL=1 REDIS_BACKEND=$REDIS_BACKEND RESQUE_PHP='/usr/src/code/vendor/autoload.php' php /usr/src/code/vendor/bin/resque-scheduler

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-audits' APP_INCLUDE='/usr/src/code/app/workers/audits.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=1 QUEUE='v1-audits' APP_INCLUDE='/usr/src/code/app/workers/audits.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-certificates' APP_INCLUDE='/usr/src/code/app/workers/certificates.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=1 QUEUE='v1-certificates' APP_INCLUDE='/usr/src/code/app/workers/certificates.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-deletes' APP_INCLUDE='/usr/src/code/app/workers/deletes.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=1 QUEUE='v1-deletes' APP_INCLUDE='/usr/src/code/app/workers/deletes.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-functions' APP_INCLUDE='/usr/src/code/app/workers/functions.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=0.1 QUEUE='v1-functions' APP_INCLUDE='/usr/src/code/app/workers/functions.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-mails' APP_INCLUDE='/usr/src/code/app/workers/mails.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=1 QUEUE='v1-mails' APP_INCLUDE='/usr/src/code/app/workers/mails.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-tasks' APP_INCLUDE='/usr/src/code/app/workers/tasks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=0.1 QUEUE='v1-tasks' APP_INCLUDE='/usr/src/code/app/workers/tasks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-usage' APP_INCLUDE='/usr/src/code/app/workers/usage.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=1 QUEUE='v1-usage' APP_INCLUDE='/usr/src/code/app/workers/usage.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -7,4 +7,4 @@ else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
QUEUE='v1-webhooks' APP_INCLUDE='/usr/src/code/app/workers/webhooks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
INTERVAL=0.1 QUEUE='v1-webhooks' APP_INCLUDE='/usr/src/code/app/workers/webhooks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -36,10 +36,10 @@
"ext-sockets": "*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.2.*",
"appwrite/php-runtimes": "0.3.*",
"utopia-php/framework": "0.14.*",
"utopia-php/abuse": "0.4.*",
"utopia-php/abuse": "0.5.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.5.*",
"utopia-php/cache": "0.2.*",
@ -51,23 +51,30 @@
"utopia-php/domains": "1.1.*",
"utopia-php/swoole": "0.2.*",
"utopia-php/storage": "0.5.*",
"utopia-php/image": "0.3.*",
"utopia-php/websocket": "dev-fix-adapter-interface",
"utopia-php/image": "0.5.*",
"resque/php-resque": "1.3.6",
"matomo/device-detector": "4.2.2",
"matomo/device-detector": "4.2.3",
"dragonmantank/cron-expression": "3.1.0",
"influxdb/influxdb-php": "1.15.2",
"phpmailer/phpmailer": "6.4.1",
"phpmailer/phpmailer": "6.5.0",
"chillerlan/php-qrcode": "4.3.0",
"adhocore/jwt": "1.1.2",
"slickdeals/statsd": "3.0.2"
"slickdeals/statsd": "3.1.0"
},
"require-dev": {
"appwrite/sdk-generator": "0.10.11",
"swoole/ide-helper": "4.6.6",
"textalk/websocket": "1.5.2",
"phpunit/phpunit": "9.5.4",
"swoole/ide-helper": "4.6.7",
"phpunit/phpunit": "9.5.6",
"vimeo/psalm": "4.7.2"
},
"repositories": [
{
"type": "git",
"url": "https://github.com/utopia-php/websocket.git"
}
],
"provide": {
"ext-phpiredis": "*"
},

192
composer.lock generated
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": "ecfe641507c78e5e886eeece09c01d50",
"content-hash": "9ad1f9e6ce5583eb13ea6ffa9a93cb97",
"packages": [
{
"name": "adhocore/jwt",
@ -115,16 +115,16 @@
},
{
"name": "appwrite/php-runtimes",
"version": "0.2.0",
"version": "0.3.0",
"source": {
"type": "git",
"url": "https://github.com/appwrite/php-runtimes.git",
"reference": "43ec4e91cecb9bba0015ef26ab3736cbee2055f5"
"reference": "39be003cdff22c8447de151921001eb5d3bf2319"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/php-runtimes/zipball/43ec4e91cecb9bba0015ef26ab3736cbee2055f5",
"reference": "43ec4e91cecb9bba0015ef26ab3736cbee2055f5",
"url": "https://api.github.com/repos/appwrite/php-runtimes/zipball/39be003cdff22c8447de151921001eb5d3bf2319",
"reference": "39be003cdff22c8447de151921001eb5d3bf2319",
"shasum": ""
},
"require": {
@ -164,9 +164,9 @@
],
"support": {
"issues": "https://github.com/appwrite/php-runtimes/issues",
"source": "https://github.com/appwrite/php-runtimes/tree/0.2.0"
"source": "https://github.com/appwrite/php-runtimes/tree/0.3.0"
},
"time": "2021-04-22T20:47:42+00:00"
"time": "2021-06-15T07:52:43+00:00"
},
{
"name": "chillerlan/php-qrcode",
@ -715,16 +715,16 @@
},
{
"name": "matomo/device-detector",
"version": "4.2.2",
"version": "4.2.3",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "dc270e7645d286d6f01d516a6634aba8b31ad668"
"reference": "d879f07496d6e6ee89cef5bcd925383d9b0c2cc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/dc270e7645d286d6f01d516a6634aba8b31ad668",
"reference": "dc270e7645d286d6f01d516a6634aba8b31ad668",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/d879f07496d6e6ee89cef5bcd925383d9b0c2cc0",
"reference": "d879f07496d6e6ee89cef5bcd925383d9b0c2cc0",
"shasum": ""
},
"require": {
@ -780,7 +780,7 @@
"source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/"
},
"time": "2021-02-26T07:31:42+00:00"
"time": "2021-05-12T14:14:25+00:00"
},
{
"name": "mustangostang/spyc",
@ -834,16 +834,16 @@
},
{
"name": "phpmailer/phpmailer",
"version": "v6.4.1",
"version": "v6.5.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "9256f12d8fb0cd0500f93b19e18c356906cbed3d"
"reference": "a5b5c43e50b7fba655f793ad27303cd74c57363c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/9256f12d8fb0cd0500f93b19e18c356906cbed3d",
"reference": "9256f12d8fb0cd0500f93b19e18c356906cbed3d",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a5b5c43e50b7fba655f793ad27303cd74c57363c",
"reference": "a5b5c43e50b7fba655f793ad27303cd74c57363c",
"shasum": ""
},
"require": {
@ -898,7 +898,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.4.1"
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.0"
},
"funding": [
{
@ -906,7 +906,7 @@
"type": "github"
}
],
"time": "2021-04-29T12:25:04+00:00"
"time": "2021-06-16T14:33:43+00:00"
},
{
"name": "psr/http-client",
@ -1192,31 +1192,33 @@
},
{
"name": "slickdeals/statsd",
"version": "3.0.2",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/Slickdeals/statsd-php.git",
"reference": "393c6565efbfb23c8296ae3099a62fb6366c6ce3"
"reference": "225588a0a079e145359049f6e5e23eedb1b4c17f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Slickdeals/statsd-php/zipball/393c6565efbfb23c8296ae3099a62fb6366c6ce3",
"reference": "393c6565efbfb23c8296ae3099a62fb6366c6ce3",
"url": "https://api.github.com/repos/Slickdeals/statsd-php/zipball/225588a0a079e145359049f6e5e23eedb1b4c17f",
"reference": "225588a0a079e145359049f6e5e23eedb1b4c17f",
"shasum": ""
},
"require": {
"php": ">= 7.2"
"php": ">= 7.3 || ^8"
},
"replace": {
"domnikl/statsd": "self.version"
},
"require-dev": {
"flyeralarm/php-code-validator": "^2.2",
"phpunit/phpunit": "~8.0",
"vimeo/psalm": "^3.4"
"friendsofphp/php-cs-fixer": "^3.0",
"phpunit/phpunit": "^9",
"vimeo/psalm": "^4.6"
},
"type": "library",
"autoload": {
"psr-4": {
"Domnikl\\Statsd\\": "src/",
"Domnikl\\Test\\Statsd\\": "tests/unit"
"Domnikl\\Statsd\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -1230,7 +1232,7 @@
}
],
"description": "a PHP client for statsd",
"homepage": "https://domnikl.github.com/statsd-php",
"homepage": "https://github.com/Slickdeals/statsd-php",
"keywords": [
"Metrics",
"monitoring",
@ -1239,9 +1241,10 @@
"udp"
],
"support": {
"source": "https://github.com/Slickdeals/statsd-php/tree/3.0.2"
"issues": "https://github.com/Slickdeals/statsd-php/issues",
"source": "https://github.com/Slickdeals/statsd-php/tree/3.1.0"
},
"time": "2020-01-03T14:24:58+00:00"
"time": "2021-06-04T20:33:46+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -1324,16 +1327,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.4.1",
"version": "0.5.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "8b7973aae4b02489bd22ffea45b985608f13b6d9"
"reference": "339c1720e5aa5314276128170463594b81f84760"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/8b7973aae4b02489bd22ffea45b985608f13b6d9",
"reference": "8b7973aae4b02489bd22ffea45b985608f13b6d9",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/339c1720e5aa5314276128170463594b81f84760",
"reference": "339c1720e5aa5314276128170463594b81f84760",
"shasum": ""
},
"require": {
@ -1370,9 +1373,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.4.1"
"source": "https://github.com/utopia-php/abuse/tree/0.5.0"
},
"time": "2021-06-05T14:31:33+00:00"
"time": "2021-06-28T10:11:01+00:00"
},
{
"name": "utopia-php/analytics",
@ -1431,21 +1434,21 @@
},
{
"name": "utopia-php/audit",
"version": "0.5.1",
"version": "0.5.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "154a850170a58667a15e4b65fbabb6cd0b709dd9"
"reference": "57e4f8f932164bdfd48ec32bf8d7d3f1bf7518e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/154a850170a58667a15e4b65fbabb6cd0b709dd9",
"reference": "154a850170a58667a15e4b65fbabb6cd0b709dd9",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/57e4f8f932164bdfd48ec32bf8d7d3f1bf7518e4",
"reference": "57e4f8f932164bdfd48ec32bf8d7d3f1bf7518e4",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=7.1"
"php": ">=7.4"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
@ -1477,9 +1480,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.5.1"
"source": "https://github.com/utopia-php/audit/tree/0.5.2"
},
"time": "2020-12-21T17:28:53+00:00"
"time": "2021-06-23T16:02:40+00:00"
},
{
"name": "utopia-php/cache",
@ -1742,16 +1745,16 @@
},
{
"name": "utopia-php/image",
"version": "0.3.2",
"version": "0.5.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/image.git",
"reference": "2044fdd44d87c4253cfe929cca975fd037461b00"
"reference": "5b4ac25e70a95fa10b39c129b742ac66748d40b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/image/zipball/2044fdd44d87c4253cfe929cca975fd037461b00",
"reference": "2044fdd44d87c4253cfe929cca975fd037461b00",
"url": "https://api.github.com/repos/utopia-php/image/zipball/5b4ac25e70a95fa10b39c129b742ac66748d40b8",
"reference": "5b4ac25e70a95fa10b39c129b742ac66748d40b8",
"shasum": ""
},
"require": {
@ -1789,9 +1792,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/image/issues",
"source": "https://github.com/utopia-php/image/tree/0.3.2"
"source": "https://github.com/utopia-php/image/tree/0.5.0"
},
"time": "2021-06-10T09:16:11+00:00"
"time": "2021-06-25T03:40:03+00:00"
},
{
"name": "utopia-php/locale",
@ -2003,16 +2006,16 @@
},
{
"name": "utopia-php/swoole",
"version": "0.2.3",
"version": "0.2.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/swoole.git",
"reference": "45c42aae7e7d3f9f82bf194c2cfa5499b674aefe"
"reference": "37d8c64b536d6bc7da4f0f5a934a0ec44885abf4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/swoole/zipball/45c42aae7e7d3f9f82bf194c2cfa5499b674aefe",
"reference": "45c42aae7e7d3f9f82bf194c2cfa5499b674aefe",
"url": "https://api.github.com/repos/utopia-php/swoole/zipball/37d8c64b536d6bc7da4f0f5a934a0ec44885abf4",
"reference": "37d8c64b536d6bc7da4f0f5a934a0ec44885abf4",
"shasum": ""
},
"require": {
@ -2053,9 +2056,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/swoole/issues",
"source": "https://github.com/utopia-php/swoole/tree/0.2.3"
"source": "https://github.com/utopia-php/swoole/tree/0.2.4"
},
"time": "2021-03-22T22:39:24+00:00"
"time": "2021-06-22T10:49:24+00:00"
},
{
"name": "utopia-php/system",
@ -2112,6 +2115,53 @@
},
"time": "2021-02-04T14:14:49+00:00"
},
{
"name": "utopia-php/websocket",
"version": "dev-fix-adapter-interface",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/websocket.git",
"reference": "0cff9078e8acdb99f2bb8b30a578d0137bd460de"
},
"require": {
"php": ">=8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5.5",
"swoole/ide-helper": "4.6.6",
"textalk/websocket": "1.5.2",
"vimeo/psalm": "^4.8.1",
"workerman/workerman": "^4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\WebSocket\\": "src/WebSocket"
}
},
"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",
"php",
"upf",
"utopia",
"websocket"
],
"time": "2021-06-29T16:04:32+00:00"
},
{
"name": "webmozart/assert",
"version": "1.10.0",
@ -3817,16 +3867,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.4",
"version": "9.5.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741"
"reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741",
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb",
"reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb",
"shasum": ""
},
"require": {
@ -3856,7 +3906,7 @@
"sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^2.3",
"sebastian/type": "^2.3.4",
"sebastian/version": "^3.0.2"
},
"require-dev": {
@ -3904,7 +3954,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.6"
},
"funding": [
{
@ -3916,7 +3966,7 @@
"type": "github"
}
],
"time": "2021-03-23T07:16:29+00:00"
"time": "2021-06-23T05:14:38+00:00"
},
{
"name": "psr/container",
@ -4932,16 +4982,16 @@
},
{
"name": "swoole/ide-helper",
"version": "4.6.6",
"version": "4.6.7",
"source": {
"type": "git",
"url": "https://github.com/swoole/ide-helper.git",
"reference": "d29d71267f8ed4e4993dc057ca53ffdb5d2703b7"
"reference": "0d1409b8274117addfe64d3ea412812a69807411"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swoole/ide-helper/zipball/d29d71267f8ed4e4993dc057ca53ffdb5d2703b7",
"reference": "d29d71267f8ed4e4993dc057ca53ffdb5d2703b7",
"url": "https://api.github.com/repos/swoole/ide-helper/zipball/0d1409b8274117addfe64d3ea412812a69807411",
"reference": "0d1409b8274117addfe64d3ea412812a69807411",
"shasum": ""
},
"require-dev": {
@ -4964,7 +5014,7 @@
"description": "IDE help files for Swoole.",
"support": {
"issues": "https://github.com/swoole/ide-helper/issues",
"source": "https://github.com/swoole/ide-helper/tree/4.6.6"
"source": "https://github.com/swoole/ide-helper/tree/4.6.7"
},
"funding": [
{
@ -4980,7 +5030,7 @@
"type": "open_collective"
}
],
"time": "2021-04-22T16:38:11+00:00"
"time": "2021-05-14T16:05:16+00:00"
},
{
"name": "symfony/console",
@ -6052,7 +6102,9 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"utopia-php/websocket": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View file

@ -1 +1 @@
Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account account, you need to update its [email and password](/docs/client/account#accountUpdateEmail).
Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](/docs/client/account#accountUpdateEmail) or create an [OAuth2 session](/docs/client/account#accountCreateOAuth2Session).

View file

@ -0,0 +1 @@
Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.

5658
package-lock.json generated

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,195 +1,195 @@
var Appwrite=(function(exports,isomorphicFormData,crossFetch){'use strict';function __awaiter(thisArg,_arguments,P,generator){function adopt(value){return value instanceof P?value:new P(function(resolve){resolve(value);});}
(function(exports,isomorphicFormData,crossFetch){'use strict';function __awaiter(thisArg,_arguments,P,generator){function adopt(value){return value instanceof P?value:new P(function(resolve){resolve(value);});}
return new(P||(P=Promise))(function(resolve,reject){function fulfilled(value){try{step(generator.next(value));}catch(e){reject(e);}}
function rejected(value){try{step(generator["throw"](value));}catch(e){reject(e);}}
function step(result){result.done?resolve(result.value):adopt(result.value).then(fulfilled,rejected);}
step((generator=generator.apply(thisArg,_arguments||[])).next());});}
class AppwriteException extends Error{constructor(message,code=0,response=''){super(message);this.name='AppwriteException';this.message=message;this.code=code;this.response=response;}}
class Appwrite{constructor(){this.config={endpoint:'https://appwrite.io/v1',project:'',key:'',jwt:'',locale:'',mode:'',};this.headers={'x-sdk-version':'appwrite:web:2.0.0','X-Appwrite-Response-Format':'0.8.0',};this.account={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(email,password,name='')=>__awaiter(this,void 0,void 0,function*(){if(email===undefined){throw new AppwriteException('Missing required parameter: "email"');}
if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
class Appwrite{constructor(){this.config={endpoint:'https://appwrite.io/v1',project:'',key:'',jwt:'',locale:'',mode:'',};this.headers={'x-sdk-version':'appwrite:web:2.0.0','X-Appwrite-Response-Format':'0.8.0',};this.account={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/account';let payload={};if(typeof email!=='undefined'){payload['email']=email;}
if(typeof password!=='undefined'){payload['password']=password;}
if(typeof name!=='undefined'){payload['name']=name;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),delete:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateEmail:(email,password)=>__awaiter(this,void 0,void 0,function*(){if(email===undefined){throw new AppwriteException('Missing required parameter: "email"');}
if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),delete:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateEmail:(email,password)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/account/email';let payload={};if(typeof email!=='undefined'){payload['email']=email;}
if(typeof password!=='undefined'){payload['password']=password;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),createJWT:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/jwt';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateName:(name)=>__awaiter(this,void 0,void 0,function*(){if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),createJWT:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/jwt';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateName:(name)=>__awaiter(this,void 0,void 0,function*(){if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/account/name';let payload={};if(typeof name!=='undefined'){payload['name']=name;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updatePassword:(password,oldPassword='')=>__awaiter(this,void 0,void 0,function*(){if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updatePassword:(password,oldPassword)=>__awaiter(this,void 0,void 0,function*(){if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/account/password';let payload={};if(typeof password!=='undefined'){payload['password']=password;}
if(typeof oldPassword!=='undefined'){payload['oldPassword']=oldPassword;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getPrefs:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/prefs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePrefs:(prefs)=>__awaiter(this,void 0,void 0,function*(){if(prefs===undefined){throw new AppwriteException('Missing required parameter: "prefs"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getPrefs:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/prefs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePrefs:(prefs)=>__awaiter(this,void 0,void 0,function*(){if(typeof prefs==='undefined'){throw new AppwriteException('Missing required parameter: "prefs"');}
let path='/account/prefs';let payload={};if(typeof prefs!=='undefined'){payload['prefs']=prefs;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),createRecovery:(email,url)=>__awaiter(this,void 0,void 0,function*(){if(email===undefined){throw new AppwriteException('Missing required parameter: "email"');}
if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),createRecovery:(email,url)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
let path='/account/recovery';let payload={};if(typeof email!=='undefined'){payload['email']=email;}
if(typeof url!=='undefined'){payload['url']=url;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),updateRecovery:(userId,secret,password,passwordAgain)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
if(secret===undefined){throw new AppwriteException('Missing required parameter: "secret"');}
if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
if(passwordAgain===undefined){throw new AppwriteException('Missing required parameter: "passwordAgain"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),updateRecovery:(userId,secret,password,passwordAgain)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof secret==='undefined'){throw new AppwriteException('Missing required parameter: "secret"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
if(typeof passwordAgain==='undefined'){throw new AppwriteException('Missing required parameter: "passwordAgain"');}
let path='/account/recovery';let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
if(typeof secret!=='undefined'){payload['secret']=secret;}
if(typeof password!=='undefined'){payload['password']=password;}
if(typeof passwordAgain!=='undefined'){payload['passwordAgain']=passwordAgain;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),getSessions:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/sessions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createSession:(email,password)=>__awaiter(this,void 0,void 0,function*(){if(email===undefined){throw new AppwriteException('Missing required parameter: "email"');}
if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),getSessions:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/sessions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createSession:(email,password)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/account/sessions';let payload={};if(typeof email!=='undefined'){payload['email']=email;}
if(typeof password!=='undefined'){payload['password']=password;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),deleteSessions:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/sessions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),createAnonymousSession:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/sessions/anonymous';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),createOAuth2Session:(provider,success='https://appwrite.io/auth/oauth2/success',failure='https://appwrite.io/auth/oauth2/failure',scopes=[])=>{if(provider===undefined){throw new AppwriteException('Missing required parameter: "provider"');}
let path='/account/sessions/oauth2/{provider}'.replace('{provider}',provider);let payload={};if(success){payload['success']=success;}
if(failure){payload['failure']=failure;}
if(scopes){payload['scopes']=scopes;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),deleteSessions:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/sessions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),createAnonymousSession:()=>__awaiter(this,void 0,void 0,function*(){let path='/account/sessions/anonymous';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),createOAuth2Session:(provider,success,failure,scopes)=>{if(typeof provider==='undefined'){throw new AppwriteException('Missing required parameter: "provider"');}
let path='/account/sessions/oauth2/{provider}'.replace('{provider}',provider);let payload={};if(typeof success!=='undefined'){payload['success']=success;}
if(typeof failure!=='undefined'){payload['failure']=failure;}
if(typeof scopes!=='undefined'){payload['scopes']=scopes;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
if(typeof window!=='undefined'&&(window===null||window===void 0?void 0:window.location)){window.location.href=uri.toString();}
else{return uri;}},deleteSession:(sessionId)=>__awaiter(this,void 0,void 0,function*(){if(sessionId===undefined){throw new AppwriteException('Missing required parameter: "sessionId"');}
let path='/account/sessions/{sessionId}'.replace('{sessionId}',sessionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),createVerification:(url)=>__awaiter(this,void 0,void 0,function*(){if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
else{return uri;}},deleteSession:(sessionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof sessionId==='undefined'){throw new AppwriteException('Missing required parameter: "sessionId"');}
let path='/account/sessions/{sessionId}'.replace('{sessionId}',sessionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),createVerification:(url)=>__awaiter(this,void 0,void 0,function*(){if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
let path='/account/verification';let payload={};if(typeof url!=='undefined'){payload['url']=url;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),updateVerification:(userId,secret)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
if(secret===undefined){throw new AppwriteException('Missing required parameter: "secret"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),updateVerification:(userId,secret)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof secret==='undefined'){throw new AppwriteException('Missing required parameter: "secret"');}
let path='/account/verification';let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
if(typeof secret!=='undefined'){payload['secret']=secret;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);})};this.avatars={getBrowser:(code,width=100,height=100,quality=100)=>{if(code===undefined){throw new AppwriteException('Missing required parameter: "code"');}
let path='/avatars/browsers/{code}'.replace('{code}',code);let payload={};if(width){payload['width']=width;}
if(height){payload['height']=height;}
if(quality){payload['quality']=quality;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);})};this.avatars={getBrowser:(code,width,height,quality)=>{if(typeof code==='undefined'){throw new AppwriteException('Missing required parameter: "code"');}
let path='/avatars/browsers/{code}'.replace('{code}',code);let payload={};if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
if(typeof quality!=='undefined'){payload['quality']=quality;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getCreditCard:(code,width=100,height=100,quality=100)=>{if(code===undefined){throw new AppwriteException('Missing required parameter: "code"');}
let path='/avatars/credit-cards/{code}'.replace('{code}',code);let payload={};if(width){payload['width']=width;}
if(height){payload['height']=height;}
if(quality){payload['quality']=quality;}
return uri;},getCreditCard:(code,width,height,quality)=>{if(typeof code==='undefined'){throw new AppwriteException('Missing required parameter: "code"');}
let path='/avatars/credit-cards/{code}'.replace('{code}',code);let payload={};if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
if(typeof quality!=='undefined'){payload['quality']=quality;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFavicon:(url)=>{if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
let path='/avatars/favicon';let payload={};if(url){payload['url']=url;}
return uri;},getFavicon:(url)=>{if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
let path='/avatars/favicon';let payload={};if(typeof url!=='undefined'){payload['url']=url;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFlag:(code,width=100,height=100,quality=100)=>{if(code===undefined){throw new AppwriteException('Missing required parameter: "code"');}
let path='/avatars/flags/{code}'.replace('{code}',code);let payload={};if(width){payload['width']=width;}
if(height){payload['height']=height;}
if(quality){payload['quality']=quality;}
return uri;},getFlag:(code,width,height,quality)=>{if(typeof code==='undefined'){throw new AppwriteException('Missing required parameter: "code"');}
let path='/avatars/flags/{code}'.replace('{code}',code);let payload={};if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
if(typeof quality!=='undefined'){payload['quality']=quality;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getImage:(url,width=400,height=400)=>{if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
let path='/avatars/image';let payload={};if(url){payload['url']=url;}
if(width){payload['width']=width;}
if(height){payload['height']=height;}
return uri;},getImage:(url,width,height)=>{if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
let path='/avatars/image';let payload={};if(typeof url!=='undefined'){payload['url']=url;}
if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getInitials:(name='',width=500,height=500,color='',background='')=>{let path='/avatars/initials';let payload={};if(name){payload['name']=name;}
if(width){payload['width']=width;}
if(height){payload['height']=height;}
if(color){payload['color']=color;}
if(background){payload['background']=background;}
return uri;},getInitials:(name,width,height,color,background)=>{let path='/avatars/initials';let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
if(typeof color!=='undefined'){payload['color']=color;}
if(typeof background!=='undefined'){payload['background']=background;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getQR:(text,size=400,margin=1,download=false)=>{if(text===undefined){throw new AppwriteException('Missing required parameter: "text"');}
let path='/avatars/qr';let payload={};if(text){payload['text']=text;}
if(size){payload['size']=size;}
if(margin){payload['margin']=margin;}
if(download){payload['download']=download;}
return uri;},getQR:(text,size,margin,download)=>{if(typeof text==='undefined'){throw new AppwriteException('Missing required parameter: "text"');}
let path='/avatars/qr';let payload={};if(typeof text!=='undefined'){payload['text']=text;}
if(typeof size!=='undefined'){payload['size']=size;}
if(typeof margin!=='undefined'){payload['margin']=margin;}
if(typeof download!=='undefined'){payload['download']=download;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;}};this.database={listCollections:(search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){let path='/database/collections';let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createCollection:(name,read,write,rules)=>__awaiter(this,void 0,void 0,function*(){if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(read===undefined){throw new AppwriteException('Missing required parameter: "read"');}
if(write===undefined){throw new AppwriteException('Missing required parameter: "write"');}
if(rules===undefined){throw new AppwriteException('Missing required parameter: "rules"');}
return uri;}};this.database={listCollections:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/database/collections';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createCollection:(name,read,write,rules)=>__awaiter(this,void 0,void 0,function*(){if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof read==='undefined'){throw new AppwriteException('Missing required parameter: "read"');}
if(typeof write==='undefined'){throw new AppwriteException('Missing required parameter: "write"');}
if(typeof rules==='undefined'){throw new AppwriteException('Missing required parameter: "rules"');}
let path='/database/collections';let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof read!=='undefined'){payload['read']=read;}
if(typeof write!=='undefined'){payload['write']=write;}
if(typeof rules!=='undefined'){payload['rules']=rules;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateCollection:(collectionId,name,read=[],write=[],rules=[])=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateCollection:(collectionId,name,read,write,rules)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof read!=='undefined'){payload['read']=read;}
if(typeof write!=='undefined'){payload['write']=write;}
if(typeof rules!=='undefined'){payload['rules']=rules;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listDocuments:(collectionId,filters=[],limit=25,offset=0,orderField='',orderType='ASC',orderCast='string',search='')=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
let path='/database/collections/{collectionId}/documents'.replace('{collectionId}',collectionId);let payload={};if(filters){payload['filters']=filters;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderField){payload['orderField']=orderField;}
if(orderType){payload['orderType']=orderType;}
if(orderCast){payload['orderCast']=orderCast;}
if(search){payload['search']=search;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createDocument:(collectionId,data,read=[],write=[],parentDocument='',parentProperty='',parentPropertyType='assign')=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(data===undefined){throw new AppwriteException('Missing required parameter: "data"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteCollection:(collectionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
let path='/database/collections/{collectionId}'.replace('{collectionId}',collectionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listDocuments:(collectionId,filters,limit,offset,orderField,orderType,orderCast,search)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
let path='/database/collections/{collectionId}/documents'.replace('{collectionId}',collectionId);let payload={};if(typeof filters!=='undefined'){payload['filters']=filters;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderField!=='undefined'){payload['orderField']=orderField;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
if(typeof orderCast!=='undefined'){payload['orderCast']=orderCast;}
if(typeof search!=='undefined'){payload['search']=search;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createDocument:(collectionId,data,read,write,parentDocument,parentProperty,parentPropertyType)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(typeof data==='undefined'){throw new AppwriteException('Missing required parameter: "data"');}
let path='/database/collections/{collectionId}/documents'.replace('{collectionId}',collectionId);let payload={};if(typeof data!=='undefined'){payload['data']=data;}
if(typeof read!=='undefined'){payload['read']=read;}
if(typeof write!=='undefined'){payload['write']=write;}
if(typeof parentDocument!=='undefined'){payload['parentDocument']=parentDocument;}
if(typeof parentProperty!=='undefined'){payload['parentProperty']=parentProperty;}
if(typeof parentPropertyType!=='undefined'){payload['parentPropertyType']=parentPropertyType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getDocument:(collectionId,documentId)=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(documentId===undefined){throw new AppwriteException('Missing required parameter: "documentId"');}
let path='/database/collections/{collectionId}/documents/{documentId}'.replace('{collectionId}',collectionId).replace('{documentId}',documentId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateDocument:(collectionId,documentId,data,read=[],write=[])=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(documentId===undefined){throw new AppwriteException('Missing required parameter: "documentId"');}
if(data===undefined){throw new AppwriteException('Missing required parameter: "data"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getDocument:(collectionId,documentId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(typeof documentId==='undefined'){throw new AppwriteException('Missing required parameter: "documentId"');}
let path='/database/collections/{collectionId}/documents/{documentId}'.replace('{collectionId}',collectionId).replace('{documentId}',documentId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateDocument:(collectionId,documentId,data,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(typeof documentId==='undefined'){throw new AppwriteException('Missing required parameter: "documentId"');}
if(typeof data==='undefined'){throw new AppwriteException('Missing required parameter: "data"');}
let path='/database/collections/{collectionId}/documents/{documentId}'.replace('{collectionId}',collectionId).replace('{documentId}',documentId);let payload={};if(typeof data!=='undefined'){payload['data']=data;}
if(typeof read!=='undefined'){payload['read']=read;}
if(typeof write!=='undefined'){payload['write']=write;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),deleteDocument:(collectionId,documentId)=>__awaiter(this,void 0,void 0,function*(){if(collectionId===undefined){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(documentId===undefined){throw new AppwriteException('Missing required parameter: "documentId"');}
let path='/database/collections/{collectionId}/documents/{documentId}'.replace('{collectionId}',collectionId).replace('{documentId}',documentId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(name,execute,env,vars={},events=[],schedule='',timeout=15)=>__awaiter(this,void 0,void 0,function*(){if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(execute===undefined){throw new AppwriteException('Missing required parameter: "execute"');}
if(env===undefined){throw new AppwriteException('Missing required parameter: "env"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),deleteDocument:(collectionId,documentId)=>__awaiter(this,void 0,void 0,function*(){if(typeof collectionId==='undefined'){throw new AppwriteException('Missing required parameter: "collectionId"');}
if(typeof documentId==='undefined'){throw new AppwriteException('Missing required parameter: "documentId"');}
let path='/database/collections/{collectionId}/documents/{documentId}'.replace('{collectionId}',collectionId).replace('{documentId}',documentId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.functions={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/functions';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(name,execute,runtime,vars,events,schedule,timeout)=>__awaiter(this,void 0,void 0,function*(){if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof execute==='undefined'){throw new AppwriteException('Missing required parameter: "execute"');}
if(typeof runtime==='undefined'){throw new AppwriteException('Missing required parameter: "runtime"');}
let path='/functions';let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof execute!=='undefined'){payload['execute']=execute;}
if(typeof env!=='undefined'){payload['env']=env;}
if(typeof runtime!=='undefined'){payload['runtime']=runtime;}
if(typeof vars!=='undefined'){payload['vars']=vars;}
if(typeof events!=='undefined'){payload['events']=events;}
if(typeof schedule!=='undefined'){payload['schedule']=schedule;}
if(typeof timeout!=='undefined'){payload['timeout']=timeout;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(functionId)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),update:(functionId,name,execute,vars={},events=[],schedule='',timeout=15)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(execute===undefined){throw new AppwriteException('Missing required parameter: "execute"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(functionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),update:(functionId,name,execute,vars,events,schedule,timeout)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof execute==='undefined'){throw new AppwriteException('Missing required parameter: "execute"');}
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof execute!=='undefined'){payload['execute']=execute;}
if(typeof vars!=='undefined'){payload['vars']=vars;}
if(typeof events!=='undefined'){payload['events']=events;}
if(typeof schedule!=='undefined'){payload['schedule']=schedule;}
if(typeof timeout!=='undefined'){payload['timeout']=timeout;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(functionId)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listExecutions:(functionId,search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createExecution:(functionId,data='')=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(functionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}'.replace('{functionId}',functionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listExecutions:(functionId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createExecution:(functionId,data)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/executions'.replace('{functionId}',functionId);let payload={};if(typeof data!=='undefined'){payload['data']=data;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getExecution:(functionId,executionId)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
if(executionId===undefined){throw new AppwriteException('Missing required parameter: "executionId"');}
let path='/functions/{functionId}/executions/{executionId}'.replace('{functionId}',functionId).replace('{executionId}',executionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateTag:(functionId,tag)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
if(tag===undefined){throw new AppwriteException('Missing required parameter: "tag"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getExecution:(functionId,executionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof executionId==='undefined'){throw new AppwriteException('Missing required parameter: "executionId"');}
let path='/functions/{functionId}/executions/{executionId}'.replace('{functionId}',functionId).replace('{executionId}',executionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateTag:(functionId,tag)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof tag==='undefined'){throw new AppwriteException('Missing required parameter: "tag"');}
let path='/functions/{functionId}/tag'.replace('{functionId}',functionId);let payload={};if(typeof tag!=='undefined'){payload['tag']=tag;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listTags:(functionId,search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTag:(functionId,command,code)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
if(command===undefined){throw new AppwriteException('Missing required parameter: "command"');}
if(code===undefined){throw new AppwriteException('Missing required parameter: "code"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listTags:(functionId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTag:(functionId,command,code)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof command==='undefined'){throw new AppwriteException('Missing required parameter: "command"');}
if(typeof code==='undefined'){throw new AppwriteException('Missing required parameter: "code"');}
let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(typeof command!=='undefined'){payload['command']=command;}
if(typeof code!=='undefined'){payload['code']=code;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'multipart/form-data',},payload);}),getTag:(functionId,tagId)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
if(tagId===undefined){throw new AppwriteException('Missing required parameter: "tagId"');}
let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionId).replace('{tagId}',tagId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteTag:(functionId,tagId)=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
if(tagId===undefined){throw new AppwriteException('Missing required parameter: "tagId"');}
let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionId).replace('{tagId}',tagId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getUsage:(functionId,range='30d')=>__awaiter(this,void 0,void 0,function*(){if(functionId===undefined){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/usage'.replace('{functionId}',functionId);let payload={};if(range){payload['range']=range;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.health={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/health';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getAntiVirus:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/anti-virus';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCache:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/cache';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getDB:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/db';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueCertificates:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/certificates';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueFunctions:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/functions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueTasks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/tasks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueUsage:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/usage';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueWebhooks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/webhooks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getStorageLocal:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/storage/local';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getTime:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/time';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.locale={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getContinents:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/continents';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountries:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesEU:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/eu';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesPhones:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/phones';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCurrencies:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/currencies';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getLanguages:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/languages';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.projects={list:(search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(name,teamId,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId='')=>__awaiter(this,void 0,void 0,function*(){if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'multipart/form-data',},payload);}),getTag:(functionId,tagId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof tagId==='undefined'){throw new AppwriteException('Missing required parameter: "tagId"');}
let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionId).replace('{tagId}',tagId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteTag:(functionId,tagId)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof tagId==='undefined'){throw new AppwriteException('Missing required parameter: "tagId"');}
let path='/functions/{functionId}/tags/{tagId}'.replace('{functionId}',functionId).replace('{tagId}',tagId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getUsage:(functionId,range)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
let path='/functions/{functionId}/usage'.replace('{functionId}',functionId);let payload={};if(typeof range!=='undefined'){payload['range']=range;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.health={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/health';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getAntiVirus:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/anti-virus';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCache:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/cache';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getDB:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/db';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueCertificates:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/certificates';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueFunctions:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/functions';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueLogs:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/logs';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueTasks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/tasks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueUsage:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/usage';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getQueueWebhooks:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/queue/webhooks';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getStorageLocal:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/storage/local';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getTime:()=>__awaiter(this,void 0,void 0,function*(){let path='/health/time';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.locale={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getContinents:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/continents';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountries:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesEU:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/eu';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCountriesPhones:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/countries/phones';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getCurrencies:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/currencies';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getLanguages:()=>__awaiter(this,void 0,void 0,function*(){let path='/locale/languages';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);})};this.projects={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/projects';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(name,teamId,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId)=>__awaiter(this,void 0,void 0,function*(){if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/projects';let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof teamId!=='undefined'){payload['teamId']=teamId;}
if(typeof description!=='undefined'){payload['description']=description;}
@ -201,9 +201,9 @@ if(typeof legalState!=='undefined'){payload['legalState']=legalState;}
if(typeof legalCity!=='undefined'){payload['legalCity']=legalCity;}
if(typeof legalAddress!=='undefined'){payload['legalAddress']=legalAddress;}
if(typeof legalTaxId!=='undefined'){payload['legalTaxId']=legalTaxId;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),update:(projectId,name,description='',logo='',url='',legalName='',legalCountry='',legalState='',legalCity='',legalAddress='',legalTaxId='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),update:(projectId,name,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof description!=='undefined'){payload['description']=description;}
if(typeof logo!=='undefined'){payload['logo']=logo;}
@ -214,75 +214,75 @@ if(typeof legalState!=='undefined'){payload['legalState']=legalState;}
if(typeof legalCity!=='undefined'){payload['legalCity']=legalCity;}
if(typeof legalAddress!=='undefined'){payload['legalAddress']=legalAddress;}
if(typeof legalTaxId!=='undefined'){payload['legalTaxId']=legalTaxId;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),delete:(projectId,password)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),delete:(projectId,password)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/projects/{projectId}'.replace('{projectId}',projectId);let payload={};if(typeof password!=='undefined'){payload['password']=password;}
const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateAuthLimit:(projectId,limit)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(limit===undefined){throw new AppwriteException('Missing required parameter: "limit"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateAuthLimit:(projectId,limit)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof limit==='undefined'){throw new AppwriteException('Missing required parameter: "limit"');}
let path='/projects/{projectId}/auth/limit'.replace('{projectId}',projectId);let payload={};if(typeof limit!=='undefined'){payload['limit']=limit;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updateAuthStatus:(projectId,method,status)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(method===undefined){throw new AppwriteException('Missing required parameter: "method"');}
if(status===undefined){throw new AppwriteException('Missing required parameter: "status"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updateAuthStatus:(projectId,method,status)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof method==='undefined'){throw new AppwriteException('Missing required parameter: "method"');}
if(typeof status==='undefined'){throw new AppwriteException('Missing required parameter: "status"');}
let path='/projects/{projectId}/auth/{method}'.replace('{projectId}',projectId).replace('{method}',method);let payload={};if(typeof status!=='undefined'){payload['status']=status;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listDomains:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/domains'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createDomain:(projectId,domain)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(domain===undefined){throw new AppwriteException('Missing required parameter: "domain"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listDomains:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/domains'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createDomain:(projectId,domain)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof domain==='undefined'){throw new AppwriteException('Missing required parameter: "domain"');}
let path='/projects/{projectId}/domains'.replace('{projectId}',projectId);let payload={};if(typeof domain!=='undefined'){payload['domain']=domain;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getDomain:(projectId,domainId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(domainId===undefined){throw new AppwriteException('Missing required parameter: "domainId"');}
let path='/projects/{projectId}/domains/{domainId}'.replace('{projectId}',projectId).replace('{domainId}',domainId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteDomain:(projectId,domainId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(domainId===undefined){throw new AppwriteException('Missing required parameter: "domainId"');}
let path='/projects/{projectId}/domains/{domainId}'.replace('{projectId}',projectId).replace('{domainId}',domainId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateDomainVerification:(projectId,domainId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(domainId===undefined){throw new AppwriteException('Missing required parameter: "domainId"');}
let path='/projects/{projectId}/domains/{domainId}/verification'.replace('{projectId}',projectId).replace('{domainId}',domainId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listKeys:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/keys'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createKey:(projectId,name,scopes)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(scopes===undefined){throw new AppwriteException('Missing required parameter: "scopes"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getDomain:(projectId,domainId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof domainId==='undefined'){throw new AppwriteException('Missing required parameter: "domainId"');}
let path='/projects/{projectId}/domains/{domainId}'.replace('{projectId}',projectId).replace('{domainId}',domainId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteDomain:(projectId,domainId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof domainId==='undefined'){throw new AppwriteException('Missing required parameter: "domainId"');}
let path='/projects/{projectId}/domains/{domainId}'.replace('{projectId}',projectId).replace('{domainId}',domainId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateDomainVerification:(projectId,domainId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof domainId==='undefined'){throw new AppwriteException('Missing required parameter: "domainId"');}
let path='/projects/{projectId}/domains/{domainId}/verification'.replace('{projectId}',projectId).replace('{domainId}',domainId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listKeys:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/keys'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createKey:(projectId,name,scopes)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof scopes==='undefined'){throw new AppwriteException('Missing required parameter: "scopes"');}
let path='/projects/{projectId}/keys'.replace('{projectId}',projectId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof scopes!=='undefined'){payload['scopes']=scopes;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getKey:(projectId,keyId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(keyId===undefined){throw new AppwriteException('Missing required parameter: "keyId"');}
let path='/projects/{projectId}/keys/{keyId}'.replace('{projectId}',projectId).replace('{keyId}',keyId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateKey:(projectId,keyId,name,scopes)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(keyId===undefined){throw new AppwriteException('Missing required parameter: "keyId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(scopes===undefined){throw new AppwriteException('Missing required parameter: "scopes"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getKey:(projectId,keyId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof keyId==='undefined'){throw new AppwriteException('Missing required parameter: "keyId"');}
let path='/projects/{projectId}/keys/{keyId}'.replace('{projectId}',projectId).replace('{keyId}',keyId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateKey:(projectId,keyId,name,scopes)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof keyId==='undefined'){throw new AppwriteException('Missing required parameter: "keyId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof scopes==='undefined'){throw new AppwriteException('Missing required parameter: "scopes"');}
let path='/projects/{projectId}/keys/{keyId}'.replace('{projectId}',projectId).replace('{keyId}',keyId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof scopes!=='undefined'){payload['scopes']=scopes;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteKey:(projectId,keyId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(keyId===undefined){throw new AppwriteException('Missing required parameter: "keyId"');}
let path='/projects/{projectId}/keys/{keyId}'.replace('{projectId}',projectId).replace('{keyId}',keyId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateOAuth2:(projectId,provider,appId='',secret='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(provider===undefined){throw new AppwriteException('Missing required parameter: "provider"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteKey:(projectId,keyId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof keyId==='undefined'){throw new AppwriteException('Missing required parameter: "keyId"');}
let path='/projects/{projectId}/keys/{keyId}'.replace('{projectId}',projectId).replace('{keyId}',keyId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateOAuth2:(projectId,provider,appId,secret)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof provider==='undefined'){throw new AppwriteException('Missing required parameter: "provider"');}
let path='/projects/{projectId}/oauth2'.replace('{projectId}',projectId);let payload={};if(typeof provider!=='undefined'){payload['provider']=provider;}
if(typeof appId!=='undefined'){payload['appId']=appId;}
if(typeof secret!=='undefined'){payload['secret']=secret;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listPlatforms:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/platforms'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createPlatform:(projectId,type,name,key='',store='',hostname='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(type===undefined){throw new AppwriteException('Missing required parameter: "type"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),listPlatforms:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/platforms'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createPlatform:(projectId,type,name,key,store,hostname)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof type==='undefined'){throw new AppwriteException('Missing required parameter: "type"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/projects/{projectId}/platforms'.replace('{projectId}',projectId);let payload={};if(typeof type!=='undefined'){payload['type']=type;}
if(typeof name!=='undefined'){payload['name']=name;}
if(typeof key!=='undefined'){payload['key']=key;}
if(typeof store!=='undefined'){payload['store']=store;}
if(typeof hostname!=='undefined'){payload['hostname']=hostname;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getPlatform:(projectId,platformId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(platformId===undefined){throw new AppwriteException('Missing required parameter: "platformId"');}
let path='/projects/{projectId}/platforms/{platformId}'.replace('{projectId}',projectId).replace('{platformId}',platformId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePlatform:(projectId,platformId,name,key='',store='',hostname='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(platformId===undefined){throw new AppwriteException('Missing required parameter: "platformId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getPlatform:(projectId,platformId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof platformId==='undefined'){throw new AppwriteException('Missing required parameter: "platformId"');}
let path='/projects/{projectId}/platforms/{platformId}'.replace('{projectId}',projectId).replace('{platformId}',platformId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePlatform:(projectId,platformId,name,key,store,hostname)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof platformId==='undefined'){throw new AppwriteException('Missing required parameter: "platformId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/projects/{projectId}/platforms/{platformId}'.replace('{projectId}',projectId).replace('{platformId}',platformId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof key!=='undefined'){payload['key']=key;}
if(typeof store!=='undefined'){payload['store']=store;}
if(typeof hostname!=='undefined'){payload['hostname']=hostname;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deletePlatform:(projectId,platformId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(platformId===undefined){throw new AppwriteException('Missing required parameter: "platformId"');}
let path='/projects/{projectId}/platforms/{platformId}'.replace('{projectId}',projectId).replace('{platformId}',platformId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listTasks:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/tasks'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTask:(projectId,name,status,schedule,security,httpMethod,httpUrl,httpHeaders=[],httpUser='',httpPass='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(status===undefined){throw new AppwriteException('Missing required parameter: "status"');}
if(schedule===undefined){throw new AppwriteException('Missing required parameter: "schedule"');}
if(security===undefined){throw new AppwriteException('Missing required parameter: "security"');}
if(httpMethod===undefined){throw new AppwriteException('Missing required parameter: "httpMethod"');}
if(httpUrl===undefined){throw new AppwriteException('Missing required parameter: "httpUrl"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deletePlatform:(projectId,platformId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof platformId==='undefined'){throw new AppwriteException('Missing required parameter: "platformId"');}
let path='/projects/{projectId}/platforms/{platformId}'.replace('{projectId}',projectId).replace('{platformId}',platformId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),listTasks:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/tasks'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTask:(projectId,name,status,schedule,security,httpMethod,httpUrl,httpHeaders,httpUser,httpPass)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof status==='undefined'){throw new AppwriteException('Missing required parameter: "status"');}
if(typeof schedule==='undefined'){throw new AppwriteException('Missing required parameter: "schedule"');}
if(typeof security==='undefined'){throw new AppwriteException('Missing required parameter: "security"');}
if(typeof httpMethod==='undefined'){throw new AppwriteException('Missing required parameter: "httpMethod"');}
if(typeof httpUrl==='undefined'){throw new AppwriteException('Missing required parameter: "httpUrl"');}
let path='/projects/{projectId}/tasks'.replace('{projectId}',projectId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof status!=='undefined'){payload['status']=status;}
if(typeof schedule!=='undefined'){payload['schedule']=schedule;}
@ -292,16 +292,16 @@ if(typeof httpUrl!=='undefined'){payload['httpUrl']=httpUrl;}
if(typeof httpHeaders!=='undefined'){payload['httpHeaders']=httpHeaders;}
if(typeof httpUser!=='undefined'){payload['httpUser']=httpUser;}
if(typeof httpPass!=='undefined'){payload['httpPass']=httpPass;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getTask:(projectId,taskId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(taskId===undefined){throw new AppwriteException('Missing required parameter: "taskId"');}
let path='/projects/{projectId}/tasks/{taskId}'.replace('{projectId}',projectId).replace('{taskId}',taskId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateTask:(projectId,taskId,name,status,schedule,security,httpMethod,httpUrl,httpHeaders=[],httpUser='',httpPass='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(taskId===undefined){throw new AppwriteException('Missing required parameter: "taskId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(status===undefined){throw new AppwriteException('Missing required parameter: "status"');}
if(schedule===undefined){throw new AppwriteException('Missing required parameter: "schedule"');}
if(security===undefined){throw new AppwriteException('Missing required parameter: "security"');}
if(httpMethod===undefined){throw new AppwriteException('Missing required parameter: "httpMethod"');}
if(httpUrl===undefined){throw new AppwriteException('Missing required parameter: "httpUrl"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getTask:(projectId,taskId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof taskId==='undefined'){throw new AppwriteException('Missing required parameter: "taskId"');}
let path='/projects/{projectId}/tasks/{taskId}'.replace('{projectId}',projectId).replace('{taskId}',taskId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateTask:(projectId,taskId,name,status,schedule,security,httpMethod,httpUrl,httpHeaders,httpUser,httpPass)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof taskId==='undefined'){throw new AppwriteException('Missing required parameter: "taskId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof status==='undefined'){throw new AppwriteException('Missing required parameter: "status"');}
if(typeof schedule==='undefined'){throw new AppwriteException('Missing required parameter: "schedule"');}
if(typeof security==='undefined'){throw new AppwriteException('Missing required parameter: "security"');}
if(typeof httpMethod==='undefined'){throw new AppwriteException('Missing required parameter: "httpMethod"');}
if(typeof httpUrl==='undefined'){throw new AppwriteException('Missing required parameter: "httpUrl"');}
let path='/projects/{projectId}/tasks/{taskId}'.replace('{projectId}',projectId).replace('{taskId}',taskId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof status!=='undefined'){payload['status']=status;}
if(typeof schedule!=='undefined'){payload['schedule']=schedule;}
@ -311,129 +311,133 @@ if(typeof httpUrl!=='undefined'){payload['httpUrl']=httpUrl;}
if(typeof httpHeaders!=='undefined'){payload['httpHeaders']=httpHeaders;}
if(typeof httpUser!=='undefined'){payload['httpUser']=httpUser;}
if(typeof httpPass!=='undefined'){payload['httpPass']=httpPass;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteTask:(projectId,taskId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(taskId===undefined){throw new AppwriteException('Missing required parameter: "taskId"');}
let path='/projects/{projectId}/tasks/{taskId}'.replace('{projectId}',projectId).replace('{taskId}',taskId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getUsage:(projectId,range='30d')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/usage'.replace('{projectId}',projectId);let payload={};if(range){payload['range']=range;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),listWebhooks:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/webhooks'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createWebhook:(projectId,name,events,url,security,httpUser='',httpPass='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(events===undefined){throw new AppwriteException('Missing required parameter: "events"');}
if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
if(security===undefined){throw new AppwriteException('Missing required parameter: "security"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteTask:(projectId,taskId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof taskId==='undefined'){throw new AppwriteException('Missing required parameter: "taskId"');}
let path='/projects/{projectId}/tasks/{taskId}'.replace('{projectId}',projectId).replace('{taskId}',taskId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getUsage:(projectId,range)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/usage'.replace('{projectId}',projectId);let payload={};if(typeof range!=='undefined'){payload['range']=range;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),listWebhooks:(projectId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
let path='/projects/{projectId}/webhooks'.replace('{projectId}',projectId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createWebhook:(projectId,name,events,url,security,httpUser,httpPass)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof events==='undefined'){throw new AppwriteException('Missing required parameter: "events"');}
if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
if(typeof security==='undefined'){throw new AppwriteException('Missing required parameter: "security"');}
let path='/projects/{projectId}/webhooks'.replace('{projectId}',projectId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof events!=='undefined'){payload['events']=events;}
if(typeof url!=='undefined'){payload['url']=url;}
if(typeof security!=='undefined'){payload['security']=security;}
if(typeof httpUser!=='undefined'){payload['httpUser']=httpUser;}
if(typeof httpPass!=='undefined'){payload['httpPass']=httpPass;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getWebhook:(projectId,webhookId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(webhookId===undefined){throw new AppwriteException('Missing required parameter: "webhookId"');}
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateWebhook:(projectId,webhookId,name,events,url,security,httpUser='',httpPass='')=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(webhookId===undefined){throw new AppwriteException('Missing required parameter: "webhookId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
if(events===undefined){throw new AppwriteException('Missing required parameter: "events"');}
if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
if(security===undefined){throw new AppwriteException('Missing required parameter: "security"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),getWebhook:(projectId,webhookId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof webhookId==='undefined'){throw new AppwriteException('Missing required parameter: "webhookId"');}
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateWebhook:(projectId,webhookId,name,events,url,security,httpUser,httpPass)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof webhookId==='undefined'){throw new AppwriteException('Missing required parameter: "webhookId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
if(typeof events==='undefined'){throw new AppwriteException('Missing required parameter: "events"');}
if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
if(typeof security==='undefined'){throw new AppwriteException('Missing required parameter: "security"');}
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof events!=='undefined'){payload['events']=events;}
if(typeof url!=='undefined'){payload['url']=url;}
if(typeof security!=='undefined'){payload['security']=security;}
if(typeof httpUser!=='undefined'){payload['httpUser']=httpUser;}
if(typeof httpPass!=='undefined'){payload['httpPass']=httpPass;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteWebhook:(projectId,webhookId)=>__awaiter(this,void 0,void 0,function*(){if(projectId===undefined){throw new AppwriteException('Missing required parameter: "projectId"');}
if(webhookId===undefined){throw new AppwriteException('Missing required parameter: "webhookId"');}
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.storage={listFiles:(search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){let path='/storage/files';let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createFile:(file,read=[],write=[])=>__awaiter(this,void 0,void 0,function*(){if(file===undefined){throw new AppwriteException('Missing required parameter: "file"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteWebhook:(projectId,webhookId)=>__awaiter(this,void 0,void 0,function*(){if(typeof projectId==='undefined'){throw new AppwriteException('Missing required parameter: "projectId"');}
if(typeof webhookId==='undefined'){throw new AppwriteException('Missing required parameter: "webhookId"');}
let path='/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}',projectId).replace('{webhookId}',webhookId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);})};this.storage={listFiles:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/files';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createFile:(file,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof file==='undefined'){throw new AppwriteException('Missing required parameter: "file"');}
let path='/storage/files';let payload={};if(typeof file!=='undefined'){payload['file']=file;}
if(typeof read!=='undefined'){payload['read']=read;}
if(typeof write!=='undefined'){payload['write']=write;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'multipart/form-data',},payload);}),getFile:(fileId)=>__awaiter(this,void 0,void 0,function*(){if(fileId===undefined){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateFile:(fileId,read,write)=>__awaiter(this,void 0,void 0,function*(){if(fileId===undefined){throw new AppwriteException('Missing required parameter: "fileId"');}
if(read===undefined){throw new AppwriteException('Missing required parameter: "read"');}
if(write===undefined){throw new AppwriteException('Missing required parameter: "write"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'multipart/form-data',},payload);}),getFile:(fileId)=>__awaiter(this,void 0,void 0,function*(){if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updateFile:(fileId,read,write)=>__awaiter(this,void 0,void 0,function*(){if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
if(typeof read==='undefined'){throw new AppwriteException('Missing required parameter: "read"');}
if(typeof write==='undefined'){throw new AppwriteException('Missing required parameter: "write"');}
let path='/storage/files/{fileId}'.replace('{fileId}',fileId);let payload={};if(typeof read!=='undefined'){payload['read']=read;}
if(typeof write!=='undefined'){payload['write']=write;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteFile:(fileId)=>__awaiter(this,void 0,void 0,function*(){if(fileId===undefined){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getFileDownload:(fileId)=>{if(fileId===undefined){throw new AppwriteException('Missing required parameter: "fileId"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),deleteFile:(fileId)=>__awaiter(this,void 0,void 0,function*(){if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getFileDownload:(fileId)=>{if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}/download'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFilePreview:(fileId,width=0,height=0,quality=100,borderWidth=0,borderColor='',borderRadius=0,opacity=1,rotation=0,background='',output='')=>{if(fileId===undefined){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}/preview'.replace('{fileId}',fileId);let payload={};if(width){payload['width']=width;}
if(height){payload['height']=height;}
if(quality){payload['quality']=quality;}
if(borderWidth){payload['borderWidth']=borderWidth;}
if(borderColor){payload['borderColor']=borderColor;}
if(borderRadius){payload['borderRadius']=borderRadius;}
if(opacity){payload['opacity']=opacity;}
if(rotation){payload['rotation']=rotation;}
if(background){payload['background']=background;}
if(output){payload['output']=output;}
return uri;},getFilePreview:(fileId,width,height,gravity,quality,borderWidth,borderColor,borderRadius,opacity,rotation,background,output)=>{if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}/preview'.replace('{fileId}',fileId);let payload={};if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
if(typeof gravity!=='undefined'){payload['gravity']=gravity;}
if(typeof quality!=='undefined'){payload['quality']=quality;}
if(typeof borderWidth!=='undefined'){payload['borderWidth']=borderWidth;}
if(typeof borderColor!=='undefined'){payload['borderColor']=borderColor;}
if(typeof borderRadius!=='undefined'){payload['borderRadius']=borderRadius;}
if(typeof opacity!=='undefined'){payload['opacity']=opacity;}
if(typeof rotation!=='undefined'){payload['rotation']=rotation;}
if(typeof background!=='undefined'){payload['background']=background;}
if(typeof output!=='undefined'){payload['output']=output;}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFileView:(fileId)=>{if(fileId===undefined){throw new AppwriteException('Missing required parameter: "fileId"');}
return uri;},getFileView:(fileId)=>{if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/files/{fileId}/view'.replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;}};this.teams={list:(search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){let path='/teams';let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(name,roles=["owner"])=>__awaiter(this,void 0,void 0,function*(){if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
return uri;}};this.teams={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/teams';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(name,roles)=>__awaiter(this,void 0,void 0,function*(){if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/teams';let payload={};if(typeof name!=='undefined'){payload['name']=name;}
if(typeof roles!=='undefined'){payload['roles']=roles;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(teamId)=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),update:(teamId,name)=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
if(name===undefined){throw new AppwriteException('Missing required parameter: "name"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(teamId)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),update:(teamId,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
if(typeof name==='undefined'){throw new AppwriteException('Missing required parameter: "name"');}
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};if(typeof name!=='undefined'){payload['name']=name;}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(teamId)=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getMemberships:(teamId,search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/teams/{teamId}/memberships'.replace('{teamId}',teamId);let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createMembership:(teamId,email,roles,url,name='')=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
if(email===undefined){throw new AppwriteException('Missing required parameter: "email"');}
if(roles===undefined){throw new AppwriteException('Missing required parameter: "roles"');}
if(url===undefined){throw new AppwriteException('Missing required parameter: "url"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('put',uri,{'content-type':'application/json',},payload);}),delete:(teamId)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/teams/{teamId}'.replace('{teamId}',teamId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getMemberships:(teamId,search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
let path='/teams/{teamId}/memberships'.replace('{teamId}',teamId);let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createMembership:(teamId,email,roles,url,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof roles==='undefined'){throw new AppwriteException('Missing required parameter: "roles"');}
if(typeof url==='undefined'){throw new AppwriteException('Missing required parameter: "url"');}
let path='/teams/{teamId}/memberships'.replace('{teamId}',teamId);let payload={};if(typeof email!=='undefined'){payload['email']=email;}
if(typeof name!=='undefined'){payload['name']=name;}
if(typeof roles!=='undefined'){payload['roles']=roles;}
if(typeof url!=='undefined'){payload['url']=url;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),updateMembershipRoles:(teamId,membershipId,roles)=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
if(membershipId===undefined){throw new AppwriteException('Missing required parameter: "membershipId"');}
if(roles===undefined){throw new AppwriteException('Missing required parameter: "roles"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),updateMembershipRoles:(teamId,membershipId,roles)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
if(typeof membershipId==='undefined'){throw new AppwriteException('Missing required parameter: "membershipId"');}
if(typeof roles==='undefined'){throw new AppwriteException('Missing required parameter: "roles"');}
let path='/teams/{teamId}/memberships/{membershipId}'.replace('{teamId}',teamId).replace('{membershipId}',membershipId);let payload={};if(typeof roles!=='undefined'){payload['roles']=roles;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),deleteMembership:(teamId,membershipId)=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
if(membershipId===undefined){throw new AppwriteException('Missing required parameter: "membershipId"');}
let path='/teams/{teamId}/memberships/{membershipId}'.replace('{teamId}',teamId).replace('{membershipId}',membershipId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateMembershipStatus:(teamId,membershipId,userId,secret)=>__awaiter(this,void 0,void 0,function*(){if(teamId===undefined){throw new AppwriteException('Missing required parameter: "teamId"');}
if(membershipId===undefined){throw new AppwriteException('Missing required parameter: "membershipId"');}
if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
if(secret===undefined){throw new AppwriteException('Missing required parameter: "secret"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),deleteMembership:(teamId,membershipId)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
if(typeof membershipId==='undefined'){throw new AppwriteException('Missing required parameter: "membershipId"');}
let path='/teams/{teamId}/memberships/{membershipId}'.replace('{teamId}',teamId).replace('{membershipId}',membershipId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateMembershipStatus:(teamId,membershipId,userId,secret)=>__awaiter(this,void 0,void 0,function*(){if(typeof teamId==='undefined'){throw new AppwriteException('Missing required parameter: "teamId"');}
if(typeof membershipId==='undefined'){throw new AppwriteException('Missing required parameter: "membershipId"');}
if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof secret==='undefined'){throw new AppwriteException('Missing required parameter: "secret"');}
let path='/teams/{teamId}/memberships/{membershipId}/status'.replace('{teamId}',teamId).replace('{membershipId}',membershipId);let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
if(typeof secret!=='undefined'){payload['secret']=secret;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};this.users={list:(search='',limit=25,offset=0,orderType='ASC')=>__awaiter(this,void 0,void 0,function*(){let path='/users';let payload={};if(search){payload['search']=search;}
if(limit){payload['limit']=limit;}
if(offset){payload['offset']=offset;}
if(orderType){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(email,password,name='')=>__awaiter(this,void 0,void 0,function*(){if(email===undefined){throw new AppwriteException('Missing required parameter: "email"');}
if(password===undefined){throw new AppwriteException('Missing required parameter: "password"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};this.users={list:(search,limit,offset,orderType)=>__awaiter(this,void 0,void 0,function*(){let path='/users';let payload={};if(typeof search!=='undefined'){payload['search']=search;}
if(typeof limit!=='undefined'){payload['limit']=limit;}
if(typeof offset!=='undefined'){payload['offset']=offset;}
if(typeof orderType!=='undefined'){payload['orderType']=orderType;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/users';let payload={};if(typeof email!=='undefined'){payload['email']=email;}
if(typeof password!=='undefined'){payload['password']=password;}
if(typeof name!=='undefined'){payload['name']=name;}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(userId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),delete:(userId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getLogs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/logs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getPrefs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePrefs:(userId,prefs)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
if(prefs===undefined){throw new AppwriteException('Missing required parameter: "prefs"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('post',uri,{'content-type':'application/json',},payload);}),get:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),delete:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getLogs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/logs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getPrefs:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),updatePrefs:(userId,prefs)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof prefs==='undefined'){throw new AppwriteException('Missing required parameter: "prefs"');}
let path='/users/{userId}/prefs'.replace('{userId}',userId);let payload={};if(typeof prefs!=='undefined'){payload['prefs']=prefs;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getSessions:(userId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/sessions'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteSessions:(userId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/sessions'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),deleteSession:(userId,sessionId)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
if(sessionId===undefined){throw new AppwriteException('Missing required parameter: "sessionId"');}
let path='/users/{userId}/sessions/{sessionId}'.replace('{userId}',userId).replace('{sessionId}',sessionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateStatus:(userId,status)=>__awaiter(this,void 0,void 0,function*(){if(userId===undefined){throw new AppwriteException('Missing required parameter: "userId"');}
if(status===undefined){throw new AppwriteException('Missing required parameter: "status"');}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),getSessions:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/sessions'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),deleteSessions:(userId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
let path='/users/{userId}/sessions'.replace('{userId}',userId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),deleteSession:(userId,sessionId)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof sessionId==='undefined'){throw new AppwriteException('Missing required parameter: "sessionId"');}
let path='/users/{userId}/sessions/{sessionId}'.replace('{userId}',userId).replace('{sessionId}',sessionId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),updateStatus:(userId,status)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof status==='undefined'){throw new AppwriteException('Missing required parameter: "status"');}
let path='/users/{userId}/status'.replace('{userId}',userId);let payload={};if(typeof status!=='undefined'){payload['status']=status;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);}),updateVerification:(userId,emailVerification)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof emailVerification==='undefined'){throw new AppwriteException('Missing required parameter: "emailVerification"');}
let path='/users/{userId}/verification'.replace('{userId}',userId);let payload={};if(typeof emailVerification!=='undefined'){payload['emailVerification']=emailVerification;}
const uri=new URL(this.config.endpoint+path);return yield this.call('patch',uri,{'content-type':'application/json',},payload);})};}
setEndpoint(endpoint){this.config.endpoint=endpoint;return this;}
setProject(value){this.headers['X-Appwrite-Project']=value;this.config.project=value;return this;}
@ -455,7 +459,7 @@ catch(e){throw new AppwriteException(e.message);}});}
flatten(data,prefix=''){let output={};for(const key in data){let value=data[key];let finalKey=prefix?`${prefix}[${key}]`:key;if(Array.isArray(value)){output=Object.assign(output,this.flatten(value,finalKey));}
else{output[finalKey]=value;}}
return output;}}
exports.Appwrite=Appwrite;return exports;}({},null,window));(function(global,factory){typeof exports==='object'&&typeof module!=='undefined'?module.exports=factory(function(){try{return require('moment');}catch(e){}}()):typeof define==='function'&&define.amd?define(['require'],function(require){return factory(function(){try{return require('moment');}catch(e){}}());}):(global=global||self,global.Chart=factory(global.moment));}(this,(function(moment){'use strict';moment=moment&&moment.hasOwnProperty('default')?moment['default']:moment;function createCommonjsModule(fn,module){return module={exports:{}},fn(module,module.exports),module.exports;}
exports.Appwrite=Appwrite;Object.defineProperty(exports,'__esModule',{value:true});}(this.window=this.window||{},null,window));(function(global,factory){typeof exports==='object'&&typeof module!=='undefined'?module.exports=factory(function(){try{return require('moment');}catch(e){}}()):typeof define==='function'&&define.amd?define(['require'],function(require){return factory(function(){try{return require('moment');}catch(e){}}());}):(global=global||self,global.Chart=factory(global.moment));}(this,(function(moment){'use strict';moment=moment&&moment.hasOwnProperty('default')?moment['default']:moment;function createCommonjsModule(fn,module){return module={exports:{}},fn(module,module.exports),module.exports;}
function getCjsExportFromNamespace(n){return n&&n['default']||n;}
var colorName={"aliceblue":[240,248,255],"antiquewhite":[250,235,215],"aqua":[0,255,255],"aquamarine":[127,255,212],"azure":[240,255,255],"beige":[245,245,220],"bisque":[255,228,196],"black":[0,0,0],"blanchedalmond":[255,235,205],"blue":[0,0,255],"blueviolet":[138,43,226],"brown":[165,42,42],"burlywood":[222,184,135],"cadetblue":[95,158,160],"chartreuse":[127,255,0],"chocolate":[210,105,30],"coral":[255,127,80],"cornflowerblue":[100,149,237],"cornsilk":[255,248,220],"crimson":[220,20,60],"cyan":[0,255,255],"darkblue":[0,0,139],"darkcyan":[0,139,139],"darkgoldenrod":[184,134,11],"darkgray":[169,169,169],"darkgreen":[0,100,0],"darkgrey":[169,169,169],"darkkhaki":[189,183,107],"darkmagenta":[139,0,139],"darkolivegreen":[85,107,47],"darkorange":[255,140,0],"darkorchid":[153,50,204],"darkred":[139,0,0],"darksalmon":[233,150,122],"darkseagreen":[143,188,143],"darkslateblue":[72,61,139],"darkslategray":[47,79,79],"darkslategrey":[47,79,79],"darkturquoise":[0,206,209],"darkviolet":[148,0,211],"deeppink":[255,20,147],"deepskyblue":[0,191,255],"dimgray":[105,105,105],"dimgrey":[105,105,105],"dodgerblue":[30,144,255],"firebrick":[178,34,34],"floralwhite":[255,250,240],"forestgreen":[34,139,34],"fuchsia":[255,0,255],"gainsboro":[220,220,220],"ghostwhite":[248,248,255],"gold":[255,215,0],"goldenrod":[218,165,32],"gray":[128,128,128],"green":[0,128,0],"greenyellow":[173,255,47],"grey":[128,128,128],"honeydew":[240,255,240],"hotpink":[255,105,180],"indianred":[205,92,92],"indigo":[75,0,130],"ivory":[255,255,240],"khaki":[240,230,140],"lavender":[230,230,250],"lavenderblush":[255,240,245],"lawngreen":[124,252,0],"lemonchiffon":[255,250,205],"lightblue":[173,216,230],"lightcoral":[240,128,128],"lightcyan":[224,255,255],"lightgoldenrodyellow":[250,250,210],"lightgray":[211,211,211],"lightgreen":[144,238,144],"lightgrey":[211,211,211],"lightpink":[255,182,193],"lightsalmon":[255,160,122],"lightseagreen":[32,178,170],"lightskyblue":[135,206,250],"lightslategray":[119,136,153],"lightslategrey":[119,136,153],"lightsteelblue":[176,196,222],"lightyellow":[255,255,224],"lime":[0,255,0],"limegreen":[50,205,50],"linen":[250,240,230],"magenta":[255,0,255],"maroon":[128,0,0],"mediumaquamarine":[102,205,170],"mediumblue":[0,0,205],"mediumorchid":[186,85,211],"mediumpurple":[147,112,219],"mediumseagreen":[60,179,113],"mediumslateblue":[123,104,238],"mediumspringgreen":[0,250,154],"mediumturquoise":[72,209,204],"mediumvioletred":[199,21,133],"midnightblue":[25,25,112],"mintcream":[245,255,250],"mistyrose":[255,228,225],"moccasin":[255,228,181],"navajowhite":[255,222,173],"navy":[0,0,128],"oldlace":[253,245,230],"olive":[128,128,0],"olivedrab":[107,142,35],"orange":[255,165,0],"orangered":[255,69,0],"orchid":[218,112,214],"palegoldenrod":[238,232,170],"palegreen":[152,251,152],"paleturquoise":[175,238,238],"palevioletred":[219,112,147],"papayawhip":[255,239,213],"peachpuff":[255,218,185],"peru":[205,133,63],"pink":[255,192,203],"plum":[221,160,221],"powderblue":[176,224,230],"purple":[128,0,128],"rebeccapurple":[102,51,153],"red":[255,0,0],"rosybrown":[188,143,143],"royalblue":[65,105,225],"saddlebrown":[139,69,19],"salmon":[250,128,114],"sandybrown":[244,164,96],"seagreen":[46,139,87],"seashell":[255,245,238],"sienna":[160,82,45],"silver":[192,192,192],"skyblue":[135,206,235],"slateblue":[106,90,205],"slategray":[112,128,144],"slategrey":[112,128,144],"snow":[255,250,250],"springgreen":[0,255,127],"steelblue":[70,130,180],"tan":[210,180,140],"teal":[0,128,128],"thistle":[216,191,216],"tomato":[255,99,71],"turquoise":[64,224,208],"violet":[238,130,238],"wheat":[245,222,179],"white":[255,255,255],"whitesmoke":[245,245,245],"yellow":[255,255,0],"yellowgreen":[154,205,50]};var conversions=createCommonjsModule(function(module){var reverseKeywords={};for(var key in colorName){if(colorName.hasOwnProperty(key)){reverseKeywords[colorName[key]]=key;}}
var convert=module.exports={rgb:{channels:3,labels:'rgb'},hsl:{channels:3,labels:'hsl'},hsv:{channels:3,labels:'hsv'},hwb:{channels:3,labels:'hwb'},cmyk:{channels:4,labels:'cmyk'},xyz:{channels:3,labels:'xyz'},lab:{channels:3,labels:'lab'},lch:{channels:3,labels:'lch'},hex:{channels:1,labels:['hex']},keyword:{channels:1,labels:['keyword']},ansi16:{channels:1,labels:['ansi16']},ansi256:{channels:1,labels:['ansi256']},hcg:{channels:3,labels:['h','c','g']},apple:{channels:3,labels:['r16','g16','b16']},gray:{channels:1,labels:['gray']}};for(var model in convert){if(convert.hasOwnProperty(model)){if(!('channels'in convert[model])){throw new Error('missing channels property: '+model);}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because it is too large Load diff

View file

@ -234,21 +234,21 @@ window.ls.filter
return $value.join(", ").replace(/,\s([^,]+)$/, ' and $1');
})
.add("envName", function($value, env) {
.add("runtimeName", function($value, env) {
if(env && env.RUNTIMES && env.RUNTIMES[$value]) {
return env.RUNTIMES[$value].name;
}
return '';
})
.add("envLogo", function($value, env) {
.add("runtimeLogo", function($value, env) {
if(env && env.RUNTIMES && env.RUNTIMES[$value]) {
return env.RUNTIMES[$value].logo;
}
return '';
})
.add("envVersion", function($value, env) {
.add("runtimeVersion", function($value, env) {
if(env && env.RUNTIMES && env.RUNTIMES[$value]) {
return env.RUNTIMES[$value].version;
}

View file

@ -2,7 +2,7 @@
"use strict";
window.ls.container.set('console', function (window) {
var sdk = new window.Appwrite.Appwrite();
var sdk = new window.Appwrite();
sdk
.setEndpoint(APP_ENV.ENDPOINT + APP_ENV.API)

View file

@ -2,7 +2,7 @@
"use strict";
window.ls.container.set('sdk', function (window, router) {
var sdk = new window.Appwrite.Appwrite();
var sdk = new window.Appwrite();
sdk
.setEndpoint(APP_ENV.ENDPOINT + APP_ENV.API)

View file

@ -257,7 +257,7 @@
args.map(function(value) {
let result = getValue(value, prefix, data);
return result;
return result ?? undefined;
})
);
};

View file

@ -66,6 +66,12 @@
--config-language-dart-contrast: #ffffff;
--config-language-flutter: #035698;
--config-language-flutter-contrast: #ffffff;
--config-language-android: #a4c439;
--config-language-android-contrast: #ffffff;
--config-language-kotlin: #766DB2;
--config-language-kotlin-contrast: #ffffff;
--config-language-java: #0074bd;
--config-language-java-contrast: #ffffff;
--config-modal-note-background: #f5fbff;
--config-modal-note-border: #eaf2f7;
--config-modal-note-color: #3b5d73;

View file

@ -271,4 +271,32 @@ class Auth
return false;
}
/**
* Returns all roles for a user.
*
* @param Document $user
* @return array
*/
public static function getRoles(Document $user): array
{
if ($user->getId()) {
$roles[] = 'user:'.$user->getId();
$roles[] = 'role:'.Auth::USER_ROLE_MEMBER;
} else {
return ['role:'.Auth::USER_ROLE_GUEST];
}
foreach ($user->getAttribute('memberships', []) as $node) {
if (isset($node['teamId']) && isset($node['roles'])) {
$roles[] = 'team:' . $node['teamId'];
foreach ($node['roles'] as $nodeRole) { // Set all team roles
$roles[] = 'team:' . $node['teamId'] . '/' . $nodeRole;
}
}
}
return $roles;
}
}

View file

@ -2,13 +2,12 @@
namespace Appwrite\Database\Adapter;
use Utopia\Registry\Registry;
use Appwrite\Database\Adapter;
use Appwrite\Database\Exception\Duplicate;
use Appwrite\Database\Validator\Authorization;
use Exception;
use PDO;
use Redis as Client;
use Redis;
class MySQL extends Adapter
{
@ -23,11 +22,6 @@ class MySQL extends Adapter
const OPTIONS_LIMIT_ATTRIBUTES = 1000;
/**
* @var Registry
*/
protected $register;
/**
* Last modified.
*
@ -42,16 +36,28 @@ class MySQL extends Adapter
*/
protected $debug = [];
/**
* @var PDO
*/
protected $pdo;
/**
* @var Redis
*/
protected $redis;
/**
* Constructor.
*
* Set connection and settings
*
* @param Registry $register
* @param PDO $pdo
* @param Redis $redis
*/
public function __construct(Registry $register)
public function __construct($pdo, Redis $redis)
{
$this->register = $register;
$this->pdo = $pdo;
$this->redis = $redis;
}
/**
@ -87,8 +93,8 @@ class MySQL extends Adapter
ORDER BY `order`
');
$st->bindParam(':documentUid', $document['uid'], PDO::PARAM_STR);
$st->bindParam(':documentRevision', $document['revision'], PDO::PARAM_STR);
$st->bindParam(':documentUid', $document['uid'], PDO::PARAM_STR, 32);
$st->bindParam(':documentRevision', $document['revision'], PDO::PARAM_STR, 32);
$st->execute();
@ -116,8 +122,8 @@ class MySQL extends Adapter
ORDER BY `order`
');
$st->bindParam(':start', $document['uid'], PDO::PARAM_STR);
$st->bindParam(':revision', $document['revision'], PDO::PARAM_STR);
$st->bindParam(':start', $document['uid'], PDO::PARAM_STR, 32);
$st->bindParam(':revision', $document['revision'], PDO::PARAM_STR, 32);
$st->execute();
@ -933,18 +939,18 @@ class MySQL extends Adapter
*
* @throws Exception
*/
protected function getPDO(): PDO
protected function getPDO()
{
return $this->register->get('db');
return $this->pdo;
}
/**
* @throws Exception
*
* @return Client
* @return Redis
*/
protected function getRedis(): Client
protected function getRedis(): Redis
{
return $this->register->get('cache');
return $this->redis;
}
}
}

View file

@ -2,7 +2,6 @@
namespace Appwrite\Database\Adapter;
use Utopia\Registry\Registry;
use Appwrite\Database\Adapter;
use Exception;
use Redis as Client;
@ -10,9 +9,9 @@ use Redis as Client;
class Redis extends Adapter
{
/**
* @var Registry
* @var Client
*/
protected $register;
protected $redis;
/**
* @var Adapter
@ -23,11 +22,11 @@ class Redis extends Adapter
* Redis constructor.
*
* @param Adapter $adapter
* @param Registry $register
* @param Client $redis
*/
public function __construct(Adapter $adapter, Registry $register)
public function __construct(Adapter $adapter, Client $redis)
{
$this->register = $register;
$this->redis = $redis;
$this->adapter = $adapter;
}
@ -261,7 +260,7 @@ class Redis extends Adapter
*/
protected function getRedis(): Client
{
return $this->register->get('cache');
return $this->redis;
}
/**
@ -281,4 +280,4 @@ class Redis extends Adapter
return parent::setNamespace($namespace);
}
}
}

View file

@ -1,19 +0,0 @@
<?php
namespace Appwrite\Database;
abstract class Pool
{
protected $available = true;
protected $pool;
protected $size = 5;
abstract public function get();
public function destruct()
{
$this->available = false;
while (!$this->pool->isEmpty()) {
$this->pool->pop();
}
}
}

View file

@ -1,49 +0,0 @@
<?php
namespace Appwrite\Database\Pool;
use Appwrite\Database\Pool;
use Appwrite\Extend\PDO;
use SplQueue;
class PDOPool extends Pool
{
public function __construct(int $size, string $host = 'localhost', string $schema = 'appwrite', string $user = '', string $pass = '', string $charset = 'utf8mb4')
{
$this->pool = new SplQueue;
$this->size = $size;
for ($i = 0; $i < $this->size; $i++) {
$pdo = new PDO(
"mysql:" .
"host={$host};" .
"dbname={$schema};" .
"charset={$charset}",
$user,
$pass,
[
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
PDO::ATTR_TIMEOUT => 3, // Seconds
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
]
);
$this->pool->enqueue($pdo);
}
}
public function put(PDO $pdo)
{
$this->pool->enqueue($pdo);
}
public function get(): PDO
{
if ($this->available && count($this->pool) > 0) {
return $this->pool->dequeue();
}
sleep(0.01);
return $this->get();
}
}

View file

@ -1,42 +0,0 @@
<?php
namespace Appwrite\Database\Pool;
use Appwrite\Database\Pool;
use SplQueue;
use Redis;
class RedisPool extends Pool
{
public function __construct(int $size, string $host, int $port, array $auth = [])
{
$this->pool = new SplQueue;
$this->size = $size;
for ($i = 0; $i < $this->size; $i++) {
$redis = new Redis();
$redis->pconnect($host, $port);
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
if ($auth) {
$redis->auth($auth);
}
$this->pool->enqueue($redis);
}
}
public function put(Redis $redis)
{
$this->pool->enqueue($redis);
}
public function get(): Redis
{
if ($this->available && !$this->pool->isEmpty()) {
return $this->pool->dequeue();
}
sleep(0.1);
return $this->get();
}
}

View file

@ -1,228 +0,0 @@
<?php
namespace Appwrite\Event;
use Appwrite\Database\Document;
use Utopia\App;
class Realtime
{
/**
* @var string
*/
protected $project = '';
/**
* @var string
*/
protected $event = '';
/**
* @var string
*/
protected $userId = '';
/**
* @var array
*/
protected $channels = [];
/**
* @var array
*/
protected $permissions = [];
/**
* @var false
*/
protected $permissionsChanged = false;
/**
* @var Document
*/
protected $payload;
/**
* Event constructor.
*
* @param string $project
* @param string $event
* @param array $payload
*/
public function __construct(string $project, string $event, array $payload)
{
$this->project = $project;
$this->event = $event;
$this->payload = new Document($payload);
}
/**
* @param string $project
* return $this
*/
public function setProject(string $project): self
{
$this->project = $project;
return $this;
}
/**
* @param string $userId
* return $this
*/
public function setUserId(string $userId): self
{
$this->userId = $userId;
return $this;
}
/**
* @return string
*/
public function getProject(): string
{
return $this->project;
}
/**
* @param string $event
* return $this
*/
public function setEvent(string $event): self
{
$this->event = $event;
return $this;
}
/**
* @return string
*/
public function getEvent(): string
{
return $this->event;
}
/**
* @param array $payload
* @return $this
*/
public function setPayload(array $payload): self
{
$this->payload = new Document($payload);
return $this;
}
/**
* @return Document
*/
public function getPayload(): Document
{
return $this->payload;
}
/**
* Populate channels array based on the event name and payload.
*
* @return void
*/
private function prepareChannels(): void
{
switch (true) {
case strpos($this->event, 'account.recovery.') === 0:
case strpos($this->event, 'account.sessions.') === 0:
case strpos($this->event, 'account.verification.') === 0:
$this->channels[] = 'account.' . $this->payload->getAttribute('userId');
$this->permissions = ['user:' . $this->payload->getAttribute('userId')];
break;
case strpos($this->event, 'account.') === 0:
$this->channels[] = 'account.' . $this->payload->getId();
$this->permissions = ['user:' . $this->payload->getId()];
break;
case strpos($this->event, 'teams.memberships') === 0:
$this->permissionsChanged = in_array($this->event, ['teams.memberships.update', 'teams.memberships.delete', 'teams.memberships.update.status']);
$this->channels[] = 'memberships';
$this->channels[] = 'memberships.' . $this->payload->getId();
$this->permissions = ['team:' . $this->payload->getAttribute('teamId')];
break;
case strpos($this->event, 'teams.') === 0:
$this->permissionsChanged = $this->event === 'teams.create';
$this->channels[] = 'teams';
$this->channels[] = 'teams.' . $this->payload->getId();
$this->permissions = ['team:' . $this->payload->getId()];
break;
case strpos($this->event, 'database.collections.') === 0:
$this->channels[] = 'collections';
$this->channels[] = 'collections.' . $this->payload->getId();
$this->permissions = $this->payload->getAttribute('$permissions.read');
break;
case strpos($this->event, 'database.documents.') === 0:
$this->channels[] = 'documents';
$this->channels[] = 'collections.' . $this->payload->getAttribute('$collection') . '.documents';
$this->channels[] = 'documents.' . $this->payload->getId();
$this->permissions = $this->payload->getAttribute('$permissions.read');
break;
case strpos($this->event, 'storage.') === 0:
$this->channels[] = 'files';
$this->channels[] = 'files.' . $this->payload->getId();
$this->permissions = $this->payload->getAttribute('$permissions.read');
break;
case strpos($this->event, 'functions.executions.') === 0:
if (!empty($this->payload->getAttribute('$permissions.read'))) {
$this->channels[] = 'executions';
$this->channels[] = 'executions.' . $this->payload->getId();
$this->channels[] = 'functions.' . $this->payload->getAttribute('functionId');
$this->permissions = $this->payload->getAttribute('$permissions.read');
}
break;
}
}
/**
* Execute Event.
*
* @return void
*/
public function trigger(): void
{
$this->prepareChannels();
if (empty($this->channels)) return;
$redis = new \Redis();
$redis->connect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
$redis->publish('realtime', json_encode([
'project' => $this->project,
'permissions' => $this->permissions,
'permissionsChanged' => $this->permissionsChanged,
'userId' => $this->userId,
'data' => [
'event' => $this->event,
'channels' => $this->channels,
'timestamp' => time(),
'payload' => $this->payload->getArrayCopy()
]
]));
$this->reset();
}
/**
* Resets this event and unpopulates all data.
*
* @return $this
*/
public function reset(): self
{
$this->event = '';
$this->payload = $this->channels = [];
return $this;
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace Appwrite\Messaging;
abstract class Adapter
{
public abstract function subscribe(string $project, mixed $identifier, array $roles, array $channels): void;
public abstract function unsubscribe(mixed $identifier): void;
public static abstract function send(string $projectId, array $payload, string $event, array $channels, array $permissions, array $options): void;
}

View file

@ -0,0 +1,295 @@
<?php
namespace Appwrite\Messaging\Adapter;
use Appwrite\Database\Document;
use Appwrite\Messaging\Adapter;
use Utopia\App;
class Realtime extends Adapter
{
/**
* Connection Tree
*
* [CONNECTION_ID] ->
* 'projectId' -> [PROJECT_ID]
* 'roles' -> [ROLE_x, ROLE_Y]
* 'channels' -> [CHANNEL_NAME_X, CHANNEL_NAME_Y, CHANNEL_NAME_Z]
*/
public array $connections = [];
/**
* Subscription Tree
*
* [PROJECT_ID] ->
* [ROLE_X] ->
* [CHANNEL_NAME_X] -> [CONNECTION_ID]
* [CHANNEL_NAME_Y] -> [CONNECTION_ID]
* [CHANNEL_NAME_Z] -> [CONNECTION_ID]
* [ROLE_Y] ->
* [CHANNEL_NAME_X] -> [CONNECTION_ID]
* [CHANNEL_NAME_Y] -> [CONNECTION_ID]
* [CHANNEL_NAME_Z] -> [CONNECTION_ID]
*/
public array $subscriptions = [];
/**
* Adds a subscribtion.
* @param string $projectId Project ID.
* @param mixed $connection Unique Identifier - Connection ID.
* @param array $roles Roles of the Subscription.
* @param array $channels Subscribed Channels.
* @return void
*/
public function subscribe(string $projectId, mixed $connection, array $roles, array $channels): void
{
if (!isset($this->subscriptions[$projectId])) { // Init Project
$this->subscriptions[$projectId] = [];
}
foreach ($roles as $role) {
if (!isset($this->subscriptions[$projectId][$role])) { // Add user first connection
$this->subscriptions[$projectId][$role] = [];
}
foreach ($channels as $channel => $list) {
$this->subscriptions[$projectId][$role][$channel][$connection] = true;
}
}
$this->connections[$connection] = [
'projectId' => $projectId,
'roles' => $roles,
'channels' => $channels
];
}
/**
* Removes Subscription.
*
* @param mixed $connection
* @return void
*/
public function unsubscribe(mixed $connection): void
{
$projectId = $this->connections[$connection]['projectId'] ?? '';
$roles = $this->connections[$connection]['roles'] ?? [];
foreach ($roles as $role) {
foreach ($this->subscriptions[$projectId][$role] as $channel => $list) {
unset($this->subscriptions[$projectId][$role][$channel][$connection]); // Remove connection
if (empty($this->subscriptions[$projectId][$role][$channel])) {
unset($this->subscriptions[$projectId][$role][$channel]); // Remove channel when no connections
}
}
if (empty($this->subscriptions[$projectId][$role])) {
unset($this->subscriptions[$projectId][$role]); // Remove role when no channels
}
}
if (empty($this->subscriptions[$projectId])) { // Remove project when no roles
unset($this->subscriptions[$projectId]);
}
unset($this->connections[$connection]);
}
/**
* Checks if Channel has a subscriber.
* @param string $projectId
* @param string $role
* @param string $channel
* @return bool
*/
public function hasSubscriber(string $projectId, string $role, string $channel = ''): bool
{
if (empty($channel)) {
return array_key_exists($projectId, $this->subscriptions)
&& array_key_exists($role, $this->subscriptions[$projectId]);
}
return array_key_exists($projectId, $this->subscriptions)
&& array_key_exists($role, $this->subscriptions[$projectId])
&& array_key_exists($channel, $this->subscriptions[$projectId][$role]);
}
/**
* Sends an event to the Realtime Server.
* @param string $project
* @param array $payload
* @param string $event
* @param array $channels
* @param array $permissions
* @param array $options
* @return void
*/
public static function send(string $project, array $payload, string $event, array $channels, array $permissions, array $options = []): void
{
if (empty($channels) || empty($permissions) || empty($project)) return;
$permissionsChanged = array_key_exists('permissionsChanged', $options) && $options['permissionsChanged'];
$userId = array_key_exists('userId', $options) ? $options['userId'] : null;
$redis = new \Redis();
$redis->connect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
$redis->publish('realtime', json_encode([
'project' => $project,
'permissions' => $permissions,
'permissionsChanged' => $permissionsChanged,
'userId' => $userId,
'data' => [
'event' => $event,
'channels' => $channels,
'timestamp' => time(),
'payload' => $payload
]
]));
}
/**
* Identifies the receivers of all subscriptions, based on the permissions and event.
*
* Example of performance with an event with user:XXX permissions and with X users spread across 10 different channels:
* - 0.014 ms (±6.88%) | 10 Connections / 100 Subscriptions
* - 0.070 ms (±3.71%) | 100 Connections / 1,000 Subscriptions
* - 0.846 ms (±2.74%) | 1,000 Connections / 10,000 Subscriptions
* - 10.866 ms (±1.01%) | 10,000 Connections / 100,000 Subscriptions
* - 110.201 ms (±2.32%) | 100,000 Connections / 1,000,000 Subscriptions
* - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions
*
* @param array $event
*/
public function getReceivers(array $event)
{
$receivers = [];
if (isset($this->subscriptions[$event['project']])) {
foreach ($this->subscriptions[$event['project']] as $role => $subscription) {
foreach ($event['data']['channels'] as $channel) {
if (
\array_key_exists($channel, $this->subscriptions[$event['project']][$role])
&& (\in_array($role, $event['permissions']) || \in_array('*', $event['permissions']))
) {
foreach (array_keys($this->subscriptions[$event['project']][$role][$channel]) as $ids) {
$receivers[$ids] = 0;
}
break;
}
}
}
}
return array_keys($receivers);
}
/**
* Converts the channels from the Query Params into an array.
* Also renames the account channel to account.USER_ID and removes all illegal account channel variations.
* @param array $channels
* @param Document $user
* @return array
*/
public static function convertChannels(array $channels, Document $user): array
{
$channels = array_flip($channels);
foreach ($channels as $key => $value) {
switch (true) {
case strpos($key, 'account.') === 0:
unset($channels[$key]);
break;
case $key === 'account':
if (!empty($user->getId())) {
$channels['account.' . $user->getId()] = $value;
}
unset($channels['account']);
break;
}
}
if (\array_key_exists('account', $channels)) {
if ($user->getId()) {
$channels['account.' . $user->getId()] = $channels['account'];
}
unset($channels['account']);
}
return $channels;
}
/**
* Create channels array based on the event name and payload.
*
* @return void
*/
public static function fromPayload(string $event, Document $payload): array
{
$channels = [];
$permissions = [];
$permissionsChanged = false;
switch (true) {
case strpos($event, 'account.recovery.') === 0:
case strpos($event, 'account.sessions.') === 0:
case strpos($event, 'account.verification.') === 0:
$channels[] = 'account.' . $payload->getAttribute('userId');
$permissions = ['user:' . $payload->getAttribute('userId')];
break;
case strpos($event, 'account.') === 0:
$channels[] = 'account.' . $payload->getId();
$permissions = ['user:' . $payload->getId()];
break;
case strpos($event, 'teams.memberships') === 0:
$permissionsChanged = in_array($event, ['teams.memberships.update', 'teams.memberships.delete', 'teams.memberships.update.status']);
$channels[] = 'memberships';
$channels[] = 'memberships.' . $payload->getId();
$permissions = ['team:' . $payload->getAttribute('teamId')];
break;
case strpos($event, 'teams.') === 0:
$permissionsChanged = $event === 'teams.create';
$channels[] = 'teams';
$channels[] = 'teams.' . $payload->getId();
$permissions = ['team:' . $payload->getId()];
break;
case strpos($event, 'database.collections.') === 0:
$channels[] = 'collections';
$channels[] = 'collections.' . $payload->getId();
$permissions = $payload->getAttribute('$permissions.read');
break;
case strpos($event, 'database.documents.') === 0:
$channels[] = 'documents';
$channels[] = 'collections.' . $payload->getAttribute('$collection') . '.documents';
$channels[] = 'documents.' . $payload->getId();
$permissions = $payload->getAttribute('$permissions.read');
break;
case strpos($event, 'storage.') === 0:
$channels[] = 'files';
$channels[] = 'files.' . $payload->getId();
$permissions = $payload->getAttribute('$permissions.read');
break;
case strpos($event, 'functions.executions.') === 0:
if (!empty($payload->getAttribute('$permissions.read'))) {
$channels[] = 'executions';
$channels[] = 'executions.' . $payload->getId();
$channels[] = 'functions.' . $payload->getAttribute('functionId');
$permissions = $payload->getAttribute('$permissions.read');
}
break;
}
return [
'channels' => $channels,
'permissions' => $permissions,
'permissionsChanged' => $permissionsChanged
];
}
}

View file

@ -1,202 +0,0 @@
<?php
namespace Appwrite\Realtime;
use Appwrite\Auth\Auth;
use Appwrite\Database\Document;
class Parser
{
/**
* @var Document $user
*/
static $user;
/**
* Sets the current user for the role and channel parsing.
*
* @param Document $user
*/
static function setUser(Document $user)
{
self::$user = $user;
}
/**
* Returns array of roles that the set User has permissions to.
*
* @return array
*/
static function getRoles()
{
if (!isset(self::$user)) {
return [];
}
$roles = ['role:' . ((self::$user->isEmpty()) ? Auth::USER_ROLE_GUEST : Auth::USER_ROLE_MEMBER)];
if (!(self::$user->isEmpty())) {
$roles[] = 'user:' . self::$user->getId();
}
foreach (self::$user->getAttribute('memberships', []) as $node) {
if (isset($node['teamId']) && isset($node['roles'])) {
$roles[] = 'team:' . $node['teamId'];
foreach ($node['roles'] as $nodeRole) { // Set all team roles
$roles[] = 'team:' . $node['teamId'] . '/' . $nodeRole;
}
}
}
return $roles;
}
/**
* Converts the channels from the Query Params into an array.
* Also renames the account channel to account.USER_ID and removes all illegal account channel variations.
*
* @param array $channels
*/
static function parseChannels(array $channels)
{
$channels = array_flip($channels);
foreach ($channels as $key => $value) {
switch (true) {
case strpos($key, 'account.') === 0:
unset($channels[$key]);
break;
case $key === 'account':
if (!empty(self::$user->getId())) {
$channels['account.' . self::$user->getId()] = $value;
}
unset($channels['account']);
break;
}
}
if (\array_key_exists('account', $channels)) {
if (self::$user->getId()) {
$channels['account.' . self::$user->getId()] = $channels['account'];
}
unset($channels['account']);
}
return $channels;
}
/**
* Identifies the receivers of all subscriptions, based on the permissions and event.
*
* Example of performance with an event with user:XXX permissions and with X users spread across 10 different channels:
* - 0.014 ms (±6.88%) | 10 Connections / 100 Subscriptions
* - 0.070 ms (±3.71%) | 100 Connections / 1,000 Subscriptions
* - 0.846 ms (±2.74%) | 1,000 Connections / 10,000 Subscriptions
* - 10.866 ms (±1.01%) | 10,000 Connections / 100,000 Subscriptions
* - 110.201 ms (±2.32%) | 100,000 Connections / 1,000,000 Subscriptions
* - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions
*
* @param array $event
* @param array $connections
* @param array $subscriptions
*/
static function identifyReceivers(array &$event, array &$subscriptions)
{
$receivers = [];
if (isset($subscriptions[$event['project']])) {
foreach ($subscriptions[$event['project']] as $role => $subscription) {
foreach ($event['data']['channels'] as $channel) {
if (
\array_key_exists($channel, $subscriptions[$event['project']][$role])
&& (\in_array($role, $event['permissions']) || \in_array('*', $event['permissions']))
) {
foreach (array_keys($subscriptions[$event['project']][$role][$channel]) as $ids) {
$receivers[$ids] = 0;
}
break;
}
}
}
}
return array_keys($receivers);
}
/**
* Adds Subscription.
*
* @param string $projectId
* @param mixed $connection
* @param array $subscriptions
* @param array $roles
* @param array $channels
*/
static function subscribe($projectId, $connection, $roles, &$subscriptions, &$connections, &$channels)
{
/**
* Build Subscriptions Tree
*
* [PROJECT_ID] ->
* [ROLE_X] ->
* [CHANNEL_NAME_X] -> [CONNECTION_ID]
* [CHANNEL_NAME_Y] -> [CONNECTION_ID]
* [CHANNEL_NAME_Z] -> [CONNECTION_ID]
* [ROLE_Y] ->
* [CHANNEL_NAME_X] -> [CONNECTION_ID]
* [CHANNEL_NAME_Y] -> [CONNECTION_ID]
* [CHANNEL_NAME_Z] -> [CONNECTION_ID]
*/
if (!isset($subscriptions[$projectId])) { // Init Project
$subscriptions[$projectId] = [];
}
foreach ($roles as $role) {
if (!isset($subscriptions[$projectId][$role])) { // Add user first connection
$subscriptions[$projectId][$role] = [];
}
foreach ($channels as $channel => $list) {
$subscriptions[$projectId][$role][$channel][$connection] = true;
}
}
$connections[$connection] = [
'projectId' => $projectId,
'roles' => $roles,
'channels' => $channels
];
}
/**
* Remove Subscription.
*
* @param mixed $connection
* @param array $subscriptions
* @param array $connections
*/
static function unsubscribe($connection, &$subscriptions, &$connections)
{
$projectId = $connections[$connection]['projectId'] ?? '';
$roles = $connections[$connection]['roles'] ?? [];
foreach ($roles as $role) {
foreach ($subscriptions[$projectId][$role] as $channel => $list) {
unset($subscriptions[$projectId][$role][$channel][$connection]); // Remove connection
if (empty($subscriptions[$projectId][$role][$channel])) {
unset($subscriptions[$projectId][$role][$channel]); // Remove channel when no connections
}
}
if (empty($subscriptions[$projectId][$role])) {
unset($subscriptions[$projectId][$role]); // Remove role when no channels
}
}
if (empty($subscriptions[$projectId])) { // Remove project when no roles
unset($subscriptions[$projectId]);
}
unset($connections[$connection]);
}
}

View file

@ -1,553 +0,0 @@
<?php
namespace Appwrite\Realtime;
use Appwrite\Database\Database;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Event\Event;
use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Response;
use Exception;
use Swoole\Coroutine\Redis;
use Swoole\Http\Request;
use Swoole\Http\Response as SwooleResponse;
use Swoole\Process;
use Swoole\Table;
use Swoole\Timer;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server as SwooleServer;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Exception as UtopiaException;
use Utopia\Registry\Registry;
use Utopia\Swoole\Request as SwooleRequest;
class Server
{
/**
* Container scoped Registry.
* @var Registry
*/
public Registry $register;
/**
* Container scoped Swoole Server.
* @var SwooleServer
*/
public SwooleServer $server;
/**
* Container scoped Usage Table.
* @var Table
*/
public Table $usage;
/**
* Container scoped Database connection.
* @var Database
*/
public Database $consoleDb;
/**
* Container scoped Database connection.
* @var Database
*/
public Database $projectDb;
/**
* Container scoped Redis connection.
* @var Redis
*/
public Redis $cache;
/**
* Worker scoped subscription.
* @var array
*/
public array $subscriptions;
/**
* Worker scoped connections.
* @var array
*/
public array $connections;
public function __construct(Registry &$register, $host = '0.0.0.0', $port = 80, $config = [])
{
$this->subscriptions = [];
$this->connections = [];
$this->register = $register;
$this->usage = new Table(4096, 1);
$this->usage->column('projectId', Table::TYPE_STRING, 64);
$this->usage->column('connections', Table::TYPE_INT);
$this->usage->column('connectionsTotal', Table::TYPE_INT);
$this->usage->column('messages', Table::TYPE_INT);
$this->usage->create();
$this->consoleDb = new Database();
$this->consoleDb->setAdapter(new RedisAdapter(new MySQLAdapter($this->register), $this->register));
$this->consoleDb->setNamespace('app_console');
$this->consoleDb->setMocks(Config::getParam('collections', []));
$this->projectDb = new Database();
$this->projectDb->setAdapter(new RedisAdapter(new MySQLAdapter($this->register), $this->register));
$this->projectDb->setMocks(Config::getParam('collections', []));
$this->server = new SwooleServer($host, $port, SWOOLE_PROCESS);
$this->server->set($config);
$this->server->on('start', [$this, 'onStart']);
$this->server->on('workerStart', [$this, 'onWorkerStart']);
$this->server->on('open', [$this, 'onOpen']);
$this->server->on('message', [$this, 'onMessage']);
$this->server->on('close', [$this, 'onClose']);
$this->server->container_id = uniqid();
$this->server->start();
}
/**
* This is executed when the Realtime server starts.
*
* @param SwooleServer $server
* @return void
*/
public function onStart(SwooleServer $server): void
{
Console::success('Server started succefully');
Console::info("Master pid {$server->master_pid}, manager pid {$server->manager_pid}");
try {
go(function() {
$document = [
'$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS,
'$permissions' => [
'read' => ['*'],
'write' => ['*'],
],
'container' => $this->server->container_id,
'timestamp' => time(),
'value' => '{}'
];
Authorization::disable();
$document = $this->consoleDb->createDocument($document);
Authorization::enable();
$this->server->document_id = $document->getId();
});
} catch (\Throwable $th) {
Console::error('[Error] Type: '.get_class($th));
Console::error('[Error] Message: '.$th->getMessage());
Console::error('[Error] File: '.$th->getFile());
Console::error('[Error] Line: '.$th->getLine());
}
// Run ever 10 seconds
Timer::tick(10000, function () {
/** @var Table $stats */
foreach ($this->usage as $projectId => $value) {
if (empty($value['connections']) && empty($value['messages'])) {
continue;
}
$connections = $value['connections'];
$messages = $value['messages'];
$usage = new Event('v1-usage', 'UsageV1');
$usage
->setParam('projectId', $projectId)
->setParam('realtimeConnections', $connections)
->setParam('realtimeMessages', $messages)
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0);
$this->usage->set($projectId, [
'projectId' => $projectId,
'messages' => 0,
'connections' => 0
]);
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
$usage->trigger();
}
}
});
// Run ever 10 seconds
Timer::tick(10000, function () {
$payload = [];
foreach ($this->usage as $projectId => $value) {
if (!empty($value['connectionsTotal'])) {
$payload[$projectId] = $value['connectionsTotal'];
}
}
if (empty($payload)){
return;
}
$document = [
'$id' => $this->server->document_id,
'$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS,
'$permissions' => [
'read' => ['*'],
'write' => ['*'],
],
'container' => $this->server->container_id,
'timestamp' => time(),
'value' => json_encode($payload)
];
try {
$document = $this->consoleDb->updateDocument($document);
} catch (\Throwable $th) {
Console::error('[Error] Type: '.get_class($th));
Console::error('[Error] Message: '.$th->getMessage());
Console::error('[Error] File: '.$th->getFile());
Console::error('[Error] Line: '.$th->getLine());
}
});
Process::signal(2, function () use ($server) {
Console::log('Stop by Ctrl+C');
$server->shutdown();
});
}
/**
* This is executed when a WebSocket worker process starts.
*
* @param SwooleServer $server
* @param int $workerId
* @return void
* @throws Exception
*/
public function onWorkerStart(SwooleServer $server, int $workerId): void
{
Console::success('Worker ' . $workerId . ' started succefully');
$attempts = 0;
$start = time();
$redisPool = $this->register->get('redisPool');
/**
* Sending current connections to project channels on the console project every 5 seconds.
*/
$server->tick(5000, function () use (&$server) {
$this->tickSendProjectUsage($server);
});
while ($attempts < 300) {
try {
if ($attempts > 0) {
Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . ').
Attempting restart in 5 seconds (attempt #' . $attempts . ')');
sleep(5); // 5 sec delay between connection attempts
}
/** @var Swoole\Coroutine\Redis $redis */
$redis = $redisPool->get();
if ($redis->ping(true)) {
$attempts = 0;
Console::success('Pub/sub connection established (worker: ' . $workerId . ')');
} else {
Console::error('Pub/sub failed (worker: ' . $workerId . ')');
}
$redis->subscribe(['realtime'], function ($redis, $channel, $payload) use ($server, $workerId) {
$this->onRedisPublish($payload, $server, $workerId);
});
} catch (\Throwable $th) {
Console::error('Pub/sub error: ' . $th->getMessage());
$redisPool->put($redis);
$attempts++;
continue;
}
$attempts++;
}
Console::error('Failed to restart pub/sub...');
}
/**
* This is executed when a new Realtime connection is established.
* @param SwooleServer $server
* @param Request $request
* @return void
* @throws Exception
* @throws UtopiaException
*/
public function onOpen(SwooleServer $server, Request $request): void
{
$app = new App('UTC');
$connection = $request->fd;
$request = new SwooleRequest($request);
$db = $this->register->get('dbPool')->get();
$redis = $this->register->get('redisPool')->get();
$this->register->set('db', function () use (&$db) {
return $db;
});
$this->register->set('cache', function () use (&$redis) {
return $redis;
});
Console::info("Connection open (user: {$connection}, worker: {$server->getWorkerId()})");
App::setResource('request', function () use ($request) {
return $request;
});
App::setResource('response', function () {
return new Response(new SwooleResponse());
});
try {
/** @var \Appwrite\Database\Document $user */
$user = $app->getResource('user');
/** @var \Appwrite\Database\Document $project */
$project = $app->getResource('project');
/** @var \Appwrite\Database\Document $console */
$console = $app->getResource('console');
/*
* Project Check
*/
if (empty($project->getId())) {
throw new Exception('Missing or unknown project ID', 1008);
}
/*
* Abuse Check
*
* Abuse limits are connecting 128 times per minute and ip address.
*/
$timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, function () use ($db) {
return $db;
});
$timeLimit
->setNamespace('app_' . $project->getId())
->setParam('{ip}', $request->getIP())
->setParam('{url}', $request->getURI());
$abuse = new Abuse($timeLimit);
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
throw new Exception('Too many requests', 1013);
}
/*
* Validate Client Domain - Check to avoid CSRF attack.
* Adding Appwrite API domains to allow XDOMAIN communication.
* Skip this check for non-web platforms which are not required to send an origin header.
*/
$origin = $request->getOrigin();
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
if (!$originValidator->isValid($origin) && $project->getId() !== 'console') {
throw new Exception($originValidator->getDescription(), 1008);
}
Parser::setUser($user);
$roles = Parser::getRoles();
$channels = Parser::parseChannels($request->getQuery('channels', []));
/**
* Channels Check
*/
if (empty($channels)) {
throw new Exception('Missing channels', 1008);
}
Parser::subscribe($project->getId(), $connection, $roles, $this->subscriptions, $this->connections, $channels);
$server->push($connection, json_encode($channels));
$this->usage->incr($project->getId(), 'connections');
$this->usage->incr($project->getId(), 'connectionsTotal');
} catch (\Throwable $th) {
$response = [
'code' => $th->getCode(),
'message' => $th->getMessage()
];
// Temporarily print debug logs by default for Alpha testing.
//if (App::isDevelopment()) {
Console::error("[Error] Connection Error");
Console::error("[Error] Code: " . $response['code']);
Console::error("[Error] Message: " . $response['message']);
//}
$server->push($connection, json_encode($response));
$server->close($connection);
}
/**
* Put used PDO and Redis Connections back into their pools.
*/
/** @var PDOPool $dbPool */
$dbPool = $this->register->get('dbPool');
$dbPool->put($db);
/** @var RedisPool $redisPool */
$redisPool = $this->register->get('redisPool');
$redisPool->put($redis);
}
/**
* This is executed when a message is received by the Realtime server.
*
* @param SwooleServer $server
* @param Frame $frame
* @return void
*/
public function onMessage(SwooleServer $server, Frame $frame)
{
$server->push($frame->fd, 'Sending messages is not allowed.');
$server->close($frame->fd);
}
/**
* This is executed when a Realtime connection is closed.
*
* @param SwooleServer $server
* @param int $connection
* @return void
*/
public function onClose(SwooleServer $server, int $connection)
{
if (array_key_exists($connection, $this->connections)) {
$this->usage->decr($this->connections[$connection]['projectId'], 'connectionsTotal');
}
Parser::unsubscribe($connection, $this->subscriptions, $this->connections);
Console::info('Connection close: ' . $connection);
}
/**
* This is executed when an event is published on realtime channel in Redis.
*
* Supported Resources:
* - Collection
* - Document
* - File
* - Account
* - Session
* - Team? (not implemented yet)
* - Membership? (not implemented yet)
* - Function
* - Execution
*
* @param string $payload
* @param SwooleServer $server
* @param int $workerId
* @return void
*/
public function onRedisPublish(string $payload, SwooleServer &$server, int $workerId)
{
$event = json_decode($payload, true);
if ($event['permissionsChanged'] && isset($event['userId'])) {
$this->addPermission($event);
}
$receivers = Parser::identifyReceivers($event, $this->subscriptions);
// Temporarily print debug logs by default for Alpha testing.
// if (App::isDevelopment() && !empty($receivers)) {
if (!empty($receivers)) {
Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers));
Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers));
Console::log("[Debug][Worker {$workerId}] Event: " . $payload);
}
foreach ($receivers as $receiver) {
if ($server->exist($receiver) && $server->isEstablished($receiver)) {
$server->push(
$receiver,
json_encode($event['data']),
SWOOLE_WEBSOCKET_OPCODE_TEXT,
SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS
);
} else {
$server->close($receiver);
}
}
if (($num = count($receivers)) > 0) {
$this->usage->incr($event['project'], 'messages', $num);
}
}
/**
* This sends the usage to the `console` channel.
*
* @param SwooleServer $server
* @return void
*/
public function tickSendProjectUsage(SwooleServer &$server)
{
if (
array_key_exists('console', $this->subscriptions)
&& array_key_exists('role:member', $this->subscriptions['console'])
&& array_key_exists('project', $this->subscriptions['console']['role:member'])
) {
$payload = [];
$list = $this->consoleDb->getCollection([
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_CONNECTIONS,
'timestamp>'.(time() - 15)
],
]);
foreach ($list as $document) {
foreach (json_decode($document->getAttribute('value')) as $projectId => $value) {
if (array_key_exists($projectId, $payload)) {
$payload[$projectId] += $value;
} else {
$payload[$projectId] = $value;
}
}
}
foreach ($this->subscriptions['console']['role:member']['project'] as $connection => $value) {
$server->push(
$connection,
json_encode([
'event' => 'stats.connections',
'channels' => ['project'],
'timestamp' => time(),
'payload' => $payload
]),
SWOOLE_WEBSOCKET_OPCODE_TEXT,
SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS
);
}
}
}
private function addPermission(array $event)
{
$project = $event['project'];
$userId = $event['userId'];
if (array_key_exists($project, $this->subscriptions) && array_key_exists('user:'.$userId, $this->subscriptions[$project])) {
$connection = array_key_first(reset($this->subscriptions[$project]['user:'.$userId]));
} else {
return;
}
$this->projectDb->setNamespace('app_'.$project);
$user = $this->projectDb->getDocument($userId);
Parser::setUser($user);
$roles = Parser::getRoles();
Parser::subscribe($project, $connection, $roles, $this->subscriptions, $this->connections, $this->connections[$connection]['channels']);
}
}

View file

@ -47,9 +47,9 @@ class Func extends Model
'default' => '',
'example' => 'enabled',
])
->addRule('env', [
->addRule('runtime', [
'type' => self::TYPE_STRING,
'description' => 'Function execution environment.',
'description' => 'Function execution runtime.',
'default' => '',
'example' => 'python-3.8',
])

View file

@ -26,7 +26,7 @@ export default function () {
'X-Appwrite-Project': '60479fe35d95d'
}}
const resDb = http.get('http://localhost:9501/v1/health/db', config);
const resDb = http.get('http://localhost:9501/', config);
check(resDb, {
'status is 200': (r) => r.status === 200,

View file

@ -8,11 +8,11 @@ export let options = {
stages: [
{
duration: '10s',
target: 10
target: 500
},
{
duration: '30m',
target: 10
duration: '1m',
target: 500
},
],
}
@ -21,7 +21,7 @@ export default function () {
// const url = new URL('wss://appwrite-realtime.monitor-api.com/v1/realtime');
// url.searchParams.append('project', '604249e6b1a9f');
const url = new URL('ws://localhost/v1/realtime');
url.searchParams.append('project', '60476312f335c');
url.searchParams.append('project', 'console');
url.searchParams.append('channels[]', 'files');
const res = ws.connect(url.toString(), function (socket) {

View file

@ -424,4 +424,39 @@ class AccountCustomClientTest extends Scope
return [];
}
public function testGetSessionByID() {
$session = $this->testCreateAnonymousAccount();
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/current', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['provider'], 'anonymous');
$sessionID = $response['body']['$id'];
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionID, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['provider'], 'anonymous');
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/97823askjdkasd80921371980', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
]));
$this->assertEquals($response['headers']['status-code'], 404);
}
}

View file

@ -54,7 +54,7 @@ class FunctionsCustomClientTest extends Scope
], [
'name' => 'Test',
'execute' => ['user:'.$this->getUser()['$id']],
'env' => 'php-8.0',
'runtime' => 'php-8.0',
'vars' => [
'funcKey1' => 'funcValue1',
'funcKey2' => 'funcValue2',
@ -140,7 +140,7 @@ class FunctionsCustomClientTest extends Scope
], [
'name' => 'Test',
'execute' => ['*'],
'env' => 'php-8.0',
'runtime' => 'php-8.0',
'vars' => [
'funcKey1' => 'funcValue1',
'funcKey2' => 'funcValue2',

View file

@ -24,7 +24,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Test',
'env' => 'php-8.0',
'runtime' => 'php-8.0',
'vars' => [
'funcKey1' => 'funcValue1',
'funcKey2' => 'funcValue2',
@ -43,7 +43,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $response1['headers']['status-code']);
$this->assertNotEmpty($response1['body']['$id']);
$this->assertEquals('Test', $response1['body']['name']);
$this->assertEquals('php-8.0', $response1['body']['env']);
$this->assertEquals('php-8.0', $response1['body']['runtime']);
$this->assertIsInt($response1['body']['dateCreated']);
$this->assertIsInt($response1['body']['dateUpdated']);
$this->assertEquals('', $response1['body']['tag']);
@ -327,7 +327,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('PHP', $execution['body']['stdout']);
$this->assertStringContainsString('8.0', $execution['body']['stdout']);
$this->assertEquals('', $execution['body']['stderr']);
$this->assertGreaterThan(0.100, $execution['body']['time']);
$this->assertGreaterThan(0.05, $execution['body']['time']);
$this->assertLessThan(0.500, $execution['body']['time']);
/**
@ -462,7 +462,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Test '.$name,
'env' => $name,
'runtime' => $name,
'vars' => [],
'events' => [],
'schedule' => '',
@ -540,7 +540,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Test '.$name,
'env' => $name,
'runtime' => $name,
'vars' => [],
'events' => [],
'schedule' => '',

View file

@ -22,7 +22,7 @@ trait RealtimeBase
];
return new WebSocketClient('ws://appwrite-traefik/v1/realtime?' . http_build_query($query), [
'headers' => $headers,
'timeout' => 60,
'timeout' => 30,
]);
}
@ -622,7 +622,7 @@ trait RealtimeBase
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'name' => 'Test',
'env' => 'php-7.4',
'runtime' => 'php-7.4',
'execute' => ['*'],
'timeout' => 10,
]);

View file

@ -306,7 +306,7 @@ class WebhooksCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Test',
'env' => 'php-8.0',
'runtime' => 'php-8.0',
'execute' => ['*'],
'timeout' => 10,
]);
@ -348,7 +348,7 @@ class WebhooksCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Test',
'env' => 'php-8.0',
'runtime' => 'php-8.0',
'execute' => ['*'],
'vars' => [
'key1' => 'value1',

View file

@ -196,4 +196,48 @@ class AuthTest extends TestCase
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_OWNER => true, 'role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_OWNER => true, 'role:'.Auth::USER_ROLE_ADMIN => true, 'role:'.Auth::USER_ROLE_DEVELOPER => true]));
}
public function testGuestRoles()
{
$user = new Document([
'$id' => ''
]);
$roles = Auth::getRoles($user);
$this->assertCount(1, $roles);
$this->assertContains('role:guest', $roles);
}
public function testUserRoles()
{
$user = new Document([
'$id' => '123',
'memberships' => [
[
'teamId' => 'abc',
'roles' => [
'administrator',
'moderator'
]
],
[
'teamId' => 'def',
'roles' => [
'guest'
]
]
]
]);
$roles = Auth::getRoles($user);
$this->assertCount(7, $roles);
$this->assertContains('role:member', $roles);
$this->assertContains('user:123', $roles);
$this->assertContains('team:abc', $roles);
$this->assertContains('team:abc/administrator', $roles);
$this->assertContains('team:abc/moderator', $roles);
$this->assertContains('team:def', $roles);
$this->assertContains('team:def/guest', $roles);
}
}

View file

@ -2,19 +2,19 @@
namespace Appwrite\Tests;
use Appwrite\Auth\Auth;
use Appwrite\Database\Document;
use Appwrite\Realtime;
use Appwrite\Messaging\Adapter\Realtime;
use PHPUnit\Framework\TestCase;
class RealtimeChannelsTest extends TestCase
class MessagingChannelsTest extends TestCase
{
/**
* Configures how many Connections the Test should Mock.
*/
public $connectionsPerChannel = 10;
public $connections = [];
public $subscriptions = [];
public Realtime $realtime;
public $connectionsCount = 0;
public $connectionsAuthenticated = 0;
public $connectionsGuest = 0;
@ -41,12 +41,14 @@ class RealtimeChannelsTest extends TestCase
$this->connectionsGuest = count($this->allChannels) * $this->connectionsPerChannel;
$this->connectionsTotal = $this->connectionsAuthenticated + $this->connectionsGuest;
$this->realtime = new Realtime();
/**
* Add Authenticated Clients
*/
for ($i = 0; $i < $this->connectionsPerChannel; $i++) {
foreach ($this->allChannels as $index => $channel) {
Realtime\Parser::setUser(new Document([
$user = new Document([
'$id' => 'user' . $this->connectionsCount,
'memberships' => [
[
@ -56,16 +58,16 @@ class RealtimeChannelsTest extends TestCase
]
]
]
]));
$roles = Realtime\Parser::getRoles();
$parsedChannels = Realtime\Parser::parseChannels([0 => $channel]);
]);
Realtime\Parser::subscribe(
$roles = Auth::getRoles($user);
$parsedChannels = Realtime::convertChannels([0 => $channel], $user);
$this->realtime->subscribe(
'1',
$this->connectionsCount,
$roles,
$this->subscriptions,
$this->connections,
$parsedChannels
);
@ -78,19 +80,18 @@ class RealtimeChannelsTest extends TestCase
*/
for ($i = 0; $i < $this->connectionsPerChannel; $i++) {
foreach ($this->allChannels as $index => $channel) {
Realtime\Parser::setUser(new Document([
$user = new Document([
'$id' => ''
]));
]);
$roles = Realtime\Parser::getRoles();
$parsedChannels = Realtime\Parser::parseChannels([0 => $channel]);
$roles = Auth::getRoles($user);
Realtime\Parser::subscribe(
$parsedChannels = Realtime::convertChannels([0 => $channel], $user);
$this->realtime->subscribe(
'1',
$this->connectionsCount,
$roles,
$this->subscriptions,
$this->connections,
$parsedChannels
);
@ -101,8 +102,7 @@ class RealtimeChannelsTest extends TestCase
public function tearDown(): void
{
$this->connections = [];
$this->subscriptions = [];
unset($this->realtime);
$this->connectionsCount = 0;
}
@ -111,7 +111,7 @@ class RealtimeChannelsTest extends TestCase
/**
* Check for 1 project.
*/
$this->assertCount(1, $this->subscriptions);
$this->assertCount(1, $this->realtime->subscriptions);
/**
* Check for correct amount of subscriptions:
@ -121,28 +121,28 @@ class RealtimeChannelsTest extends TestCase
* - 1 role:guest
* - 1 role:member
*/
$this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->subscriptions['1']);
$this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
/**
* Check for connections
* - Authenticated
* - Guests
*/
$this->assertCount($this->connectionsTotal, $this->connections);
$this->assertCount($this->connectionsTotal, $this->realtime->connections);
$this->realtime->unsubscribe(-1);
Realtime\Parser::unsubscribe(-1, $this->subscriptions, $this->connections);
$this->assertCount($this->connectionsTotal, $this->connections);
$this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->subscriptions['1']);
$this->assertCount($this->connectionsTotal, $this->realtime->connections);
$this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
for ($i = 0; $i < $this->connectionsCount; $i++) {
Realtime\Parser::unsubscribe($i, $this->subscriptions, $this->connections);
$this->realtime->unsubscribe($i);
$this->assertCount(($this->connectionsCount - $i - 1), $this->connections);
$this->assertCount(($this->connectionsCount - $i - 1), $this->realtime->connections);
}
$this->assertEmpty($this->connections);
$this->assertEmpty($this->subscriptions);
$this->assertEmpty($this->realtime->connections);
$this->assertEmpty($this->realtime->subscriptions);
}
/**
@ -161,10 +161,7 @@ class RealtimeChannelsTest extends TestCase
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $this->realtime->getReceivers($event);
/**
* Every Client subscribed to the Wildcard should receive this event.
@ -197,10 +194,7 @@ class RealtimeChannelsTest extends TestCase
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $this->realtime->getReceivers($event);
/**
* Every Role subscribed to a Channel should receive this event.
@ -234,10 +228,7 @@ class RealtimeChannelsTest extends TestCase
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $this->realtime->getReceivers($event);
/**
* Every Client subscribed to a Channel should receive this event.
@ -271,10 +262,7 @@ class RealtimeChannelsTest extends TestCase
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $this->realtime->getReceivers($event);
/**
* Every Team Member should receive this event.
@ -300,10 +288,7 @@ class RealtimeChannelsTest extends TestCase
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $this->realtime->getReceivers($event);
/**
* Only 1 Team Member of a role should have access to a specific channel.

View file

@ -0,0 +1,128 @@
<?php
namespace Appwrite\Tests;
use Appwrite\Messaging\Adapter\Realtime;
use PHPUnit\Framework\TestCase;
class MessagingGuestTest extends TestCase
{
public function testGuest()
{
$realtime = new Realtime();
$realtime->subscribe(
'1',
1,
['role:guest'],
['files' => 0, 'documents' => 0, 'documents.789' => 0, 'account.123' => 0]
);
$event = [
'project' => '1',
'permissions' => ['*'],
'data' => [
'channels' => [
0 => 'documents',
1 => 'documents',
]
]
];
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['role:guest'];
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['role:member'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['user:123'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:abc'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:abc/administrator'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:abc/god'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def/guest'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['user:456'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def/member'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['*'];
$event['data']['channels'] = ['documents.123'];
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['data']['channels'] = ['documents.789'];
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['project'] = '2';
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$realtime->unsubscribe(2);
$this->assertCount(1, $realtime->connections);
$this->assertCount(1, $realtime->subscriptions['1']);
$realtime->unsubscribe(1);
$this->assertEmpty($realtime->connections);
$this->assertEmpty($realtime->subscriptions);
}
}

View file

@ -3,14 +3,11 @@
namespace Appwrite\Tests;
use Appwrite\Database\Document;
use Appwrite\Realtime;
use Appwrite\Messaging\Adapter\Realtime;
use PHPUnit\Framework\TestCase;
class RealtimeTest extends TestCase
class MessagingTest extends TestCase
{
public $connections = [];
public $subscriptions = [];
public function setUp(): void
{
}
@ -21,55 +18,14 @@ class RealtimeTest extends TestCase
public function testUser()
{
Realtime\Parser::setUser(new Document([
'$id' => '123',
'memberships' => [
[
'teamId' => 'abc',
'roles' => [
'administrator',
'god'
]
],
[
'teamId' => 'def',
'roles' => [
'guest'
]
]
]
]));
$realtime = new Realtime();
$roles = Realtime\Parser::getRoles();
$this->assertCount(7, $roles);
$this->assertContains('user:123', $roles);
$this->assertContains('role:member', $roles);
$this->assertContains('team:abc', $roles);
$this->assertContains('team:abc/administrator', $roles);
$this->assertContains('team:abc/god', $roles);
$this->assertContains('team:def', $roles);
$this->assertContains('team:def/guest', $roles);
$channels = [
0 => 'files',
1 => 'documents',
2 => 'documents.789',
3 => 'account',
4 => 'account.456'
];
$channels = Realtime\Parser::parseChannels($channels);
$this->assertCount(4, $channels);
$this->assertArrayHasKey('files', $channels);
$this->assertArrayHasKey('documents', $channels);
$this->assertArrayHasKey('documents.789', $channels);
$this->assertArrayHasKey('account.123', $channels);
$this->assertArrayNotHasKey('account', $channels);
$this->assertArrayNotHasKey('account.456', $channels);
Realtime\Parser::subscribe('1', 1, $roles, $this->subscriptions, $this->connections, $channels);
$realtime->subscribe(
'1',
1,
['user:123', 'role:member', 'team:abc', 'team:abc/administrator', 'team:abc/moderator', 'team:def', 'team:def/guest'],
['files' => 0, 'documents' => 0, 'documents.789' => 0, 'account.123' => 0]
);
$event = [
'project' => '1',
@ -81,140 +37,162 @@ class RealtimeTest extends TestCase
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['role:member'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['user:123'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['team:abc'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['team:abc/administrator'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['team:abc/god'];
$event['permissions'] = ['team:abc/moderator'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['team:def'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['team:def/guest'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['user:456'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def/member'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['permissions'] = ['*'];
$event['data']['channels'] = ['documents.123'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
$event['data']['channels'] = ['documents.789'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['project'] = '2';
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$receivers = $realtime->getReceivers($event);
$this->assertEmpty($receivers);
Realtime\Parser::unsubscribe(2, $this->subscriptions, $this->connections);
$realtime->unsubscribe(2);
$this->assertCount(1, $this->connections);
$this->assertCount(7, $this->subscriptions['1']);
$this->assertCount(1, $realtime->connections);
$this->assertCount(7, $realtime->subscriptions['1']);
$realtime->unsubscribe(1);
Realtime\Parser::unsubscribe(1, $this->subscriptions, $this->connections);
$this->assertEmpty($realtime->connections);
$this->assertEmpty($realtime->subscriptions);
}
$this->assertEmpty($this->connections);
$this->assertEmpty($this->subscriptions);
public function testConvertChannelsGuest()
{
$user = new Document([
'$id' => ''
]);
$channels = [
0 => 'files',
1 => 'documents',
2 => 'documents.789',
3 => 'account',
4 => 'account.456'
];
$channels = Realtime::convertChannels($channels, $user);
$this->assertCount(3, $channels);
$this->assertArrayHasKey('files', $channels);
$this->assertArrayHasKey('documents', $channels);
$this->assertArrayHasKey('documents.789', $channels);
$this->assertArrayNotHasKey('account', $channels);
$this->assertArrayNotHasKey('account.456', $channels);
}
public function testConvertChannelsUser()
{
$user = new Document([
'$id' => '123',
'memberships' => [
[
'teamId' => 'abc',
'roles' => [
'administrator',
'moderator'
]
],
[
'teamId' => 'def',
'roles' => [
'guest'
]
]
]
]);
$channels = [
0 => 'files',
1 => 'documents',
2 => 'documents.789',
3 => 'account',
4 => 'account.456'
];
$channels = Realtime::convertChannels($channels, $user);
$this->assertCount(4, $channels);
$this->assertArrayHasKey('files', $channels);
$this->assertArrayHasKey('documents', $channels);
$this->assertArrayHasKey('documents.789', $channels);
$this->assertArrayHasKey('account.123', $channels);
$this->assertArrayNotHasKey('account', $channels);
$this->assertArrayNotHasKey('account.456', $channels);
}
}

View file

@ -1,191 +0,0 @@
<?php
namespace Appwrite\Tests;
use Appwrite\Database\Document;
use Appwrite\Realtime;
use PHPUnit\Framework\TestCase;
class RealtimeGuestTest extends TestCase
{
public $connections = [];
public $subscriptions = [];
public function testGuest()
{
Realtime\Parser::setUser(new Document([
'$id' => ''
]));
$roles = Realtime\Parser::getRoles();
$this->assertCount(1, $roles);
$this->assertContains('role:guest', $roles);
$channels = [
0 => 'files',
1 => 'documents',
2 => 'documents.789',
3 => 'account',
4 => 'account.456'
];
$channels = Realtime\Parser::parseChannels($channels);
$this->assertCount(3, $channels);
$this->assertArrayHasKey('files', $channels);
$this->assertArrayHasKey('documents', $channels);
$this->assertArrayHasKey('documents.789', $channels);
$this->assertArrayNotHasKey('account', $channels);
$this->assertArrayNotHasKey('account.456', $channels);
Realtime\Parser::subscribe('1', 1, $roles, $this->subscriptions, $this->connections, $channels);
$event = [
'project' => '1',
'permissions' => ['*'],
'data' => [
'channels' => [
0 => 'documents',
1 => 'documents',
]
]
];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['role:guest'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['permissions'] = ['role:member'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['user:123'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:abc'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:abc/administrator'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:abc/god'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def/guest'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['user:456'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['team:def/member'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['permissions'] = ['*'];
$event['data']['channels'] = ['documents.123'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
$event['data']['channels'] = ['documents.789'];
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertCount(1, $receivers);
$this->assertEquals(1, $receivers[0]);
$event['project'] = '2';
$receivers = Realtime\Parser::identifyReceivers(
$event,
$this->subscriptions
);
$this->assertEmpty($receivers);
Realtime\Parser::unsubscribe(2, $this->subscriptions, $this->connections);
$this->assertCount(1, $this->connections);
$this->assertCount(1, $this->subscriptions['1']);
Realtime\Parser::unsubscribe(1, $this->subscriptions, $this->connections);
$this->assertEmpty($this->connections);
$this->assertEmpty($this->subscriptions);
}
}