diff --git a/app/config/collections.php b/app/config/collections.php
index cab98fb8ca..2b806ac319 100644
--- a/app/config/collections.php
+++ b/app/config/collections.php
@@ -1598,8 +1598,8 @@ $collections = [
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
- 'label' => 'Command',
- 'key' => 'command',
+ 'label' => 'Entrypoint',
+ 'key' => 'entrypoint',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
diff --git a/app/config/runtimes.php b/app/config/runtimes.php
index d34cfc52e1..bdcf9e01f4 100644
--- a/app/config/runtimes.php
+++ b/app/config/runtimes.php
@@ -15,7 +15,11 @@ $allowList = empty(App::getEnv('_APP_FUNCTIONS_RUNTIMES')) ? [] : \explode(',',
$node = new Runtime('node', 'Node.js');
$node->addVersion('NG-Latest', 'node:16-alpine-nx', 'node-runtime', [System::X86, System::PPC, System::ARM]);
+$deno = new Runtime('deno', 'Deno');
+$deno->addVersion('NG-Latest', 'deno:latest-alpine-nx', 'deno-runtime', [System::X86, System::PPC, System::ARM]);
+
$runtimes->add($node);
+$runtimes->add($deno);
$runtimes = $runtimes->getAll(true, $allowList);
diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php
index 6f35d9016a..5a9dfe2c16 100644
--- a/app/controllers/api/functions.php
+++ b/app/controllers/api/functions.php
@@ -434,13 +434,13 @@ App::post('/v1/functions/:functionId/tags')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG)
->param('functionId', '', new UID(), 'Function unique ID.')
- ->param('command', '', new Text('1028'), 'Code execution command.')
+ ->param('entrypoint', '', new Text('1028'), 'Entrypoint File.')
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
->inject('request')
->inject('response')
->inject('projectDB')
->inject('usage')
- ->action(function ($functionId, $command, $file, $request, $response, $projectDB, $usage) {
+ ->action(function ($functionId, $entrypoint, $file, $request, $response, $projectDB, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
@@ -495,7 +495,7 @@ App::post('/v1/functions/:functionId/tags')
],
'functionId' => $function->getId(),
'dateCreated' => time(),
- 'command' => $command,
+ 'entrypoint' => $entrypoint,
'path' => $path,
'size' => $size
]);
diff --git a/app/executor.php b/app/executor.php
index 98ed8460d2..1eadd63250 100644
--- a/app/executor.php
+++ b/app/executor.php
@@ -423,10 +423,12 @@ function execute(string $trigger, string $projectId, string $executionId, string
\curl_setopt($ch, CURLOPT_POST, true);
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'path' => '/usr/code',
- 'file' => 'index.js',
+ 'file' => $tag->getAttribute('entrypoint', ''),
'env' => $vars,
- 'payload' => $data
+ 'payload' => $data,
+ 'timeout' => $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900))
]));
+
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
@@ -518,9 +520,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
return [
'status' => $functionStatus,
- 'exitCode' => $exitCode,
- 'stdout' => $stdout,
- 'stderr' => $stderr,
+ 'response' => $stdout,
'time' => $executionTime
];
}
diff --git a/app/views/console/functions/function.phtml b/app/views/console/functions/function.phtml
index 554139876e..c829d3e864 100644
--- a/app/views/console/functions/function.phtml
+++ b/app/views/console/functions/function.phtml
@@ -100,7 +100,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
-
+
@@ -599,7 +599,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
@@ -608,7 +608,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
@@ -634,8 +634,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
-
-
+
+
diff --git a/package-lock.json b/package-lock.json
index 2dd7d37b11..e63f4954ac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,7 +1,7 @@
{
"name": "appwrite-server",
"version": "0.1.0",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
"packages": {
"": {
@@ -2880,7 +2880,7 @@
"object-assign": "^4.0.1",
"read-pkg-up": "^1.0.1",
"redent": "^1.0.0",
- "trim-newlines": "^4.0.0"
+ "trim-newlines": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
@@ -7353,7 +7353,7 @@
"object-assign": "^4.0.1",
"read-pkg-up": "^1.0.1",
"redent": "^1.0.0",
- "trim-newlines": "^4.0.0"
+ "trim-newlines": "^1.0.0"
},
"dependencies": {
"minimist": {
@@ -8489,6 +8489,15 @@
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
"dev": true
},
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@@ -8517,15 +8526,6 @@
}
}
},
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
"strip-ansi": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
@@ -8699,8 +8699,7 @@
}
},
"trim-newlines": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz",
+ "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz",
"integrity": "sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew==",
"dev": true
},
diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js
index 5f334eb7de..e751f06939 100644
--- a/public/dist/scripts/app-all.js
+++ b/public/dist/scripts/app-all.js
@@ -174,10 +174,10 @@ let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let p
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"');}
+const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTag:(functionId,entrypoint,code)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
+if(typeof entrypoint==='undefined'){throw new AppwriteException('Missing required parameter: "entrypoint"');}
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;}
+let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(typeof entrypoint!=='undefined'){payload['entrypoint']=entrypoint;}
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(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof tagId==='undefined'){throw new AppwriteException('Missing required parameter: "tagId"');}
diff --git a/public/dist/scripts/app-dep.js b/public/dist/scripts/app-dep.js
index 4a5f301275..f506e690de 100644
--- a/public/dist/scripts/app-dep.js
+++ b/public/dist/scripts/app-dep.js
@@ -174,10 +174,10 @@ let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let p
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"');}
+const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),createTag:(functionId,entrypoint,code)=>__awaiter(this,void 0,void 0,function*(){if(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
+if(typeof entrypoint==='undefined'){throw new AppwriteException('Missing required parameter: "entrypoint"');}
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;}
+let path='/functions/{functionId}/tags'.replace('{functionId}',functionId);let payload={};if(typeof entrypoint!=='undefined'){payload['entrypoint']=entrypoint;}
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(typeof functionId==='undefined'){throw new AppwriteException('Missing required parameter: "functionId"');}
if(typeof tagId==='undefined'){throw new AppwriteException('Missing required parameter: "tagId"');}
diff --git a/public/scripts/dependencies/appwrite.js b/public/scripts/dependencies/appwrite.js
index c538693f63..a1e6efb129 100644
--- a/public/scripts/dependencies/appwrite.js
+++ b/public/scripts/dependencies/appwrite.js
@@ -1580,28 +1580,28 @@
* learn more about code packaging in the [Appwrite Cloud Functions
* tutorial](/docs/functions).
*
- * Use the "command" param to set the entry point used to execute your code.
+ * Use the "entrypoint" param to set the entry point used to execute your code.
*
* @param {string} functionId
- * @param {string} command
+ * @param {string} entrypoint
* @param {File} code
* @throws {AppwriteException}
* @returns {Promise}
*/
- createTag: (functionId, command, code) => __awaiter(this, void 0, void 0, function* () {
+ createTag: (functionId, entrypoint, 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 entrypoint === 'undefined') {
+ throw new AppwriteException('Missing required parameter: "entrypoint"');
}
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 entrypoint !== 'undefined') {
+ payload['entrypoint'] = entrypoint;
}
if (typeof code !== 'undefined') {
payload['code'] = code;
diff --git a/src/Appwrite/Utopia/Response/Model/SyncExecution.php b/src/Appwrite/Utopia/Response/Model/SyncExecution.php
index 4bdca8b922..d7d667ef40 100644
--- a/src/Appwrite/Utopia/Response/Model/SyncExecution.php
+++ b/src/Appwrite/Utopia/Response/Model/SyncExecution.php
@@ -16,24 +16,12 @@ class SyncExecution extends Model
'default' => '',
'example' => '5e5ea5c16897e',
])
- ->addRule('exitCode', [
- 'type' => self::TYPE_INTEGER,
- 'description' => 'Execution Exit Code.',
- 'default' => 0,
- 'example' => 0,
- ])
- ->addRule('stdout', [
+ ->addRule('response', [
'type' => self::TYPE_STRING,
- 'description' => 'Execution Stdout.',
+ 'description' => 'Execution Response.',
'default' => '',
'example' => 'Hello World!',
])
- ->addRule('stderr', [
- 'type' => self::TYPE_STRING,
- 'description' => 'Execution Stderr.',
- 'default' => '',
- 'example' => 'An error occoured: ....... example',
- ])
->addRule('time', [
'type' => self::TYPE_INTEGER,
'description' => 'Execution Time.',
diff --git a/src/Appwrite/Utopia/Response/Model/Tag.php b/src/Appwrite/Utopia/Response/Model/Tag.php
index b48e157291..fde42cbfbf 100644
--- a/src/Appwrite/Utopia/Response/Model/Tag.php
+++ b/src/Appwrite/Utopia/Response/Model/Tag.php
@@ -28,9 +28,9 @@ class Tag extends Model
'default' => 0,
'example' => 1592981250,
])
- ->addRule('command', [
+ ->addRule('entrypoint', [
'type' => self::TYPE_STRING,
- 'description' => 'The entrypoint command in use to execute the tag code.',
+ 'description' => 'The entrypoint file to use to execute the tag code.',
'default' => '',
'example' => 'enabled',
])
diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
index 454a149c3c..10ad410c10 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
@@ -75,7 +75,7 @@ class FunctionsCustomClientTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
- 'command' => 'php index.php',
+ 'entrypoint' => 'index.php',
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
]);
@@ -158,7 +158,7 @@ class FunctionsCustomClientTest extends Scope
'x-appwrite-project' => $projectId,
'x-appwrite-key' => $apikey,
], [
- 'command' => 'php index.php',
+ 'entrypoint' => 'index.php',
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php-fn.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'), //different tarball names intentional
]);
diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
index 775eca06e2..c87091eb97 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
@@ -182,7 +182,7 @@ class FunctionsCustomServerTest extends Scope
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
- 'command' => 'php index.php',
+ 'entrypoint' => 'index.php',
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
]);
@@ -191,7 +191,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $tag['headers']['status-code']);
$this->assertNotEmpty($tag['body']['$id']);
$this->assertIsInt($tag['body']['dateCreated']);
- $this->assertEquals('php index.php', $tag['body']['command']);
+ $this->assertEquals('php index.php', $tag['body']['entrypoint']);
$this->assertGreaterThan(10000, $tag['body']['size']);
/**
@@ -454,7 +454,7 @@ class FunctionsCustomServerTest extends Scope
{
$name = 'php-8.0';
$code = realpath(__DIR__ . '/../../../resources/functions').'/timeout.tar.gz';
- $command = 'php index.php';
+ $entrypoint = 'php index.php';
$timeout = 2;
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
@@ -477,7 +477,7 @@ class FunctionsCustomServerTest extends Scope
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
- 'command' => $command,
+ 'entrypoint' => $entrypoint,
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
]);
@@ -532,7 +532,7 @@ class FunctionsCustomServerTest extends Scope
{
$name = 'php-8.0';
$code = realpath(__DIR__ . '/../../../resources/functions').'/php-fn.tar.gz';
- $command = 'php index.php';
+ $entrypoint = 'index.php';
$timeout = 2;
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
@@ -555,7 +555,7 @@ class FunctionsCustomServerTest extends Scope
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
- 'command' => $command,
+ 'entrypoint' => $entrypoint,
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
]);
diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php
index 0d3678eaf2..5d61193032 100644
--- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php
+++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php
@@ -384,7 +384,7 @@ class WebhooksCustomServerTest extends Scope
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
- 'command' => 'php index.php',
+ 'entrypoint' => 'index.php',
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/timeout.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
]);