diff --git a/src/app.js b/src/app.js index abe05a6..1eff6b5 100644 --- a/src/app.js +++ b/src/app.js @@ -1,7 +1,5 @@ -const { Client, Databases, Functions, Account, Users, Storage, TablesDB, Query, Permission, Role, ID, Runtime, ExecutionMethod, IndexType } = require('node-appwrite'); +const { Client, Functions, Account, Users, Storage, TablesDB, Query, Permission, Role, ID, Runtime, ExecutionMethod, IndexType, RelationshipType, RelationMutate, MessagingProviderType } = require('node-appwrite'); const chalk = require('chalk'); -const fs = require('fs'); -const path = require('path'); const { InputFile } = require('node-appwrite/file'); // Config @@ -11,16 +9,12 @@ const client = new Client() .setKey(process.env.APPWRITE_API_KEY || 'YOUR_API_KEY'); // Replace with your API Key //.setJWT('jwt'); // Use this to authenticate with JWT generated from Client SDK -const databases = new Databases(client); const functions = new Functions(client); const storage = new Storage(client); const users = new Users(client); const account = new Account(client); const tablesDB = new TablesDB(client); -let databaseId; -let collectionId; -let documentId; let userId; let bucketId; let fileId; @@ -32,258 +26,9 @@ let tablesDatabaseId; let tableId; let rowId; let transactionId; +let targetId; // List of API Definitions -const createDatabase = async () => { - console.log(chalk.greenBright('Running Create Database API')); - - const response = await databases.create({ - databaseId: ID.unique(), - name: "Default" - }); - - databaseId = response.$id; - - console.log(response); -} - -const listDatabases = async () => { - console.log(chalk.greenBright("Running List Databases API")); - - const response = await databases.list(); - - console.log(response); -} - -const getDatabase = async () => { - console.log(chalk.greenBright("Running Get Database API")); - - const response = await databases.get({ - databaseId - }); - - console.log(response); -} - -const updateDatabase = async () => { - console.log(chalk.greenBright('Running Update Database API')); - - const response = await databases.update({ - databaseId, - name: "Updated Database" - }); - - console.log(response); -} - -const deleteDatabase = async () => { - console.log(chalk.greenBright("Running Delete Database API")); - - const response = await databases.delete({ - databaseId - }); - - console.log(response); -} - -const createCollection = async () => { - console.log(chalk.greenBright('Running Create Collection API')); - - const response = await databases.createCollection({ - databaseId, - collectionId: ID.unique(), - name: "Collection", - permissions: [ - Permission.read(Role.any()), - Permission.create(Role.users()), - Permission.update(Role.users()), - Permission.delete(Role.users()), - ] - }); - - collectionId = response.$id; - console.log(response); - - const nameAttributeResponse = await databases.createStringAttribute({ - databaseId, - collectionId, - key: 'name', - size: 255, - required: false, - xdefault: "Empty Name", - array: false - }); - console.log(nameAttributeResponse); - - const yearAttributeResponse = await databases.createIntegerAttribute({ - databaseId, - collectionId, - key: 'release_year', - required: false, - min: 0, - max: 5000, - xdefault: 1970, - array: false - }); - console.log(yearAttributeResponse); - - console.log("Waiting a little to ensure attributes are created ..."); - await new Promise((resolve) => setTimeout(resolve, 2000)); - - const yearIndexResponse = await databases.createIndex({ - databaseId, - collectionId, - key: 'key_release_year_asc', - type: IndexType.Key, - attributes: ['release_year'], - orders: ['ASC'], - }); - console.log(yearIndexResponse); - - console.log("Waiting a little to ensure index is created ..."); - await new Promise((resolve) => setTimeout(resolve, 2000)); -} - -const listCollections = async () => { - console.log(chalk.greenBright('Running List Collections API')); - - const response = await databases.listCollections({ - databaseId - }); - - console.log(response); -} - -const getCollection = async () => { - console.log(chalk.greenBright("Running Get Collection API")); - - const response = await databases.getCollection({ - databaseId, - collectionId - }); - - console.log(response); -} - -const updateCollection = async () => { - console.log(chalk.greenBright("Running Update Collection API")); - - const response = await databases.updateCollection({ - databaseId, - collectionId, - name: "Updated Collection" - }); - - console.log(response); -} - -const deleteCollection = async () => { - console.log(chalk.greenBright("Running Delete Collection API")); - - const response = await databases.deleteCollection({ - databaseId, - collectionId - }); - - console.log(response); -} - -const listAttributes = async () => { - console.log(chalk.greenBright('Running List Attributes API')); - - const response = await databases.listAttributes({ - databaseId, - collectionId - }); - - console.log(response); -} - -const listIndexes = async () => { - console.log(chalk.greenBright('Running List Indexes API')); - - const response = await databases.listIndexes({ - databaseId, - collectionId - }); - - console.log(response); -} - -const createDocument = async () => { - console.log(chalk.greenBright('Running Add Document API')); - - const response = await databases.createDocument({ - databaseId, - collectionId, - documentId: ID.unique(), - data: { - name: 'Spider Man', - release_year: 1920 - }, - permissions: [ - Permission.read(Role.any()), - Permission.update(Role.users()), - Permission.delete(Role.users()), - ] - }); - documentId = response.$id; - - console.log(response); -} - -const listDocuments = async () => { - console.log(chalk.greenBright('Running List Documents API')); - - const response = await databases.listDocuments({ - databaseId, - collectionId, - queries: [ - Query.equal('release_year', 1920), - ] - }); - - console.log(response); -} - -const getDocument = async () => { - console.log(chalk.greenBright("Running Get Document API")); - - const response = await databases.getDocument({ - databaseId, - collectionId, - documentId - }); - - console.log(response); -} - -const updateDocument = async () => { - console.log(chalk.greenBright("Running Update Document API")); - - const response = await databases.updateDocument({ - databaseId, - collectionId, - documentId, - data: { - release_year: 2005 - } - }); - - console.log(response); -} - -const deleteDocument = async () => { - console.log(chalk.greenBright("Running Delete Document API")); - - const response = await databases.deleteDocument({ - databaseId, - collectionId, - documentId - }); - - console.log(response); -} const createBucket = async () => { console.log(chalk.greenBright("Running Create Bucket API")); @@ -413,6 +158,21 @@ const getFilePreview = async () => { } } +const getFileView = async () => { + console.log(chalk.greenBright("Running Get File View API")); + + try { + const response = await storage.getFileView({ + bucketId, + fileId + }); + + console.log(`View file: ${response.byteLength} bytes`); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + const updateFile = async () => { console.log(chalk.greenBright("Running Update File API")); @@ -474,7 +234,7 @@ const getUser = async () => { } const getAccount = async () => { - console.log(chalk.greenBright('Running List Users API')); + console.log(chalk.greenBright('Running Get Account API')); const response = await account.get(); @@ -526,144 +286,650 @@ const deleteUser = async () => { console.log(response); } -const createFunction = async () => { - console.log(chalk.greenBright('Running Create Function API')); +// --- Additional Users API Methods --- - const response = await functions.create({ - functionId: ID.unique(), - name: "Node Hello World", - runtime: Runtime.Node22, - execute: [Role.any()], - entrypoint: "index.js", - timeout: 15, - enabled: true, - logging: true - }); +const updateUserEmail = async () => { + console.log(chalk.greenBright('Running Update User Email API')); - functionId = response.$id; + const response = await users.updateEmail({ + userId, + email: 'updated_' + new Date().getTime() + '@example.com' + }); console.log(response); } -const listFunctions = async () => { - console.log(chalk.greenBright('Running List Functions API')); +const updateUserPassword = async () => { + console.log(chalk.greenBright('Running Update User Password API')); - let response = await functions.list(); + const response = await users.updatePassword({ + userId, + password: 'newPassword@456' + }); console.log(response); } -const getFunction = async () => { - console.log(chalk.greenBright('Running Get Function API')); +const updateUserPhone = async () => { + console.log(chalk.greenBright('Running Update User Phone API')); - let response = await functions.get({ - functionId + const response = await users.updatePhone({ + userId, + number: '+14155551234' }); console.log(response); } -const updateFunction = async () => { - console.log(chalk.greenBright('Running Update Function API')); +const updateUserStatus = async () => { + console.log(chalk.greenBright('Running Update User Status API')); - let response = await functions.update({ - functionId, - name: "Updated Node Hello World", - runtime: Runtime.Node22, - execute: [Role.any()], - entrypoint: "index.js", - timeout: 30, - enabled: true, - logging: true + // Disable user + const response = await users.updateStatus({ + userId, + status: false }); - console.log(response); + console.log('Disabled user:', response); + + // Re-enable user + const reEnable = await users.updateStatus({ + userId, + status: true + }); + + console.log('Re-enabled user:', reEnable); } -const uploadDeployment = async () => { - console.log(chalk.greenBright('Running Upload Deployment API')); +const updateUserLabels = async () => { + console.log(chalk.greenBright('Running Update User Labels API')); - let response = await functions.createDeployment({ - functionId, - code: InputFile.fromPath("./resources/code.tar.gz", "code.tar.gz"), - activate: true, - entrypoint: "index.js" + const response = await users.updateLabels({ + userId, + labels: ['vip', 'betatester'] }); - deploymentId = response.$id; console.log(response); - - console.log("Waiting for deployment to be ready ..."); - - // Poll for deployment status until it's ready - let maxAttempts = 30; - let attempts = 0; - while (attempts < maxAttempts) { - await new Promise((resolve) => setTimeout(resolve, 2000)); - const deployment = await functions.getDeployment({ - functionId, - deploymentId - }); - console.log(`Deployment status: ${deployment.status}`); - - if (deployment.status === 'ready') { - console.log("Deployment is ready!"); - break; - } else if (deployment.status === 'failed') { - throw new Error("Deployment failed to build"); - } - attempts++; - } - - if (attempts >= maxAttempts) { - throw new Error("Deployment timed out waiting to be ready"); - } } -const listDeployments = async () => { - console.log(chalk.greenBright('Running List Deployments API')); +const listUserLogs = async () => { + console.log(chalk.greenBright('Running List User Logs API')); - let response = await functions.listDeployments({ - functionId + const response = await users.listLogs({ + userId }); console.log(response); } -const listExecutions = async () => { - console.log(chalk.greenBright('Running List Executions API')); +const listUserMemberships = async () => { + console.log(chalk.greenBright('Running List User Memberships API')); - let response = await functions.listExecutions({ - functionId + const response = await users.listMemberships({ + userId }); console.log(response); } -const createVariable = async () => { - console.log(chalk.greenBright('Running Create Variable API')); +const listUserSessions = async () => { + console.log(chalk.greenBright('Running List User Sessions API')); - let response = await functions.createVariable({ - functionId, - key: 'MY_VAR', - value: 'hello123' + const response = await users.listSessions({ + userId }); - variableId = response.$id; console.log(response); } -const listVariables = async () => { - console.log(chalk.greenBright('Running List Variables API')); +const createUserSession = async () => { + console.log(chalk.greenBright('Running Create User Session API')); - let response = await functions.listVariables({ - functionId + try { + const response = await users.createSession({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped (may require specific auth config): ${err.message}`)); + } +} + +const deleteUserSessions = async () => { + console.log(chalk.greenBright('Running Delete User Sessions API')); + + const response = await users.deleteSessions({ + userId }); console.log(response); } -const getVariable = async () => { +const updateUserEmailVerification = async () => { + console.log(chalk.greenBright('Running Update User Email Verification API')); + + const response = await users.updateEmailVerification({ + userId, + emailVerification: true + }); + + console.log(response); +} + +const updateUserPhoneVerification = async () => { + console.log(chalk.greenBright('Running Update User Phone Verification API')); + + const response = await users.updatePhoneVerification({ + userId, + phoneVerification: true + }); + + console.log(response); +} + +const listUserIdentities = async () => { + console.log(chalk.greenBright('Running List User Identities API')); + + try { + const response = await users.listIdentities(); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const deleteUserIdentity = async () => { + console.log(chalk.greenBright('Running Delete User Identity API')); + + try { + // List identities first and delete one if available + const identities = await users.listIdentities(); + if (identities.identities && identities.identities.length > 0) { + const response = await users.deleteIdentity({ + identityId: identities.identities[0].$id + }); + console.log(response); + } else { + console.log(chalk.yellow('No identities to delete')); + } + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const updateUserMFA = async () => { + console.log(chalk.greenBright('Running Update User MFA API')); + + try { + // Enable MFA + const response = await users.updateMFA({ + userId, + mfa: true + }); + console.log('Enabled MFA:', response); + + // Disable MFA + const disableResponse = await users.updateMFA({ + userId, + mfa: false + }); + console.log('Disabled MFA:', disableResponse); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const listUserMFAFactors = async () => { + console.log(chalk.greenBright('Running List User MFA Factors API')); + + try { + const response = await users.listMFAFactors({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createUserMFARecoveryCodes = async () => { + console.log(chalk.greenBright('Running Create User MFA Recovery Codes API')); + + try { + const response = await users.createMFARecoveryCodes({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const getUserMFARecoveryCodes = async () => { + console.log(chalk.greenBright('Running Get User MFA Recovery Codes API')); + + try { + const response = await users.getMFARecoveryCodes({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const updateUserMFARecoveryCodes = async () => { + console.log(chalk.greenBright('Running Update (Regenerate) User MFA Recovery Codes API')); + + try { + const response = await users.updateMFARecoveryCodes({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const deleteUserMFAAuthenticator = async () => { + console.log(chalk.greenBright('Running Delete User MFA Authenticator API')); + + try { + const response = await users.deleteMFAAuthenticator({ + userId, + type: 'totp' + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createUserTarget = async () => { + console.log(chalk.greenBright('Running Create User Target API')); + + try { + const response = await users.createTarget({ + userId, + targetId: ID.unique(), + providerType: MessagingProviderType.Email, + identifier: 'target_' + new Date().getTime() + '@example.com' + }); + targetId = response.$id; + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const getUserTarget = async () => { + console.log(chalk.greenBright('Running Get User Target API')); + + try { + if (!targetId) { console.log(chalk.yellow('Skipped: no targetId')); return; } + const response = await users.getTarget({ + userId, + targetId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const listUserTargets = async () => { + console.log(chalk.greenBright('Running List User Targets API')); + + try { + const response = await users.listTargets({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const updateUserTarget = async () => { + console.log(chalk.greenBright('Running Update User Target API')); + + try { + if (!targetId) { console.log(chalk.yellow('Skipped: no targetId')); return; } + const response = await users.updateTarget({ + userId, + targetId, + name: 'Updated Target' + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const deleteUserTarget = async () => { + console.log(chalk.greenBright('Running Delete User Target API')); + + try { + if (!targetId) { console.log(chalk.yellow('Skipped: no targetId')); return; } + const response = await users.deleteTarget({ + userId, + targetId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createUserJWT = async () => { + console.log(chalk.greenBright('Running Create User JWT API')); + + try { + const response = await users.createJWT({ + userId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createUserToken = async () => { + console.log(chalk.greenBright('Running Create User Token API')); + + try { + const response = await users.createToken({ + userId, + length: 6, + expire: 60 + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +// --- Specialized User Creation (Hash Algorithms) --- + +const createArgon2User = async () => { + console.log(chalk.greenBright('Running Create Argon2 User API')); + + try { + const response = await users.createArgon2User({ + userId: ID.unique(), + email: 'argon2_' + new Date().getTime() + '@example.com', + password: '$argon2id$v=19$m=65536,t=3,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+daw', + name: 'Argon2 User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createBcryptUser = async () => { + console.log(chalk.greenBright('Running Create Bcrypt User API')); + + try { + const response = await users.createBcryptUser({ + userId: ID.unique(), + email: 'bcrypt_' + new Date().getTime() + '@example.com', + password: '$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW', + name: 'Bcrypt User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createMD5User = async () => { + console.log(chalk.greenBright('Running Create MD5 User API')); + + try { + const response = await users.createMD5User({ + userId: ID.unique(), + email: 'md5_' + new Date().getTime() + '@example.com', + password: '5d41402abc4b2a76b9719d911017c592', + name: 'MD5 User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createSHAUser = async () => { + console.log(chalk.greenBright('Running Create SHA User API')); + + try { + const response = await users.createSHAUser({ + userId: ID.unique(), + email: 'sha_' + new Date().getTime() + '@example.com', + password: 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d', + name: 'SHA User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createPHPassUser = async () => { + console.log(chalk.greenBright('Running Create PHPass User API')); + + try { + const response = await users.createPHPassUser({ + userId: ID.unique(), + email: 'phpass_' + new Date().getTime() + '@example.com', + password: '$P$B5WY6IigCfNBkOVNJgrVOHFTlaJm3R/', + name: 'PHPass User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createScryptUser = async () => { + console.log(chalk.greenBright('Running Create Scrypt User API')); + + try { + const response = await users.createScryptUser({ + userId: ID.unique(), + email: 'scrypt_' + new Date().getTime() + '@example.com', + password: 'f7f7ad57b9ba3a7f697c0d3cb429a007d48fb3e38b438b72c6e9a11797a68f92', + passwordSalt: 'salt123', + passwordCpu: 8, + passwordMemory: 14, + passwordParallel: 1, + passwordLength: 64, + name: 'Scrypt User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createScryptModifiedUser = async () => { + console.log(chalk.greenBright('Running Create Scrypt Modified User API')); + + try { + const response = await users.createScryptModifiedUser({ + userId: ID.unique(), + email: 'scryptmod_' + new Date().getTime() + '@example.com', + password: 'UlLCFMhENH0LTA==', + passwordSalt: 'c2FsdA==', + passwordSaltSeparator: 'Bw==', + passwordSignerKey: 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oJpCo/Y7KTjfAn3OOdh0XAr/A==', + name: 'Scrypt Modified User' + }); + console.log(response); + await users.delete({ userId: response.$id }); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createFunction = async () => { + console.log(chalk.greenBright('Running Create Function API')); + + const response = await functions.create({ + functionId: ID.unique(), + name: "Node Hello World", + runtime: Runtime.Node22, + execute: [Role.any()], + entrypoint: "index.js", + timeout: 15, + enabled: true, + logging: true + }); + + functionId = response.$id; + + console.log(response); +} + +const listFunctions = async () => { + console.log(chalk.greenBright('Running List Functions API')); + + let response = await functions.list(); + + console.log(response); +} + +const getFunction = async () => { + console.log(chalk.greenBright('Running Get Function API')); + + let response = await functions.get({ + functionId + }); + + console.log(response); +} + +const updateFunction = async () => { + console.log(chalk.greenBright('Running Update Function API')); + + let response = await functions.update({ + functionId, + name: "Updated Node Hello World", + runtime: Runtime.Node22, + execute: [Role.any()], + entrypoint: "index.js", + timeout: 30, + enabled: true, + logging: true + }); + + console.log(response); +} + +const uploadDeployment = async () => { + console.log(chalk.greenBright('Running Upload Deployment API')); + + let response = await functions.createDeployment({ + functionId, + code: InputFile.fromPath("./resources/code.tar.gz", "code.tar.gz"), + activate: true, + entrypoint: "index.js" + }); + + deploymentId = response.$id; + console.log(response); + + console.log("Waiting for deployment to be ready ..."); + + // Poll for deployment status until it's ready + let maxAttempts = 30; + let attempts = 0; + while (attempts < maxAttempts) { + await new Promise((resolve) => setTimeout(resolve, 2000)); + const deployment = await functions.getDeployment({ + functionId, + deploymentId + }); + console.log(`Deployment status: ${deployment.status}`); + + if (deployment.status === 'ready') { + console.log("Deployment is ready!"); + break; + } else if (deployment.status === 'failed') { + throw new Error("Deployment failed to build"); + } + attempts++; + } + + if (attempts >= maxAttempts) { + throw new Error("Deployment timed out waiting to be ready"); + } +} + +const listDeployments = async () => { + console.log(chalk.greenBright('Running List Deployments API')); + + let response = await functions.listDeployments({ + functionId + }); + + console.log(response); +} + +const listExecutions = async () => { + console.log(chalk.greenBright('Running List Executions API')); + + let response = await functions.listExecutions({ + functionId + }); + + console.log(response); +} + +const createVariable = async () => { + console.log(chalk.greenBright('Running Create Variable API')); + + let response = await functions.createVariable({ + functionId, + key: 'MY_VAR', + value: 'hello123' + }); + + variableId = response.$id; + console.log(response); +} + +const listVariables = async () => { + console.log(chalk.greenBright('Running List Variables API')); + + let response = await functions.listVariables({ + functionId + }); + + console.log(response); +} + +const getVariable = async () => { console.log(chalk.greenBright('Running Get Variable API')); let response = await functions.getVariable({ @@ -741,14 +1007,167 @@ const executeAsync = async () => { console.log(asyncResponse); } -const deleteFunction = async () => { - console.log(chalk.greenBright('Running Delete function API')); +const deleteFunction = async () => { + console.log(chalk.greenBright('Running Delete function API')); + + const response = await functions.delete({ + functionId + }); + + console.log(response); +} + +// --- Additional Functions API Methods --- + +const listRuntimes = async () => { + console.log(chalk.greenBright('Running List Runtimes API')); + + try { + const response = await functions.listRuntimes(); + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped (requires public scope): ${err.message}`)); + } +} + +const listSpecifications = async () => { + console.log(chalk.greenBright('Running List Specifications API')); + + try { + const response = await functions.listSpecifications(); + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped (requires public scope): ${err.message}`)); + } +} + +const deleteDeployment = async () => { + console.log(chalk.greenBright('Running Delete Deployment API')); + + // deploymentId is set from uploadDeployment + try { + const response = await functions.deleteDeployment({ + functionId, + deploymentId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const deleteExecution = async () => { + console.log(chalk.greenBright('Running Delete Execution API')); + + try { + if (!executionId) { console.log(chalk.yellow('Skipped: no executionId')); return; } + const response = await functions.deleteExecution({ + functionId, + executionId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const getDeploymentDownload = async () => { + console.log(chalk.greenBright('Running Get Deployment Download API')); + + try { + const response = await functions.getDeploymentDownload({ + functionId, + deploymentId + }); + + console.log(`Deployment download: ${response.byteLength} bytes`); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const updateFunctionDeployment = async () => { + console.log(chalk.greenBright('Running Update Function Deployment (set active) API')); + + try { + const response = await functions.updateFunctionDeployment({ + functionId, + deploymentId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const updateDeploymentStatus = async () => { + console.log(chalk.greenBright('Running Update Deployment Status API')); + + try { + const response = await functions.updateDeploymentStatus({ + functionId, + deploymentId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createDuplicateDeployment = async () => { + console.log(chalk.greenBright('Running Create Duplicate Deployment API')); + + try { + const response = await functions.createDuplicateDeployment({ + functionId, + deploymentId + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createTemplateDeployment = async () => { + console.log(chalk.greenBright('Running Create Template Deployment API')); + + try { + const response = await functions.createTemplateDeployment({ + functionId, + repository: 'https://github.com/appwrite/templates', + owner: 'appwrite', + rootDirectory: 'node/starter', + type: 'branch', + reference: 'main', + activate: false + }); + + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped: ${err.message}`)); + } +} + +const createVcsDeployment = async () => { + console.log(chalk.greenBright('Running Create VCS Deployment API')); - const response = await functions.delete({ - functionId - }); + try { + const response = await functions.createVcsDeployment({ + functionId, + type: 'branch', + reference: 'main', + activate: false + }); - console.log(response); + console.log(response); + } catch (err) { + console.log(chalk.yellow(`Skipped (requires VCS installation): ${err.message}`)); + } } // TablesDB API Definitions @@ -892,6 +1311,218 @@ const createColumns = async () => { await new Promise((resolve) => setTimeout(resolve, 2000)); } +// --- Additional TablesDB Column Types --- + +const createAdditionalColumns = async () => { + console.log(chalk.greenBright('Running TablesDB Create Additional Column Types API')); + + const datetimeCol = await tablesDB.createDatetimeColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'release_date', + required: false + }); + console.log('Datetime column:', datetimeCol); + + const emailCol = await tablesDB.createEmailColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'contact_email', + required: false + }); + console.log('Email column:', emailCol); + + const enumCol = await tablesDB.createEnumColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'genre', + elements: ['action', 'comedy', 'drama', 'sci-fi', 'thriller'], + required: false, + xdefault: 'drama' + }); + console.log('Enum column:', enumCol); + + const ipCol = await tablesDB.createIpColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'server_ip', + required: false + }); + console.log('IP column:', ipCol); + + const urlCol = await tablesDB.createUrlColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'trailer_url', + required: false + }); + console.log('URL column:', urlCol); + + // Geo/spatial columns + try { + const pointCol = await tablesDB.createPointColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'filming_location', + required: false + }); + console.log('Point column:', pointCol); + + const lineCol = await tablesDB.createLineColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'tour_route', + required: false + }); + console.log('Line column:', lineCol); + + const polygonCol = await tablesDB.createPolygonColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'filming_area', + required: false + }); + console.log('Polygon column:', polygonCol); + } catch (err) { + console.log(chalk.yellow(`Geo columns skipped (may not be supported): ${err.message}`)); + } + + console.log("Waiting a little to ensure columns are created ..."); + await new Promise((resolve) => setTimeout(resolve, 2000)); +} + +const updateColumns = async () => { + console.log(chalk.greenBright('Running TablesDB Update Columns API')); + + const stringUpdate = await tablesDB.updateStringColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'title', + required: true, + xdefault: null, + size: 500 + }); + console.log('Updated string column:', stringUpdate); + + const intUpdate = await tablesDB.updateIntegerColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'year', + required: false, + xdefault: 2000, + min: 1800, + max: 2200 + }); + console.log('Updated integer column:', intUpdate); + + const floatUpdate = await tablesDB.updateFloatColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'rating', + required: false, + xdefault: 5.0, + min: 0, + max: 10 + }); + console.log('Updated float column:', floatUpdate); + + const boolUpdate = await tablesDB.updateBooleanColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'is_released', + required: false, + xdefault: false + }); + console.log('Updated boolean column:', boolUpdate); + + const datetimeUpdate = await tablesDB.updateDatetimeColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'release_date', + required: false, + xdefault: null + }); + console.log('Updated datetime column:', datetimeUpdate); + + const emailUpdate = await tablesDB.updateEmailColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'contact_email', + required: false, + xdefault: 'movies@example.com' + }); + console.log('Updated email column:', emailUpdate); + + const enumUpdate = await tablesDB.updateEnumColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'genre', + elements: ['action', 'comedy', 'drama', 'sci-fi', 'thriller', 'horror'], + required: false, + xdefault: 'action' + }); + console.log('Updated enum column:', enumUpdate); + + const ipUpdate = await tablesDB.updateIpColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'server_ip', + required: false, + xdefault: '192.168.1.1' + }); + console.log('Updated IP column:', ipUpdate); + + const urlUpdate = await tablesDB.updateUrlColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'trailer_url', + required: false, + xdefault: 'https://example.com/trailer' + }); + console.log('Updated URL column:', urlUpdate); + + // Geo/spatial column updates + try { + const pointUpdate = await tablesDB.updatePointColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'filming_location', + required: false + }); + console.log('Updated point column:', pointUpdate); + + const lineUpdate = await tablesDB.updateLineColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'tour_route', + required: false + }); + console.log('Updated line column:', lineUpdate); + + const polygonUpdate = await tablesDB.updatePolygonColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'filming_area', + required: false + }); + console.log('Updated polygon column:', polygonUpdate); + } catch (err) { + console.log(chalk.yellow(`Geo column updates skipped: ${err.message}`)); + } +} + +const getTableIndex = async () => { + console.log(chalk.greenBright('Running TablesDB Get Index API')); + + const response = await tablesDB.getIndex({ + databaseId: tablesDatabaseId, + tableId, + key: 'idx_year' + }); + + console.log(response); +} + const listTableColumns = async () => { console.log(chalk.greenBright('Running TablesDB List Columns API')); @@ -1007,6 +1638,165 @@ const updateTableRow = async () => { console.log(response); } +// --- Bulk Row Operations --- + +const createTableRows = async () => { + console.log(chalk.greenBright('Running TablesDB Bulk Create Rows API')); + + const response = await tablesDB.createRows({ + databaseId: tablesDatabaseId, + tableId, + rows: [ + { + $id: ID.unique(), + title: 'Pulp Fiction', year: 1994, rating: 8.9, is_released: true, genre: 'thriller', + $permissions: [Permission.read(Role.any()), Permission.update(Role.users()), Permission.delete(Role.users())] + }, + { + $id: ID.unique(), + title: 'Fight Club', year: 1999, rating: 8.8, is_released: true, genre: 'drama', + $permissions: [Permission.read(Role.any()), Permission.update(Role.users()), Permission.delete(Role.users())] + }, + { + $id: ID.unique(), + title: 'Forrest Gump', year: 1994, rating: 8.8, is_released: true, genre: 'drama', + $permissions: [Permission.read(Role.any()), Permission.update(Role.users()), Permission.delete(Role.users())] + } + ] + }); + + console.log(response); +} + +const upsertTableRow = async () => { + console.log(chalk.greenBright('Running TablesDB Upsert Row API')); + + // Upsert existing row (update) + const response = await tablesDB.upsertRow({ + databaseId: tablesDatabaseId, + tableId, + rowId, + data: { + title: 'Inception (Director\'s Cut)', + year: 2010, + rating: 9.2, + is_released: true + }, + permissions: [ + Permission.read(Role.any()), + Permission.update(Role.users()), + Permission.delete(Role.users()), + ] + }); + console.log('Upserted (updated) row:', response); + + // Upsert new row (create) + const newRowResponse = await tablesDB.upsertRow({ + databaseId: tablesDatabaseId, + tableId, + rowId: ID.unique(), + data: { + title: 'Memento', + year: 2000, + rating: 8.4, + is_released: true, + genre: 'thriller' + }, + permissions: [ + Permission.read(Role.any()), + Permission.update(Role.users()), + Permission.delete(Role.users()), + ] + }); + console.log('Upserted (created) row:', newRowResponse); +} + +const upsertTableRows = async () => { + console.log(chalk.greenBright('Running TablesDB Bulk Upsert Rows API')); + + const response = await tablesDB.upsertRows({ + databaseId: tablesDatabaseId, + tableId, + rows: [ + { + $id: ID.unique(), + title: 'The Prestige', year: 2006, rating: 8.5, is_released: true, genre: 'thriller', + $permissions: [Permission.read(Role.any()), Permission.update(Role.users()), Permission.delete(Role.users())] + }, + { + $id: ID.unique(), + title: 'Insomnia', year: 2002, rating: 7.2, is_released: true, genre: 'thriller', + $permissions: [Permission.read(Role.any()), Permission.update(Role.users()), Permission.delete(Role.users())] + } + ] + }); + + console.log(response); +} + +const updateTableRows = async () => { + console.log(chalk.greenBright('Running TablesDB Bulk Update Rows API')); + + const response = await tablesDB.updateRows({ + databaseId: tablesDatabaseId, + tableId, + data: { + genre: 'action' + }, + queries: [ + Query.greaterThan('rating', 9.0) + ] + }); + + console.log(response); +} + +const deleteTableRows = async () => { + console.log(chalk.greenBright('Running TablesDB Bulk Delete Rows API')); + + const response = await tablesDB.deleteRows({ + databaseId: tablesDatabaseId, + tableId, + queries: [ + Query.lessThan('rating', 7.5) + ] + }); + + console.log(response); +} + +// --- Atomic Row Column Operations --- + +const incrementRowColumn = async () => { + console.log(chalk.greenBright('Running TablesDB Increment Row Column API')); + + const response = await tablesDB.incrementRowColumn({ + databaseId: tablesDatabaseId, + tableId, + rowId, + column: 'rating', + value: 0.5, + max: 10 + }); + + console.log('Incremented rating by 0.5:', response); +} + +const decrementRowColumn = async () => { + console.log(chalk.greenBright('Running TablesDB Decrement Row Column API')); + + const response = await tablesDB.decrementRowColumn({ + databaseId: tablesDatabaseId, + tableId, + rowId, + column: 'rating', + value: 0.2, + min: 0 + }); + + console.log('Decremented rating by 0.2:', response); +} + const deleteTableRow = async () => { console.log(chalk.greenBright('Running TablesDB Delete Row API')); @@ -1064,6 +1854,82 @@ const deleteTablesDatabase = async () => { console.log(response); } +// --- TablesDB Relationship Column --- + +const createTablesRelationshipDemo = async () => { + console.log(chalk.greenBright('Running TablesDB Create Relationship Column API')); + + // Create a second table for the relationship + const relTable = await tablesDB.createTable({ + databaseId: tablesDatabaseId, + tableId: ID.unique(), + name: "Directors", + permissions: [ + Permission.read(Role.any()), + Permission.create(Role.users()), + Permission.update(Role.users()), + Permission.delete(Role.users()), + ] + }); + const secondTableId = relTable.$id; + + await tablesDB.createStringColumn({ + databaseId: tablesDatabaseId, + tableId: secondTableId, + key: 'director_name', + size: 255, + required: false + }); + + console.log("Waiting for column creation ..."); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + try { + const response = await tablesDB.createRelationshipColumn({ + databaseId: tablesDatabaseId, + tableId, + relatedTableId: secondTableId, + type: RelationshipType.ManyToOne, + twoWay: true, + key: 'director', + twoWayKey: 'movies', + onDelete: RelationMutate.SetNull + }); + console.log('TablesDB relationship column created:', response); + + console.log("Waiting for relationship creation ..."); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + // Update relationship column + const updateResponse = await tablesDB.updateRelationshipColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'director', + onDelete: RelationMutate.Cascade + }); + console.log('TablesDB relationship column updated:', updateResponse); + + // Cleanup + await tablesDB.deleteColumn({ + databaseId: tablesDatabaseId, + tableId, + key: 'director' + }); + + console.log("Waiting for column deletion ..."); + await new Promise((resolve) => setTimeout(resolve, 2000)); + } catch (err) { + console.log(chalk.yellow(`TablesDB relationship skipped: ${err.message}`)); + } + + await tablesDB.deleteTable({ + databaseId: tablesDatabaseId, + tableId: secondTableId + }); + + console.log('Cleaned up TablesDB relationship demo'); +} + // Transactions API Definitions const createTransaction = async () => { @@ -1219,27 +2085,9 @@ const deleteTransaction = async () => { } const runAllTasks = async () => { - await createDatabase(); - await listDatabases(); - await getDatabase(); - await updateDatabase(); - - await createCollection(); - await listCollections(); - await getCollection(); - await updateCollection(); - await listAttributes(); - await listIndexes(); - - await createDocument(); - await listDocuments(); - await getDocument(); - await updateDocument(); - - await deleteDocument(); - await deleteCollection(); - await deleteDatabase(); - + // ======================== + // Storage API + // ======================== await createBucket(); await listBuckets(); await getBucket(); @@ -1250,26 +2098,77 @@ const runAllTasks = async () => { await getFile(); await getFileDownload(); await getFilePreview(); + await getFileView(); await updateFile(); await deleteFile(); await deleteBucket(); + // ======================== + // Users API + // ======================== // await getAccount() // works only with JWT await createUser(); await listUsers(); await getUser(); await updateUserName(); + await updateUserEmail(); + await updateUserPassword(); + await updateUserPhone(); + await updateUserStatus(); + await updateUserLabels(); await getUserPrefs(); await updateUserPrefs(); + await listUserLogs(); + await listUserMemberships(); + await listUserSessions(); + await createUserSession(); + await deleteUserSessions(); + await updateUserEmailVerification(); + await updateUserPhoneVerification(); + await listUserIdentities(); + await deleteUserIdentity(); + await updateUserMFA(); + await listUserMFAFactors(); + await createUserMFARecoveryCodes(); + await getUserMFARecoveryCodes(); + await updateUserMFARecoveryCodes(); + await deleteUserMFAAuthenticator(); + await createUserTarget(); + await getUserTarget(); + await listUserTargets(); + await updateUserTarget(); + await deleteUserTarget(); + await createUserJWT(); + await createUserToken(); await deleteUser(); + // Specialized user creation (hash algorithms) + await createArgon2User(); + await createBcryptUser(); + await createMD5User(); + await createSHAUser(); + await createPHPassUser(); + await createScryptUser(); + await createScryptModifiedUser(); + + // ======================== + // Functions API + // ======================== + await listRuntimes(); + await listSpecifications(); await createFunction(); await listFunctions(); await getFunction(); await updateFunction(); await uploadDeployment(); await listDeployments(); + await getDeploymentDownload(); + await updateFunctionDeployment(); + await updateDeploymentStatus(); + await createDuplicateDeployment(); + await createTemplateDeployment(); + await createVcsDeployment(); await createVariable(); await listVariables(); await getVariable(); @@ -1278,8 +2177,13 @@ const runAllTasks = async () => { await executeSync(); await executeAsync(); await listExecutions(); + await deleteExecution(); + await deleteDeployment(); await deleteFunction(); + // ======================== + // TablesDB API + // ======================== await createTablesDatabase(); await listTablesDatabases(); await getTablesDatabase(); @@ -1291,18 +2195,36 @@ const runAllTasks = async () => { await updateTable(); await createColumns(); + await createAdditionalColumns(); + await updateColumns(); await listTableColumns(); await getTableColumn(); await createTableIndex(); await listTableIndexes(); + await getTableIndex(); + // Single row CRUD await createTableRow(); await listTableRows(); await getTableRow(); await updateTableRow(); - // Transactions API + // Bulk row operations + await createTableRows(); + await upsertTableRow(); + await upsertTableRows(); + await updateTableRows(); + await deleteTableRows(); + + // Atomic row column operations + await incrementRowColumn(); + await decrementRowColumn(); + + // TablesDB Relationship Column + await createTablesRelationshipDemo(); + + // TablesDB Transactions API await createTransaction(); await getTransaction(); await listTransactions(); @@ -1313,6 +2235,7 @@ const runAllTasks = async () => { await rollbackTransactionDemo(); await deleteTransaction(); + // Cleanup await deleteTableRow(); await deleteTableIndex(); await deleteTableColumn();