Skip to content

Conversation

@ChiragAgg5k
Copy link
Member

@ChiragAgg5k ChiragAgg5k commented Dec 22, 2025

This PR contains updates to the Command Line SDK for version 13.0.0-rc.1.

Summary by CodeRabbit

  • New Features

    • Complete TypeScript migration of codebase for improved type safety and developer experience.
  • Documentation

    • Updated installation scripts and documentation examples for version 13.0.0-rc.1.
    • Removed --data flag from upsert-document CLI example.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Walkthrough

This pull request represents a major codebase migration from JavaScript to TypeScript for the Appwrite CLI. The version is bumped from 12.0.1 to 13.0.0-rc.1. Key infrastructure files are rewritten with ES module syntax and type safety: index.js (bootstrap) → index.ts, lib/client.js → lib/client.ts, lib/config.js → lib/config.ts, lib/exception.js → lib/exception.ts, lib/parser.js → lib/parser.ts, lib/sdks.js → lib/sdks.ts, and lib/emulation/utils.js → lib/emulation/utils.ts. Over 60 command modules are migrated from CommonJS to TypeScript with explicit parameter interfaces and named exports. Installation scripts and documentation are updated to reflect the new version. Core patterns include converting require to import, module.exports to named exports, and introducing TypeScript interfaces for all public function parameters.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

This is a comprehensive, large-scale refactoring affecting core infrastructure and the majority of the codebase. While the migration pattern is relatively consistent, the sheer volume of files (100+), the complete rewrite of critical modules, and the density of logic changes across CLI commands, error handling, SDK factories, and configuration management demand thorough review.

  • lib/index.ts: Entry point rewrite with CLI bootstrap, version checking, command registration, and option parsing—verify the complete initialization flow and argument handling
  • lib/client.ts: HTTP client rewrite with error handling changes, including special-case for 401 errors and session management; validate request/response handling and error propagation
  • lib/config.ts: Complete configuration persistence system rewrite; ensure Local and Global config classes correctly handle nested key validation and session management
  • lib/parser.ts: CLI formatting, error reporting, and actionRunner wrapper; verify output formatting, error detail collection, and environment traceback generation
  • lib/commands/*.ts migrations: 60+ command modules converted; spot-check parameter interface definitions, showConsole naming consistency, and SDK client resolution patterns
  • lib/emulation/docker.ts and lib/emulation/utils.ts: Emulation layer rewrite with FunctionConfig interface and JwtManager/Queue singletons; validate Docker lifecycle and JWT token handling
  • lib/sdks.ts: SDK factory functions for console and project scope; ensure endpoint/project resolution and authentication mode selection (cookie vs key) are correct
  • Parameter interface consistency: Check that console → showConsole renaming is applied uniformly across all command modules and that optional parameter defaults are preserved
  • Installation scripts and version references: Confirm all version strings are updated consistently and that download URLs are valid

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Command Line SDK update for version 13.0.0-rc.1' accurately reflects the main change: a version update to 13.0.0-rc.1. However, it obscures the more significant underlying transformation—the codebase migration from JavaScript to TypeScript—which is evident from the commit message and the extensive .js to .ts conversions throughout the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ChiragAgg5k ChiragAgg5k requested a review from Copilot December 22, 2025 11:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Command Line SDK to version 13.0.0-rc.1 by migrating JavaScript files to TypeScript across multiple library modules. The changes involve converting CommonJS modules to ES modules, adding type annotations, and removing unnecessary files.

Key changes:

  • Migrated core library files from JavaScript (.js) to TypeScript (.ts) with proper type definitions
  • Converted module.exports to ES module exports across all files
  • Added comprehensive TypeScript interfaces for function parameters and return types

Reviewed changes

Copilot reviewed 57 out of 76 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
lib/type-generation/languages/javascript.js Deleted JavaScript implementation
lib/type-generation/languages/java.ts Migrated to TypeScript with type annotations
lib/type-generation/languages/dart.ts Migrated to TypeScript with type annotations
lib/type-generation/languages/csharp.ts Migrated to TypeScript with type annotations
lib/type-generation/attribute.ts New TypeScript attribute type definitions
lib/type-generation/attribute.js Deleted JavaScript implementation
lib/spinner.ts Migrated to TypeScript with interfaces and type safety
lib/sdks.ts Migrated to TypeScript with proper return types
lib/sdks.js Deleted JavaScript implementation
lib/questions.ts Migrated to TypeScript with comprehensive interfaces
lib/parser.ts Migrated to TypeScript with type-safe exports
lib/parser.js Deleted JavaScript implementation
lib/paginate.ts Migrated to TypeScript with generic types
lib/id.ts Migrated to TypeScript with method signatures
lib/exception.ts New TypeScript exception class
lib/exception.js Deleted JavaScript implementation
lib/emulation/utils.ts Migrated to TypeScript with interfaces
lib/emulation/utils.js Deleted JavaScript implementation
lib/emulation/docker.ts Migrated to TypeScript with function signatures
lib/config.ts Migrated to TypeScript with extensive type definitions
lib/config.js Deleted JavaScript implementation
lib/commands/vcs.ts Migrated to TypeScript with interface definitions
lib/commands/users.ts Migrated to TypeScript with interface definitions
lib/commands/update.ts Migrated to TypeScript with type safety
lib/commands/types.ts Migrated to TypeScript with type annotations
lib/commands/tokens.ts Migrated to TypeScript with interface definitions
lib/commands/teams.ts Migrated to TypeScript with interface definitions
lib/commands/storage.ts Migrated to TypeScript with interface definitions
lib/commands/run.ts Migrated to TypeScript with interface definitions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ChiragAgg5k ChiragAgg5k merged commit 72cd1a6 into master Dec 22, 2025
1 of 2 checks passed
@ChiragAgg5k ChiragAgg5k deleted the dev branch December 22, 2025 11:35
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (13)
lib/emulation/docker.ts (1)

21-31: Docker process promises don't check exit codes.

The dockerStop, dockerPull, dockerBuild, and copy process all resolve on close event without checking if the process succeeded. A non-zero exit code would still resolve the promise, potentially masking failures.

🔎 Proposed fix for dockerStop
 export async function dockerStop(id: string): Promise<void> {
     const stopProcess = childProcess.spawn('docker', ['rm', '--force', id], {
         stdio: 'pipe',
         env: {
             ...process.env,
             DOCKER_CLI_HINTS: 'false'
         }
     });
 
-    await new Promise<void>((res) => { stopProcess.on('close', res) });
+    await new Promise<void>((resolve, reject) => {
+        stopProcess.on('close', (code) => {
+            if (code === 0 || code === null) {
+                resolve();
+            } else {
+                reject(new Error(`docker rm failed with exit code ${code}`));
+            }
+        });
+        stopProcess.on('error', reject);
+    });
 }

Apply similar pattern to dockerPull and the copy process in dockerBuild.

Also applies to: 49-50, 128-128, 150-150

lib/commands/update.ts (1)

178-187: Version comparison logic is inverted.

The condition comparison < 0 with message "You're running a newer version" is backwards. When comparison < 0, it means the current version is older than the latest version, not newer. Change the condition to comparison > 0 or swap the logic between these two branches.

lib/commands/types.ts (1)

73-83: Type assertion after auto-detection can cause runtime failures.

The detectLanguage() function (lib/type-generation/languages/language.ts line 83-119) can return 'python', 'ruby', or 'dotnet', but SupportedLanguage (lib/commands/types.ts line 17) is defined as 'ts' | 'js' | 'php' | 'kotlin' | 'swift' | 'java' | 'dart' | 'cs'. The type assertion as SupportedLanguage on line 83 suppresses this incompatibility. If auto-detection returns an unsupported language, createLanguageMeta() will throw a runtime error instead of failing at compile time.

lib/spinner.ts (1)

96-104: Off-by-one error in spinner frame iteration.

The spinner animation skips the first frame (index 0) because spinnerFrame starts at 1 and is incremented before use. Also, the fallback key 'dots' should use the constant SPINNER_DOTS for consistency.

🔎 Proposed fix
     startSpinner(name: string): void {
-        let spinnerFrame = 1;
-        const spinner = spinners[name] ?? spinners['dots'];
+        let spinnerFrame = 0;
+        const spinner = spinners[name] ?? spinners[SPINNER_DOTS];

         this.spinnerInterval = setInterval(() => {
-            if (spinnerFrame === spinner.frames.length) spinnerFrame = 1;
-            this.bar.update({ prefix: spinner.frames[spinnerFrame++] });
+            this.bar.update({ prefix: spinner.frames[spinnerFrame] });
+            spinnerFrame = (spinnerFrame + 1) % spinner.frames.length;
         }, spinner.interval);
     }
lib/commands/run.ts (1)

192-216: Inconsistent ignore module usage.

Line 193 uses ignore() directly while line 259 uses ignore.default(). This inconsistency may cause issues depending on how the module is resolved. Both usages should be consistent.

🔎 Proposed fix - use consistent initialization
     if(reload) {
-        const ignorer = ignore();
+        const ignorer = ignore.default();
         ignorer.add('.appwrite');
lib/commands/teams.ts (1)

469-498: Type mismatch: prefs is typed as object but used with JSON.parse.

The interface declares prefs: object but line 483 calls JSON.parse(prefs), which expects a string. The CLI option on line 606 passes a string from the command line, so the interface type should be string to match runtime usage.

🔎 Proposed fix
 interface TeamsUpdatePrefsRequestParams {
     teamId: string;
-    prefs: object;
+    prefs: string;
     overrideForCli?: boolean;
     parseOutput?: boolean;
     sdk?: Client;
 }
lib/commands/users.ts (1)

1032-1060: Fix prefs typing vs JSON.parse in usersUpdatePrefs

UsersUpdatePrefsRequestParams.prefs is typed as object, but the implementation assumes a JSON string and calls JSON.parse(prefs). This works for the CLI (which passes a string) but will throw for programmatic callers that follow the type and pass an object.

I’d align the type with the behavior or handle both forms, e.g.:

Proposed fix: accept string or object
-interface UsersUpdatePrefsRequestParams {
-    userId: string;
-    prefs: object;
+interface UsersUpdatePrefsRequestParams {
+    userId: string;
+    prefs: string | Record<string, unknown>;
@@
-export const usersUpdatePrefs = async ({userId,prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePrefsRequestParams): Promise<any> => {
+export const usersUpdatePrefs = async ({userId,prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePrefsRequestParams): Promise<any> => {
@@
-    if (typeof prefs !== 'undefined') {
-        payload['prefs'] = JSON.parse(prefs);
-    }
+    if (typeof prefs !== 'undefined') {
+        payload['prefs'] =
+            typeof prefs === 'string' ? JSON.parse(prefs) : prefs;
+    }
lib/commands/functions.ts (3)

655-677: Off‑by‑one when trimming the last chunk in uploadChunk

In the non‑full‑chunk branch you allocate new Uint8Array(currentPosition) but copy with i <= currentPosition, which writes currentPosition + 1 bytes and includes one extra (stale or zero) byte:

uploadableChunkTrimmed = new Uint8Array(currentPosition);
for (let i = 0; i <= currentPosition; i++) {
    uploadableChunkTrimmed[i] = uploadableChunk[i];
}

This can desync the actual payload size from the declared content‑range and corrupt the last chunk.

Trim to exactly currentPosition bytes:

Proposed fix
-        } else {
-            uploadableChunkTrimmed = new Uint8Array(currentPosition);
-            for(let i = 0; i <= currentPosition; i++) {
-                uploadableChunkTrimmed[i] = uploadableChunk[i];
-            }
-        }
+        } else {
+            uploadableChunkTrimmed = new Uint8Array(currentPosition);
+            for (let i = 0; i < currentPosition; i++) {
+                uploadableChunkTrimmed[i] = uploadableChunk[i];
+            }
+        }

1021-1053: Align headers type with JSON.parse usage in functionsCreateExecution

FunctionsCreateExecutionRequestParams.headers is typed as object, but the code assumes a JSON string:

if (typeof headers !== 'undefined') {
    payload['headers'] = JSON.parse(headers);
}

CLI passes a string, but the exported type invites callers to pass an object, which would cause JSON.parse to throw.

Consider mirroring the prefs fix from users and accepting both string and object:

Proposed fix
-interface FunctionsCreateExecutionRequestParams {
+interface FunctionsCreateExecutionRequestParams {
@@
-    headers?: object;
+    headers?: string | Record<string, unknown>;
@@
-    if (typeof headers !== 'undefined') {
-        payload['headers'] = JSON.parse(headers);
-    }
+    if (typeof headers !== 'undefined') {
+        payload['headers'] =
+            typeof headers === 'string' ? JSON.parse(headers) : headers;
+    }

721-721: Use fs.promises.unlink() instead of callback-based fs.unlink()

Callback-based functions are incompatible with promises & async/await. The current code await fs.unlink(filePath, () => {}); does not actually wait for deletion since fs.unlink() is asynchronous by default and returns immediately without waiting for the file deletion to complete. Additionally, errors in the empty callback are silently discarded.

Replace with:

-    await fs.unlink(filePath,()=>{});
+    await fs.promises.unlink(filePath);
lib/commands/init.ts (1)

158-168: Bug: Using answers.bucket for team name.

Line 163 uses answers.bucket but this is the initTeam function. This appears to be a copy-paste error from initBucket. The team name should likely come from answers.name or a team-specific answer field.

🔎 Proposed fix
     localConfig.addTeam({
         $id: answers.id === 'unique()' ? ID.unique() : answers.id,
-        name: answers.bucket,
+        name: answers.name,
     });
lib/commands/sites.ts (1)

720-720: Silent error handling in fs.unlink may leave orphaned temp files.

The fs.unlink call uses an empty callback ()=>{}, which silently ignores any errors. If the unlink fails (e.g., permission issues), the temporary archive file will remain on disk without any indication to the user.

🔎 Proposed fix - add error logging
-    await fs.unlink(filePath,()=>{});
+    fs.unlink(filePath, (err) => {
+        if (err) {
+            warn(`Failed to clean up temporary file: ${filePath}`);
+        }
+    });
lib/commands/account.ts (1)

671-685: Fix type mismatch for prefs parameter.

Line 672 declares prefs: object, but line 684 calls JSON.parse(prefs), which expects a string. Based on the CLI option at line 1681, the parameter should be typed as string since it's received as a JSON string from the command line.

🔎 Proposed fix
 interface AccountUpdatePrefsRequestParams {
-    prefs: object;
+    prefs: string;
     overrideForCli?: boolean;
     parseOutput?: boolean;
     sdk?: Client;
♻️ Duplicate comments (1)
lib/commands/project.ts (1)

1-13: Same unused imports pattern as other command files.

This file contains the same boilerplate imports and unused convertReadStreamToReadableStream function. As noted in tokens.ts, this appears to be auto-generated.

🟡 Minor comments (11)
lib/paginate.ts-5-8 (1)

5-8: Index signature in PaginateResponse may cause type conflicts.

The PaginateResponse interface has both an index signature [key: string]: T and a total: number property. This creates a type conflict because total must also satisfy the index signature constraint. TypeScript requires total: number to be assignable to T, which may cause issues when T is not number.

🔎 Proposed fix
-interface PaginateResponse<T = any> {
-    [key: string]: T;
-    total: number;
-}
+interface PaginateResponse<T = any> {
+    [key: string]: T | number;
+    total: number;
+}

Or consider a more explicit structure without index signature if possible.

lib/commands/types.ts-187-192 (1)

187-192: Double-wrapped actionRunner on types command.

The typesCommand is already wrapped with actionRunner on line 73, and then wrapped again on line 192. This could cause issues with error handling being applied twice.

🔎 Proposed fix
 export const types = new Command("types")
   .description("Generate types for your Appwrite project")
   .addArgument(typesOutputArgument)
   .addOption(typesLanguageOption)
   .addOption(typesStrictOption)
-  .action(actionRunner(typesCommand));
+  .action(typesCommand);
lib/commands/functions.ts-909-919 (1)

909-919: Make destination required or guard against undefined in functionsGetDeploymentDownload

FunctionsGetDeploymentDownloadRequestParams marks destination as optional, but the implementation assumes it’s always set:

fs.writeFileSync(destination, response);

From the CLI side this is enforced by .requiredOption('--destination <path>'), but programmatic callers following the type can omit destination and hit a runtime error.

Either:

  • Make destination required in the interface, or
  • Guard explicitly and throw a clear error if it’s missing.

Also applies to: 944-945

lib/commands/graphql.ts-98-102 (1)

98-102: Incorrect command description: "mutation" instead of "query".

Line 100 describes the query command as "Execute a GraphQL mutation." This should say "Execute a GraphQL query."

🔎 Proposed fix
 graphql
     .command(`query`)
-    .description(`Execute a GraphQL mutation.`)
+    .description(`Execute a GraphQL query.`)
     .requiredOption(`--query <query>`, `The query or queries to execute.`)
lib/commands/push.ts-1187-1192 (1)

1187-1192: Question asks for entrypoint but result is assigned to buildCommand.

Lines 1189-1191 use questionsGetEntrypoint (which prompts "Enter the entrypoint") but assign the answer to site.buildCommand. This creates a semantic mismatch—either the question should ask for a build command instead of an entrypoint, or the assignment should use a different property that aligns with the prompt.

lib/parser.ts-229-229 (1)

229-229: Typo: "whomai" should be "whoami".

The description text contains a typo: "The whomai command" should be "The whoami command".

🔎 Proposed fix
-    whoami: `The whomai command gives information about the currently logged-in user.`,
+    whoami: `The whoami command gives information about the currently logged-in user.`,
lib/commands/proxy.ts-34-36 (1)

34-36: Missing command description for 'proxy'.

Similar to the tokens command, the commandDescriptions map in lib/parser.ts does not include a 'proxy' key, resulting in an empty description for this command.

🔎 Add to lib/parser.ts commandDescriptions
 export const commandDescriptions: Record<string, string> = {
+    proxy: `The proxy command allows you to manage custom domain proxy rules for your Appwrite project.`,
     account: `The account command allows you to authenticate and manage a user account.`,

Committable suggestion skipped: line range outside the PR's diff.

lib/commands/tokens.ts-34-36 (1)

34-36: Missing command description for 'tokens'.

The commandDescriptions map in lib/parser.ts does not include a 'tokens' key, so this command will have an empty description. Consider adding a description entry for the tokens command.

🔎 Add to lib/parser.ts commandDescriptions
 export const commandDescriptions: Record<string, string> = {
     account: `The account command allows you to authenticate and manage a user account.`,
+    tokens: `The tokens command allows you to manage file access tokens.`,
     graphql: `The graphql command allows you to query and mutate any resource type on your Appwrite server.`,
lib/questions.ts-81-82 (1)

81-82: Same typo in getEntrypoint and getInstallCommand.

The languge typo is repeated in these functions as well.

🔎 Proposed fix
 const getEntrypoint = (runtime: string): string | undefined => {
-    const languge = runtime.split("-").slice(0, -1).join("-");
+    const language = runtime.split("-").slice(0, -1).join("-");

-    switch (languge) {
+    switch (language) {
 const getInstallCommand = (runtime: string): string | undefined => {
-    const languge = runtime.split("-").slice(0, -1).join("-");
+    const language = runtime.split("-").slice(0, -1).join("-");

-    switch (languge) {
+    switch (language) {

Also applies to: 119-120

lib/questions.ts-47-50 (1)

47-50: Typo: languge should be language.

The variable name is misspelled as languge instead of language. This typo appears in getIgnores, getEntrypoint, and getInstallCommand functions.

🔎 Proposed fix for getIgnores
 const getIgnores = (runtime: string): string[] => {
-    const languge = runtime.split("-").slice(0, -1).join("-");
+    const language = runtime.split("-").slice(0, -1).join("-");

-    switch (languge) {
+    switch (language) {
lib/commands/account.ts-2-5 (1)

2-5: Remove unused imports from lines 2-5.

The imported modules pathLib, tar, ignore, and promisify are not used anywhere in this file and should be removed.

🧹 Nitpick comments (47)
lib/type-generation/languages/dart.ts (1)

1-4: Consider using ES module import syntax for consistency.

The import fs = require('fs') and import path = require('path') syntax works but is less common in modern TypeScript. Since this PR migrates to TypeScript with ES modules, consider aligning with the ES module style used in other files.

🔎 Proposed fix
-import fs = require('fs');
-import path = require('path');
+import * as fs from 'fs';
+import * as path from 'path';
 import { AttributeType } from '../attribute';
 import { LanguageMeta, Attribute, Collection } from './language';
lib/commands/pull.ts (5)

33-64: Actions map has loose typing for action callbacks.

The actions map is typed as Record<string, (options?: any) => Promise<void>>, but the individual functions have different signatures (e.g., pullFunctions expects PullFunctionsOptions). This works at runtime but loses type safety for the options parameter.

Consider creating a union type or using a discriminated union for stronger typing if you want to ensure type safety when calling these actions with specific options.


66-81: Empty catch block with rethrow is redundant.

The try/catch block on lines 69-80 catches the exception only to rethrow it, which provides no benefit.

🔎 Proposed fix
 const pullSettings = async (): Promise<void> => {
     log("Pulling project settings ...");
 
-    try {
-        let response = await projectsGet({
-            parseOutput: false,
-            projectId: localConfig.getProject().projectId
-        });
-
-        localConfig.setProject(response.$id, response.name, response);
-
-        success(`Successfully pulled ${chalk.bold('all')} project settings.`);
-    } catch (e) {
-        throw e;
-    }
+    let response = await projectsGet({
+        parseOutput: false,
+        projectId: localConfig.getProject().projectId
+    });
+
+    localConfig.setProject(response.$id, response.name, response);
+
+    success(`Successfully pulled ${chalk.bold('all')} project settings.`);
 }

154-155: Silent catch blocks swallow errors.

Empty catch blocks at lines 154-155 and 186-187 silently swallow errors without any logging, making debugging difficult when API calls fail.

Consider at least logging the error at a debug level:

-        } catch {
-        }
+        } catch (e) {
+            // Deployment listing failed; proceed without deployment
+        }

189-189: Consider more specific typing for holdingVars.

The variable holdingVars is implicitly typed as any from func['vars'], and then map casts items to any. Consider defining a proper type for function variables.


267-268: Consistent silent catch blocks in pullSites.

Same issue as in pullFunctions - empty catch blocks silently swallow errors. Consider adding at least a comment explaining why the error is being ignored.

Also applies to: 298-300

lib/paginate.ts (1)

10-16: Return type union creates awkward consumer experience.

The function returns either T[] or PaginateResponse<T[]> depending on whether wrapper is empty. This forces consumers to check the return type at runtime. Consider using an options object with a discriminant or always returning a consistent shape.

Also applies to: 55-62

lib/emulation/docker.ts (2)

12-19: Duplicate FunctionConfig interface differs from lib/types.ts.

This file defines a local FunctionConfig interface that differs from the one in lib/types.ts (lines 56-72 in relevant snippets). The lib/types.ts version includes additional fields like name, execute, enabled, logging, events, schedule, timeout, vars, and scopes that are missing here.

Consider importing from lib/types.ts and extending or picking the needed fields to avoid divergence:

-interface FunctionConfig {
-    $id: string;
-    runtime: string;
-    path: string;
-    entrypoint: string;
-    commands: string;
-    ignore?: string;
-}
+import { FunctionConfig } from '../types';

Or if you need a subset:

import { FunctionConfig as FullFunctionConfig } from '../types';
type FunctionConfig = Pick<FullFunctionConfig, '$id' | 'runtime' | 'path' | 'entrypoint' | 'commands'> & { ignore?: string };

233-264: Recursive promise pattern in waitUntilPortOpen works but could leak resources.

The recursive call to waitUntilPortOpen inside the error handler creates new promises on each retry. While functional, if the error handling path is taken many times, this could potentially lead to memory pressure in edge cases.

Consider refactoring to an iterative approach with a loop for clarity and to avoid deep recursion:

async function waitUntilPortOpen(port: number, maxAttempts: number = 100): Promise<void> {
    for (let i = 0; i < maxAttempts; i++) {
        try {
            await tryConnect(port);
            return;
        } catch {
            await new Promise<void>((res) => setTimeout(res, 100));
        }
    }
    throw new Error(`Port ${port} did not open after ${maxAttempts} attempts`);
}
lib/commands/types.ts (1)

108-122: Use of any[] type loses type safety.

Variables collections, dataItems are typed as any[] which defeats the purpose of TypeScript migration. Consider defining proper interfaces for these data structures.

-  let collections: any[] = [];
+  let collections: Collection[] = [];
   let dataSource = 'tables';
   
   // ...
   
-  let dataItems: any[] = tables.length > 0 ? tables : collections;
+  let dataItems: Collection[] = tables.length > 0 ? tables : collections;
lib/commands/update.ts (2)

9-9: Using require for JSON import works but could use ES module syntax.

The require('../../../package.json') works for reading the version, but for full TypeScript benefit, consider using ES module import with resolveJsonModule enabled in tsconfig.

-const { version } = require('../../../package.json');
+import packageJson from '../../../package.json';
+const { version } = packageJson;

This requires "resolveJsonModule": true in tsconfig.json.


81-91: Error message detection is fragile.

Checking e.message.includes('EEXIST') or 'already installed' for success detection is brittle as these strings could change between npm/brew versions or locales.

Consider checking the exit code instead, or at minimum log the full error for debugging:

} catch (e: any) {
    // Log full error for debugging before checking specific conditions
    console.debug('Update error details:', e);
    if (e.message.includes('EEXIST') || ...

Also applies to: 103-113

lib/commands/run.ts (1)

45-52: Potential logic issue with NaN check on null value.

isNaN(null!) returns false because null coerces to 0. If port is not provided and portNum remains null, the check on line 50 won't catch it. However, the subsequent if(portNum) check on line 54 handles this, so it's not a runtime bug—but the NaN check is misleading and can be simplified.

🔎 Suggested simplification
     let portNum: number | null = null;
     if(port) {
-        portNum = +port;
-    }
-
-    if(isNaN(portNum!)) {
-        portNum = null;
+        const parsed = +port;
+        portNum = isNaN(parsed) ? null : parsed;
     }
lib/emulation/utils.ts (2)

99-145: Consider handling missing projectId gracefully.

Line 138 uses a non-null assertion on projectId. If localConfig.getProject().projectId is undefined, this will pass undefined! to the API call, which may cause confusing errors downstream.

🔎 Proposed defensive check
+        const projectId = localConfig.getProject().projectId;
+        if (!projectId) {
+            throw new Error('Project ID is not configured. Run "appwrite init" first.');
+        }
+
         const functionResponse: any = await projectsCreateJWT({
-            projectId: localConfig.getProject().projectId!,
+            projectId,
             scopes: projectScopes,
             duration: 60 * 60,
             parseOutput: false,
         });

183-192: Files array not cleared after reload event emission.

The _trigger method emits the reload event with the current files array but doesn't clear it afterward. The files array is only cleared in lock(). If unlock() is called without lock() being called first (or if push is called between unlock and the next lock), files could be processed multiple times.

🔎 Proposed fix to clear files after emission
     _trigger(): void {
         if (this.debounce) {
             return;
         }

         this.debounce = setTimeout(() => {
-            this.events.emit('reload', { files: this.files } as QueueReloadEvent);
+            const filesToProcess = [...this.files];
+            this.files = [];
+            this.events.emit('reload', { files: filesToProcess } as QueueReloadEvent);
             this.debounce = null;
         }, 300);
     },
lib/commands/teams.ts (1)

1-13: Several imports appear unused in this file.

The imports for tar, ignore, pathLib, promisify, getAllFiles, File, and ReadableStream don't appear to be used in the teams command module. Similarly, convertReadStreamToReadableStream (lines 15-32) is defined but not called.

This is likely template-generated code, so this may be acceptable for consistency across command modules.

lib/commands/migrations.ts (2)

1-13: Same pattern of potentially unused imports.

Similar to teams.ts, several imports (tar, ignore, pathLib, promisify, getAllFiles, File, ReadableStream) and the convertReadStreamToReadableStream function appear unused in this specific command module.


156-171: Parameter escape shadows global property.

The escape parameter shadows the global escape function. While escape is deprecated, this can still cause confusion. Consider renaming to escapeChar or similar.

Based on static analysis hint from Biome.

🔎 Proposed fix
 interface MigrationsCreateCSVExportRequestParams {
     resourceId: string;
     filename: string;
     columns?: string[];
     queries?: string[];
     delimiter?: string;
     enclosure?: string;
-    escape?: string;
+    escapeChar?: string;
     header?: boolean;
     notify?: boolean;
     overrideForCli?: boolean;
     parseOutput?: boolean;
     sdk?: Client;
 }

-export const migrationsCreateCSVExport = async ({resourceId,filename,columns,queries,delimiter,enclosure,escape,header,notify,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateCSVExportRequestParams): Promise<any> => {
+export const migrationsCreateCSVExport = async ({resourceId,filename,columns,queries,delimiter,enclosure,escapeChar,header,notify,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateCSVExportRequestParams): Promise<any> => {

Note: The payload assignment (line 196-198) would also need updating to map escapeChar to the API's escape field:

if (typeof escapeChar !== 'undefined') {
    payload['escape'] = escapeChar;
}
lib/commands/users.ts (1)

15-32: Unused convertReadStreamToReadableStream helper in users commands

This helper isn’t used anywhere in lib/commands/users.ts. Consider removing it here (and the related imports) or moving it to a shared utility that’s only imported by modules that actually need streaming uploads, to avoid dead code and reduce cognitive load.

lib/commands/projects.ts (1)

15-32: Remove unused convertReadStreamToReadableStream helper from projects commands

This file doesn’t use streaming uploads, but still defines convertReadStreamToReadableStream and imports the related dependencies. That’s effectively dead code here.

Consider dropping the helper (and its supporting imports) from this module, or moving it into a shared utility that’s only imported by callers that actually need chunked uploads.

CHANGELOG.md (1)

3-6: Optional: Clarify impact of TS migration in changelog

The 13.0.0-rc.1 entry only mentions “Migrates codebase from JavaScript to TypeScript”. Since this release also introduces ESM-style named exports and typed param objects, you might want to briefly call out any breaking surface changes for consumers (e.g., import path / export changes), if they exist.

This helps downstream users understand whether they need to adjust code when upgrading.

lib/exception.ts (1)

1-20: Exception implementation looks good; consider ES-style export for consistency

The AppwriteException class itself is fine (name set, extra fields exposed, stack captured on V8).

The file currently uses a CommonJS-style export:

export = AppwriteException;

Given the rest of the codebase is moving to ES module style (import Client from '../client';, named exports from commands), consider switching to an ES export (e.g., export default AppwriteException) for consistency—provided it doesn’t break existing consumers that require() this module.

If you do keep export =, double‑check that lib/client.ts and any external consumers are importing it in a way that TypeScript and your bundling/emit settings support (e.g., import AppwriteException = require('./exception'); or compatible interop config).

lib/commands/organizations.ts (1)

14-45: LGTM - Clean implementation following established patterns.

The function correctly handles optional SDK injection, payload construction, and conditional output parsing. The renaming of console to showConsole (line 19) nicely avoids shadowing the global console object.

Minor optional nit: consider using const instead of let for client, apiPath, payload, and response since none are reassigned.

lib/commands/init.ts (1)

327-342: Duplicate copyRecursiveSync function.

This helper is defined identically here and again in initSite (lines 472-487). Consider extracting it to a shared utility module (e.g., lib/utils.ts) to follow DRY principles.

🔎 Suggested extraction

Add to lib/utils.ts:

export const copyRecursiveSync = (src: string, dest: string): void => {
    const exists = fs.existsSync(src);
    const stats = exists && fs.statSync(src);
    const isDirectory = exists && stats && stats.isDirectory();
    if (isDirectory) {
        if (!fs.existsSync(dest)) {
            fs.mkdirSync(dest);
        }
        fs.readdirSync(src).forEach((childItemName) => {
            copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
        });
    } else {
        fs.copyFileSync(src, dest);
    }
};

Then import and use it in both initFunction and initSite.

lib/sdks.ts (1)

24-34: Minor: localConfig.getProject() is called twice.

Line 27 calls localConfig.getProject() twice in the same expression. Consider caching the result:

🔎 Proposed optimization
 export const sdkForProject = async (): Promise<Client> => {
     const client = new Client();
     const endpoint = localConfig.getEndpoint() || globalConfig.getEndpoint();
-    const project = localConfig.getProject().projectId ? localConfig.getProject().projectId : globalConfig.getProject();
+    const localProject = localConfig.getProject();
+    const project = localProject.projectId ? localProject.projectId : globalConfig.getProject();
     const key = globalConfig.getKey();
lib/commands/graphql.ts (1)

1-14: Multiple unused imports.

Several imports appear unused in this file: fs, pathLib, tar, ignore, promisify, getAllFiles, localConfig, globalConfig, File, ReadableStream. The convertReadStreamToReadableStream function (lines 15-32) also appears unused.

Consider removing these to reduce clutter, unless they're planned for future use.

🔎 Minimal imports needed
import Client from '../client';
import { Command } from 'commander';
import { sdkForProject } from '../sdks';
import { parse, actionRunner, commandDescriptions } from '../parser';
lib/commands/console.ts (5)

1-13: Unused imports detected.

Several imports are not used in this file: fs, pathLib, tar, ignore, promisify, getAllFiles, parseInteger, localConfig, and File. These appear to be leftover from a template or copy-paste.

🔎 Proposed cleanup
-import fs = require('fs');
-import pathLib = require('path');
-import tar = require('tar');
-import ignore = require('ignore');
-import { promisify } from 'util';
 import Client from '../client';
-import { getAllFiles, showConsoleLink } from '../utils';
+import { showConsoleLink } from '../utils';
 import { Command } from 'commander';
-import { sdkForProject, sdkForConsole } from '../sdks';
-import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser';
-import { localConfig, globalConfig } from '../config';
-import { File } from 'undici';
-import { ReadableStream } from 'stream/web';
+import { sdkForProject } from '../sdks';
+import { parse, actionRunner, commandDescriptions } from '../parser';

15-32: Unused helper function.

convertReadStreamToReadableStream is defined but never used in this file. Consider removing it to reduce dead code.


34-36: Export name console shadows the global console object.

Naming the exported Command console shadows JavaScript's global console, which could cause confusion and subtle bugs if console.log or similar methods are used later in this module. While TypeScript may catch direct misuse, this is a maintenance hazard.

Consider renaming to consoleCommand or similar to avoid shadowing.

🔎 Proposed rename
-export const console = new Command("console").description(commandDescriptions['console'] ?? '').configureHelp({
+export const consoleCommand = new Command("console").description(commandDescriptions['console'] ?? '').configureHelp({
     helpWidth: process.stdout.columns || 80
 })

Then update command wiring at lines 99 and 107 to use consoleCommand.


47-74: Unused parameter overrideForCli.

The overrideForCli parameter is destructured from the input but never used in the function body. Either remove it from the interface and function signature, or implement the intended behavior.

Additionally, Line 59's let response = undefined; is redundant since it's immediately assigned on line 61.

🔎 Proposed cleanup
-export const consoleGetResource = async ({value,type,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ConsoleGetResourceRequestParams): Promise<any> => {
-    let client = !sdk ? await sdkForProject() :
-    sdk;
+export const consoleGetResource = async ({value, type, parseOutput = true, sdk = undefined, console: showConsole}: ConsoleGetResourceRequestParams): Promise<any> => {
+    const client = sdk ?? await sdkForProject();
     let apiPath = '/console/resources';
     let payload = {};
     if (typeof value !== 'undefined') {
         payload['value'] = value;
     }
     if (typeof type !== 'undefined') {
         payload['type'] = type;
     }

-    let response = undefined;
-
-    response = await client.call('get', apiPath, {
+    const response = await client.call('get', apiPath, {
     }, payload);

75-98: Same issues as consoleGetResource.

The overrideForCli parameter is unused, and let response = undefined; is redundant. Apply similar cleanup as suggested for the previous function.

lib/client.ts (3)

11-29: Unused constant CHUNK_SIZE.

The CHUNK_SIZE constant on line 12 is defined but never used in this file. Consider removing it or adding a TODO if it's intended for future chunked upload functionality.


148-196: Type safety concern in URLSearchParams construction.

On line 161, Client.flatten(params) returns Record<string, unknown>, but URLSearchParams expects Record<string, string>. Non-string values may be coerced to [object Object] or similar.

🔎 Proposed fix
 if (method.toUpperCase() === 'GET') {
-    url.search = new URLSearchParams(Client.flatten(params) as Record<string, string>).toString();
+    const flatParams = Client.flatten(params);
+    const stringParams: Record<string, string> = {};
+    for (const [key, value] of Object.entries(flatParams)) {
+        stringParams[key] = String(value);
+    }
+    url.search = new URLSearchParams(stringParams).toString();
 }

207-214: Side-effect in generic HTTP call method.

Automatically removing sessions (lines 207-213) when receiving a 401 with user_more_factors_required is a significant side effect in a low-level HTTP client method. This behavior might surprise callers who expect the call method to only perform the HTTP request.

Consider moving this logic to a higher-level wrapper or documenting this behavior clearly.

lib/commands/push.ts (1)

1-97: Unused JSONbigNative constant.

JSONbigNative is initialized on line 97 but never used in the file. Consider removing it.

lib/config.ts (1)

285-308: Inconsistent merge behavior across addX methods.

addSite (and addFunction) merge existing entities with new props using spread operator ({ ...sites[i], ...props }), while addCollection, addTable, addBucket, and others completely replace existing entries (collections[i] = props).

This inconsistency could lead to unexpected data loss if users expect merge behavior. Consider standardizing on one approach.

lib/parser.ts (1)

113-158: Control flow issue in parseError with async IIFE.

The async IIFE on lines 115-148 calls process.exit(1) inside it, but since the IIFE is not awaited, the code on line 156 (process.exit(1)) could potentially execute before the async block completes in edge cases. However, since both paths end in process.exit(1), this is functionally correct but the pattern is slightly confusing.

Additionally, line 128 accesses (cliConfig.reportData as any).data.args which relies on runtime structure without type safety. Consider defining a proper type for reportData to avoid potential runtime errors if the structure changes.

lib/commands/tokens.ts (1)

1-13: Unused imports detected.

Several imports are not used in this file: fs, pathLib, tar, ignore, promisify, getAllFiles, localConfig, File, and ReadableStream. Similarly, the convertReadStreamToReadableStream function (lines 15-32) is defined but never called.

This appears to be auto-generated boilerplate. If this is intentional for consistency across command files, consider adding a comment or configuring the linter to ignore these. Otherwise, removing unused imports would reduce bundle size and improve clarity.

lib/commands/locale.ts (1)

38-42: Consider consolidating identical request param interfaces.

All the Locale*RequestParams interfaces in this file share the same structure with only overrideForCli?, parseOutput?, and sdk? properties. While this is likely auto-generated code, consolidating into a shared base interface would reduce duplication:

interface BaseLocaleRequestParams {
    overrideForCli?: boolean;
    parseOutput?: boolean;
    sdk?: Client;
}

However, if this is auto-generated, maintaining separate interfaces may be intentional for future extensibility.

lib/questions.ts (3)

17-17: Unused variable: JSONbigConfig is defined but never used.

The JSONbigConfig constant is initialized but not referenced anywhere in the file. Consider removing it or utilizing it where JSONbig is needed.

🔎 Proposed fix
-const JSONbigConfig = JSONbig({ storeAsString: false });

682-696: Potential runtime error if sessions array is empty.

The reduce call on line 684 will throw a TypeError if sessions is an empty array since no initial value is provided. While the choices function is likely only called when sessions exist (based on the when condition at line 647), adding a guard or initial value would make this more robust.

🔎 Proposed defensive fix
-            const longestEmail = sessions.reduce((prev: any, current: any) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length;
+            const longestEmail = sessions.length > 0 
+                ? sessions.reduce((prev: any, current: any) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length 
+                : 0;

737-751: Same empty array risk in questionsLogout.

The same reduce pattern without an initial value is used in questionsLogout, which could throw if sessions is unexpectedly empty.

lib/commands/health.ts (1)

1-13: Unused imports detected.

Several imports (fs, pathLib, tar, ignore, promisify, getAllFiles, File) are not used in this file. The convertReadStreamToReadableStream helper function is also defined but never called. These appear to be copy-pasted boilerplate from a template.

🔎 Proposed fix - remove unused imports and helper
-import fs = require('fs');
-import pathLib = require('path');
-import tar = require('tar');
-import ignore = require('ignore');
-import { promisify } from 'util';
 import Client from '../client';
-import { getAllFiles, showConsoleLink } from '../utils';
+import { showConsoleLink } from '../utils';
 import { Command } from 'commander';
 import { sdkForProject, sdkForConsole } from '../sdks';
 import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser';
 import { localConfig, globalConfig } from '../config';
-import { File } from 'undici';
-import { ReadableStream } from 'stream/web';
-
-function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream {
-  return new ReadableStream({
-    start(controller) {
-      readStream.on("data", (chunk: Buffer) => {
-        controller.enqueue(chunk);
-      });
-      readStream.on("end", () => {
-        controller.close();
-      });
-      readStream.on("error", (err: Error) => {
-        controller.error(err);
-      });
-    },
-    cancel() {
-      readStream.destroy();
-    },
-  });
-}
lib/commands/storage.ts (1)

107-110: Unusual pattern: permissions === true ? [] : permissions

This pattern suggests that the CLI parser might pass true when an option is specified without a value. While this works as a workaround, consider adding a comment explaining the behavior or handling this at the CLI option parsing level for clarity.

Also applies to: 120-123

lib/commands/vcs.ts (1)

1-32: Unused imports and helper function.

Similar to health.ts, this file has unused imports (fs, pathLib, tar, ignore, promisify, getAllFiles, File, ReadableStream) and an unused convertReadStreamToReadableStream function that should be removed.

🔎 Proposed fix - remove unused code
-import fs = require('fs');
-import pathLib = require('path');
-import tar = require('tar');
-import ignore = require('ignore');
-import { promisify } from 'util';
 import Client from '../client';
-import { getAllFiles, showConsoleLink } from '../utils';
+import { showConsoleLink } from '../utils';
 import { Command } from 'commander';
 import { sdkForProject, sdkForConsole } from '../sdks';
 import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser';
 import { localConfig, globalConfig } from '../config';
-import { File } from 'undici';
-import { ReadableStream } from 'stream/web';
-
-function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream {
-  return new ReadableStream({
-    start(controller) {
-      readStream.on("data", (chunk: Buffer) => {
-        controller.enqueue(chunk);
-      });
-      readStream.on("end", () => {
-        controller.close();
-      });
-      readStream.on("error", (err: Error) => {
-        controller.error(err);
-      });
-    },
-    cancel() {
-      readStream.destroy();
-    },
-  });
-}
lib/commands/account.ts (2)

1-5: Prefer modern ES module import syntax.

Lines 1-5 use TypeScript's legacy CommonJS import syntax (import fs = require('fs')), while lines 6-12 use modern ES module syntax. For consistency and better alignment with ES module standards, convert the legacy imports to modern syntax.

🔎 Proposed refactor
-import fs = require('fs');
-import pathLib = require('path');
-import tar = require('tar');
-import ignore = require('ignore');
+import * as fs from 'fs';
+import * as pathLib from 'path';
+import * as tar from 'tar';
+import * as ignore from 'ignore';
 import { promisify } from 'util';

1368-1418: Consider extracting common logic to reduce duplication.

The functions accountCreateEmailVerification and accountCreateVerification (lines 1368-1418) have identical implementations. While the duplication is intentional for backward compatibility (as accountCreateVerification is deprecated), extracting the shared logic into a common helper function would improve maintainability.

🔎 Example refactor
const _createEmailVerificationInternal = async ({url, parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateEmailVerificationRequestParams): Promise<any> => {
    let client = !sdk ? await sdkForProject() : sdk;
    let apiPath = '/account/verifications/email';
    let payload = {};
    if (typeof url !== 'undefined') {
        payload['url'] = url;
    }

    let response = undefined;

    response = await client.call('post', apiPath, {
        'content-type': 'application/json',
    }, payload);

    if (parseOutput) {
        parse(response)
    }

    return response;
}

export const accountCreateEmailVerification = _createEmailVerificationInternal;
export const accountCreateVerification = _createEmailVerificationInternal;

Note: The same pattern applies to accountUpdateEmailVerification and accountUpdateVerification (lines 1427-1484).

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc16866 and 7bc80b2.

📒 Files selected for processing (76)
  • CHANGELOG.md
  • README.md
  • docs/examples/databases/upsert-document.md
  • index.js
  • index.ts
  • install.ps1
  • install.sh
  • lib/client.js
  • lib/client.ts
  • lib/commands/account.ts
  • lib/commands/console.js
  • lib/commands/console.ts
  • lib/commands/databases.ts
  • lib/commands/functions.ts
  • lib/commands/generic.ts
  • lib/commands/graphql.js
  • lib/commands/graphql.ts
  • lib/commands/health.ts
  • lib/commands/init.ts
  • lib/commands/locale.ts
  • lib/commands/messaging.ts
  • lib/commands/migrations.ts
  • lib/commands/organizations.js
  • lib/commands/organizations.ts
  • lib/commands/project.ts
  • lib/commands/projects.ts
  • lib/commands/proxy.ts
  • lib/commands/pull.ts
  • lib/commands/push.ts
  • lib/commands/run.ts
  • lib/commands/sites.ts
  • lib/commands/storage.ts
  • lib/commands/tables-db.ts
  • lib/commands/teams.ts
  • lib/commands/tokens.ts
  • lib/commands/types.ts
  • lib/commands/update.ts
  • lib/commands/users.ts
  • lib/commands/vcs.ts
  • lib/config.js
  • lib/config.ts
  • lib/emulation/docker.ts
  • lib/emulation/utils.js
  • lib/emulation/utils.ts
  • lib/exception.js
  • lib/exception.ts
  • lib/id.ts
  • lib/paginate.ts
  • lib/parser.js
  • lib/parser.ts
  • lib/questions.ts
  • lib/sdks.js
  • lib/sdks.ts
  • lib/spinner.ts
  • lib/type-generation/attribute.js
  • lib/type-generation/attribute.ts
  • lib/type-generation/languages/csharp.ts
  • lib/type-generation/languages/dart.ts
  • lib/type-generation/languages/java.ts
  • lib/type-generation/languages/javascript.js
  • lib/type-generation/languages/javascript.ts
  • lib/type-generation/languages/kotlin.js
  • lib/type-generation/languages/kotlin.ts
  • lib/type-generation/languages/language.js
  • lib/type-generation/languages/language.ts
  • lib/type-generation/languages/php.ts
  • lib/type-generation/languages/swift.ts
  • lib/type-generation/languages/typescript.js
  • lib/type-generation/languages/typescript.ts
  • lib/types.ts
  • lib/utils.ts
  • lib/validations.js
  • lib/validations.ts
  • package.json
  • scoop/appwrite.config.json
  • tsconfig.json
💤 Files with no reviewable changes (11)
  • lib/emulation/utils.js
  • lib/type-generation/attribute.js
  • lib/commands/organizations.js
  • lib/sdks.js
  • lib/commands/graphql.js
  • lib/exception.js
  • index.js
  • lib/parser.js
  • lib/config.js
  • lib/client.js
  • lib/commands/console.js
🧰 Additional context used
🧬 Code graph analysis (23)
lib/commands/organizations.ts (3)
lib/sdks.ts (1)
  • sdkForProject (24-55)
lib/utils.ts (1)
  • showConsoleLink (111-153)
lib/parser.ts (1)
  • parse (21-48)
lib/type-generation/languages/dart.ts (2)
lib/type-generation/languages/language.ts (2)
  • Attribute (4-15)
  • Collection (17-21)
lib/type-generation/attribute.ts (1)
  • AttributeType (1-15)
lib/sdks.ts (2)
lib/commands/generic.ts (1)
  • client (242-316)
lib/config.ts (2)
  • globalConfig (843-843)
  • localConfig (842-842)
lib/commands/graphql.ts (3)
lib/parser.ts (3)
  • commandDescriptions (206-236)
  • parse (21-48)
  • actionRunner (160-168)
lib/commands/generic.ts (1)
  • client (242-316)
lib/sdks.ts (1)
  • sdkForProject (24-55)
lib/type-generation/languages/csharp.ts (2)
lib/type-generation/languages/language.ts (2)
  • Attribute (4-15)
  • Collection (17-21)
lib/type-generation/attribute.ts (1)
  • AttributeType (1-15)
lib/emulation/utils.ts (4)
lib/parser.ts (1)
  • log (184-186)
lib/commands/users.ts (2)
  • usersGet (545-566)
  • usersCreateJWT (632-656)
lib/commands/projects.ts (1)
  • projectsCreateJWT (852-877)
lib/config.ts (1)
  • localConfig (842-842)
lib/commands/update.ts (2)
lib/parser.ts (3)
  • success (196-198)
  • hint (192-194)
  • error (200-202)
lib/spinner.ts (1)
  • update (86-89)
lib/parser.ts (3)
lib/types.ts (1)
  • CliConfig (1-9)
lib/config.ts (1)
  • globalConfig (843-843)
lib/utils.ts (1)
  • isCloud (318-322)
lib/emulation/docker.ts (2)
lib/types.ts (1)
  • FunctionConfig (57-73)
lib/parser.ts (2)
  • error (200-202)
  • success (196-198)
lib/commands/push.ts (3)
lib/config.ts (2)
  • keys (156-158)
  • localConfig (842-842)
lib/utils.ts (1)
  • checkDeployConditions (103-109)
lib/questions.ts (1)
  • questionsGetEntrypoint (931-944)
lib/type-generation/languages/java.ts (2)
lib/type-generation/languages/language.ts (2)
  • Attribute (4-15)
  • Collection (17-21)
lib/type-generation/attribute.ts (1)
  • AttributeType (1-15)
lib/commands/types.ts (2)
lib/parser.ts (2)
  • actionRunner (160-168)
  • log (184-186)
lib/type-generation/languages/language.ts (1)
  • Collection (17-21)
lib/commands/generic.ts (3)
lib/parser.ts (5)
  • log (184-186)
  • success (196-198)
  • hint (192-194)
  • commandDescriptions (206-236)
  • actionRunner (160-168)
lib/commands/account.ts (1)
  • account (34-36)
lib/config.ts (1)
  • globalConfig (843-843)
lib/config.ts (1)
lib/types.ts (4)
  • ConfigData (27-29)
  • ProjectConfigData (46-55)
  • GlobalConfigData (38-44)
  • SessionData (31-36)
lib/client.ts (1)
lib/types.ts (4)
  • Headers (11-13)
  • RequestParams (15-17)
  • ResponseType (25-25)
  • FileUpload (19-23)
lib/commands/console.ts (4)
lib/parser.ts (3)
  • commandDescriptions (206-236)
  • parse (21-48)
  • actionRunner (160-168)
lib/commands/generic.ts (1)
  • client (242-316)
lib/sdks.ts (1)
  • sdkForProject (24-55)
lib/utils.ts (1)
  • showConsoleLink (111-153)
lib/commands/tokens.ts (1)
lib/parser.ts (2)
  • commandDescriptions (206-236)
  • parseBool (178-182)
lib/commands/project.ts (1)
lib/parser.ts (2)
  • commandDescriptions (206-236)
  • parseBool (178-182)
lib/commands/vcs.ts (1)
lib/parser.ts (1)
  • parseBool (178-182)
lib/commands/proxy.ts (1)
lib/parser.ts (2)
  • commandDescriptions (206-236)
  • parseBool (178-182)
lib/commands/sites.ts (1)
lib/parser.ts (2)
  • commandDescriptions (206-236)
  • parseBool (178-182)
lib/commands/functions.ts (1)
lib/parser.ts (2)
  • commandDescriptions (206-236)
  • parseBool (178-182)
lib/commands/projects.ts (1)
lib/parser.ts (3)
  • commandDescriptions (206-236)
  • parseBool (178-182)
  • actionRunner (160-168)
🪛 Biome (2.1.2)
lib/type-generation/languages/dart.ts

[error] 63-63: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

lib/type-generation/languages/csharp.ts

[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

lib/type-generation/languages/java.ts

[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

lib/commands/migrations.ts

[error] 171-171: Do not shadow the global "escape" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

Comment on lines 1 to +4
appwrite databases upsert-document \
--database-id <DATABASE_ID> \
--collection-id <COLLECTION_ID> \
--document-id <DOCUMENT_ID> \
--data '{ "key": "value" }'
--document-id <DOCUMENT_ID>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add --data parameter to the upsert-document example.

The upsertDocument operation requires a data parameter containing the document attributes to be created or updated. The example must include this parameter with sample JSON data for the command to function correctly:

appwrite databases upsert-document \
    --database-id <DATABASE_ID> \
    --collection-id <COLLECTION_ID> \
    --document-id <DOCUMENT_ID> \
    --data '{"key": "value"}'
🤖 Prompt for AI Agents
In docs/examples/databases/upsert-document.md around lines 1 to 4, the example
command is missing the required --data parameter; update the example to include
a --data argument with sample JSON (e.g., --data '{"key":"value"}') so the
upsert-document command supplies the document attributes needed for
create/update.

Comment on lines +1 to +14
import fs = require('fs');
import pathLib = require('path');
import tar = require('tar');
import ignore = require('ignore');
import { promisify } from 'util';
import Client from '../client';
import { getAllFiles, showConsoleLink } from '../utils';
import { Command } from 'commander';
import { sdkForProject, sdkForConsole } from '../sdks';
import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser';
import { localConfig, globalConfig } from '../config';
import { File } from 'undici';
import { ReadableStream } from 'stream/web';

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the file exists and examine the imports and references
if [ -f "lib/commands/account.ts" ]; then
  echo "=== File exists, checking size ==="
  wc -l lib/commands/account.ts
  
  echo ""
  echo "=== Checking imports section (lines 1-20) ==="
  head -20 lib/commands/account.ts
  
  echo ""
  echo "=== Searching for AuthenticatorType references ==="
  grep -n "AuthenticatorType" lib/commands/account.ts | head -10
  
  echo ""
  echo "=== Searching for AuthenticationFactor references ==="
  grep -n "AuthenticationFactor" lib/commands/account.ts | head -10
  
  echo ""
  echo "=== Searching for OAuthProvider references ==="
  grep -n "OAuthProvider" lib/commands/account.ts | head -10
else
  echo "File not found"
fi

Repository: appwrite/sdk-for-cli

Length of output: 1357


🏁 Script executed:

#!/bin/bash
# Check the context around the references to understand how they're being used
echo "=== Context around AuthenticatorType (line 311) ==="
sed -n '308,315p' lib/commands/account.ts

echo ""
echo "=== Context around AuthenticationFactor (line 393) ==="
sed -n '390,397p' lib/commands/account.ts

echo ""
echo "=== Context around OAuthProvider (line 916) ==="
sed -n '913,920p' lib/commands/account.ts

Repository: appwrite/sdk-for-cli

Length of output: 730


Add missing type imports from appwrite module.

The code references types AuthenticatorType (lines 311, 337, 367), AuthenticationFactor (line 393), and OAuthProvider (lines 916, 1292) that are not imported. Import these types from the appwrite module to resolve compilation errors:

import { AuthenticatorType, AuthenticationFactor, OAuthProvider } from 'appwrite';
🤖 Prompt for AI Agents
In lib/commands/account.ts around lines 1 to 14, the file uses Appwrite types
AuthenticatorType (lines ~311, 337, 367), AuthenticationFactor (~393) and
OAuthProvider (~916, 1292) but does not import them; add a named import from the
'appwrite' module to include AuthenticatorType, AuthenticationFactor and
OAuthProvider at the top of the file so the referenced types resolve and
TypeScript compiles.

Comment on lines +38 to +45
interface ConsoleGetResourceRequestParams {
value: string;
type: ConsoleResourceType;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
console?: boolean;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing type definition: ConsoleResourceType.

The interface references ConsoleResourceType on line 40, but this type is never imported or defined in the file. This will cause a TypeScript compilation error.

🔎 Proposed fix

Either import the type if it exists elsewhere, or define it locally:

+type ConsoleResourceType = string; // or the appropriate union type
+
 interface ConsoleGetResourceRequestParams {
     value: string;
     type: ConsoleResourceType;
     overrideForCli?: boolean;
     parseOutput?: boolean;
     sdk?: Client;
     console?: boolean;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface ConsoleGetResourceRequestParams {
value: string;
type: ConsoleResourceType;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
console?: boolean;
}
type ConsoleResourceType = string; // or the appropriate union type
interface ConsoleGetResourceRequestParams {
value: string;
type: ConsoleResourceType;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
console?: boolean;
}
🤖 Prompt for AI Agents
In lib/commands/console.ts around lines 38-45, the interface references
ConsoleResourceType but that type is not defined or imported; add a proper type
declaration or import to fix the TypeScript error — either import
ConsoleResourceType from the module where it is declared (e.g., add an import
line at the top importing ConsoleResourceType from the package/file that defines
it) or define a local type/union named ConsoleResourceType in this file
(matching the expected values) and use that in the interface.

Comment on lines +569 to +579
interface FunctionsCreateDeploymentRequestParams {
functionId: string;
code: string;
activate: boolean;
entrypoint?: string;
commands?: string;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
onProgress?: (progress: number) => void;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Resolve type mismatches in functionsCreateDeployment (code param and onProgress callback)

Two issues here:

  1. code parameter re-typed at runtime

FunctionsCreateDeploymentRequestParams declares:

code: string;

but inside functionsCreateDeployment you later do:

code = { type: 'file', stream, filename: ..., size: ... };
const size = code.size;
for await (const chunk of code.stream) { ... }

This won’t type‑check in TS (assigning an object to a string), and it makes the runtime shape of code unclear to consumers.

Prefer keeping the param as a path string and introducing a separate local variable for the file object, e.g.:

Sketch of safer approach
export const functionsCreateDeployment = async ({ functionId, code: codePath, ... }: FunctionsCreateDeploymentRequestParams) => {
    const folderPath = fs.realpathSync(codePath);
    // ...
    const filePath = fs.realpathSync(archivePath);
    const nodeStream = fs.createReadStream(filePath);
    const stream = convertReadStreamToReadableStream(nodeStream);

    const fileCode = {
        type: 'file' as const,
        stream,
        filename: pathLib.basename(filePath),
        size: fs.statSync(filePath).size,
    };

    payload.code = fileCode;

    const size = fileCode.size;
    // use fileCode.stream for iteration instead of reusing `code`
};
  1. onProgress callback type doesn’t match the actual argument

The interface currently has:

onProgress?: (progress: number) => void;

but you invoke it as:

onProgress({
    $id: response['$id'],
    progress: ...,
    sizeUploaded: end + 1,
    chunksTotal: response['chunksTotal'],
    chunksUploaded: response['chunksUploaded']
});

This will surprise TS consumers expecting a number. Define a specific shape instead:

Proposed callback type update
 interface FunctionsCreateDeploymentRequestParams {
@@
-    onProgress?: (progress: number) => void;
+    onProgress?: (state: {
+        $id: string;
+        progress: number;
+        sizeUploaded: number;
+        chunksTotal: number;
+        chunksUploaded: number;
+    }) => void;
 }

Also applies to: 581-642, 690-699

🤖 Prompt for AI Agents
In lib/commands/functions.ts around lines 569-579 (and similarly 581-642,
690-699), the FunctionsCreateDeploymentRequestParams incorrectly types `code` as
a string while the function reassigns it to a file object and also types
`onProgress` as a number-only callback while invoking it with an object; change
the `code` param to remain a path string (e.g., `code: string` passed in as
`codePath`) and create a separate local file object (e.g., `fileCode`) that
contains the stream, filename and size which you assign to the payload and
iterate over, and change the `onProgress` type to accept a typed progress object
(define a small interface for { $id?: string; progress: number; sizeUploaded?:
number; chunksTotal?: number; chunksUploaded?: number }) and update all
`onProgress` invocations and uses to pass that object shape instead of a number.

Comment on lines +38 to +43
interface GraphqlQueryRequestParams {
query: object;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Type mismatch: query is typed as object but used as a string.

The interface declares query: object, but line 51 calls JSON.parse(query), which expects a string. This will cause a runtime error if an actual object is passed, or a TypeScript error if a string is passed.

🔎 Proposed fix
 interface GraphqlQueryRequestParams {
-    query: object;
+    query: string;
     overrideForCli?: boolean;
     parseOutput?: boolean;
     sdk?: Client;
 }

And similarly for GraphqlMutationRequestParams on lines 68-73.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface GraphqlQueryRequestParams {
query: object;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
}
interface GraphqlQueryRequestParams {
query: string;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
}
🤖 Prompt for AI Agents
In lib/commands/graphql.ts around lines 38-43 (and similarly for
GraphqlMutationRequestParams at lines ~68-73), the interface currently types
`query` as object but the code treats it as a JSON string (calling
JSON.parse(query)). Change the `query` type to `string` (or to `string | object`
and add runtime handling: if typeof query === 'string' parse it, else use it
directly) for both Query and Mutation request params so types match usage and
avoid runtime/TS errors.

Comment on lines +708 to +713
interface StorageGetUsageRequestParams {
range?: UsageRange;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Undefined type UsageRange.

The UsageRange type is used in StorageGetUsageRequestParams and StorageGetBucketUsageRequestParams but is not imported.

Also applies to: 736-743

🤖 Prompt for AI Agents
In lib/commands/storage.ts around lines 708-713 (and similarly 736-743) the
interface fields reference an undefined type UsageRange; locate the module that
declares UsageRange in the codebase and add an import for it at the top of this
file (for example: import { UsageRange } from '<correct-path-to-definition>'),
or alternatively replace UsageRange with the correct, already-imported type if
it was renamed; ensure the import path is correct and run TypeScript to verify
the error is resolved.

Comment on lines +38 to +46
interface VcsCreateRepositoryDetectionRequestParams {
installationId: string;
providerRepositoryId: string;
type: VCSDetectionType;
providerRootDirectory?: string;
overrideForCli?: boolean;
parseOutput?: boolean;
sdk?: Client;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the vcs.ts file structure and imports
cat -n lib/commands/vcs.ts | head -50

echo "---"
# Search for VCSDetectionType definition in the entire codebase
rg -n "type VCSDetectionType|enum VCSDetectionType" --type ts

Repository: appwrite/sdk-for-cli

Length of output: 2170


🏁 Script executed:

#!/bin/bash
# Search for VCSDetectionType anywhere in the codebase
echo "=== Searching for VCSDetectionType definition ==="
rg "VCSDetectionType" --type ts

echo ""
echo "=== Checking for imports with asterisk or specific type imports ==="
rg "import.*VCSDetectionType|export.*VCSDetectionType" --type ts

echo ""
echo "=== Looking at vcs.ts file around line 76-84 ==="
sed -n '70,90p' lib/commands/vcs.ts

Repository: appwrite/sdk-for-cli

Length of output: 1008


🏁 Script executed:

#!/bin/bash
# Search entire codebase for VCSDetectionType definition
echo "=== Searching entire codebase for VCSDetectionType ==="
rg "type VCSDetectionType|enum VCSDetectionType" --type ts -B 2 -A 2

echo ""
echo "=== Searching in all files, not just TypeScript ==="
rg "VCSDetectionType" -B 2 -A 2

echo ""
echo "=== Check if it's defined in lib/types or similar ==="
find lib -name "*.ts" -type f | head -20

Repository: appwrite/sdk-for-cli

Length of output: 1198


🏁 Script executed:

#!/bin/bash
# Check if VCSDetectionType might be in Client type definitions
echo "=== Checking client.ts for VCSDetectionType ==="
rg "VCSDetectionType" lib/client.ts

echo ""
echo "=== Check for type definitions directory ==="
find . -path ./node_modules -prune -o -name "*.d.ts" -type f -print | head -20

echo ""
echo "=== Search all TypeScript files for VCSDetectionType ==="
git ls-files "*.ts" "*.d.ts" | xargs rg "VCSDetectionType" 2>/dev/null | grep -v "lib/commands/vcs.ts" || echo "Not found outside vcs.ts"

Repository: appwrite/sdk-for-cli

Length of output: 240


Undefined type VCSDetectionType will cause TypeScript compilation error.

The VCSDetectionType type is used in VcsCreateRepositoryDetectionRequestParams (line 41) and VcsListRepositoriesRequestParams (line 78) but is neither imported nor defined in the file. Add the missing type definition or import statement.

🤖 Prompt for AI Agents
In lib/commands/vcs.ts around lines 38–46 (and also referenced at line 78), the
type VCSDetectionType is used but undefined; fix this by either adding an import
for VCSDetectionType from the module where your VCS/shared types are declared
(the same module that exports other VCS types used in this file) or by declaring
and exporting the appropriate type alias/enum locally in this file that matches
the expected values, then update the import/exports accordingly and re-run
TypeScript to ensure the compilation error is resolved.

Comment on lines +25 to +38
case AttributeType.RELATIONSHIP:
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = `List<${type}>`;
}
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Wrap the RELATIONSHIP case body in a block to fix scope issue.

The const relatedCollection declaration inside the switch case can be erroneously accessed by other cases. This is flagged by the linter and is a JavaScript/TypeScript best practice issue.

🔎 Proposed fix
             case AttributeType.RELATIONSHIP:
+            {
                 const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
                 if (!relatedCollection) {
                     throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
                 }
                 type = LanguageMeta.toPascalCase(relatedCollection.name);
                 if (
                     (attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
                     (attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
                     attribute.relationType === 'manyToMany'
                 ) {
                     type = `List<${type}>`;
                 }
                 break;
+            }
🧰 Tools
🪛 Biome (2.1.2)

[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
In lib/type-generation/languages/csharp.ts around lines 25 to 38, the
RELATIONSHIP switch case declares const relatedCollection which leaks scope to
other cases and triggers a linter error; fix by wrapping the entire case body in
its own block (add { ... } around the existing case logic) so relatedCollection
and any other local variables are block-scoped, keep the existing logic and the
break inside that block unchanged.

Comment on lines +62 to +75
case AttributeType.RELATIONSHIP:
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = `List<${type}>`;
}
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Wrap the RELATIONSHIP case body in a block to fix scope issue.

Same issue as in the C# generator - the const relatedCollection declaration should be scoped to this case block.

🔎 Proposed fix
             case AttributeType.RELATIONSHIP:
+            {
                 const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
                 if (!relatedCollection) {
                     throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
                 }
                 type = LanguageMeta.toPascalCase(relatedCollection.name);
                 if (
                     (attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
                     (attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
                     attribute.relationType === 'manyToMany'
                 ) {
                     type = `List<${type}>`;
                 }
                 break;
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case AttributeType.RELATIONSHIP:
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = `List<${type}>`;
}
break;
case AttributeType.RELATIONSHIP:
{
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = `List<${type}>`;
}
break;
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 63-63: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
In lib/type-generation/languages/dart.ts around lines 62 to 75, the RELATIONSHIP
case declares const relatedCollection at switch scope which can cause a scoping
conflict; wrap the entire case body in a block (add { ... } immediately after
the case label and before the break) so relatedCollection and any other locals
are block-scoped, keeping existing logic for computing type and list wrapping
unchanged.

Comment on lines +25 to +38
case AttributeType.RELATIONSHIP:
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = 'List<' + type + '>';
}
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Wrap the RELATIONSHIP case body in a block to fix scope issue.

Same issue as in the other language generators - the const relatedCollection declaration should be scoped to this case block.

🔎 Proposed fix
             case AttributeType.RELATIONSHIP:
+            {
                 const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
                 if (!relatedCollection) {
                     throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
                 }
                 type = LanguageMeta.toPascalCase(relatedCollection.name);
                 if (
                     (attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
                     (attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
                     attribute.relationType === 'manyToMany'
                 ) {
                     type = 'List<' + type + '>';
                 }
                 break;
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case AttributeType.RELATIONSHIP:
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = 'List<' + type + '>';
}
break;
case AttributeType.RELATIONSHIP:
{
const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection);
if (!relatedCollection) {
throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`);
}
type = LanguageMeta.toPascalCase(relatedCollection.name);
if (
(attribute.relationType === 'oneToMany' && attribute.side === 'parent') ||
(attribute.relationType === 'manyToOne' && attribute.side === 'child') ||
attribute.relationType === 'manyToMany'
) {
type = 'List<' + type + '>';
}
break;
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 26-26: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
In lib/type-generation/languages/java.ts around lines 25 to 38, the case for
AttributeType.RELATIONSHIP declares a const (relatedCollection) at case scope
which can leak into other cases; wrap the entire case body in a block by adding
an opening brace after `case AttributeType.RELATIONSHIP:` and a closing brace
before the `break;` so `relatedCollection` and any other declarations are
properly scoped to this case only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants