Skip to content

fix(cli): console auth for console-only services and improved output rendering#1399

Open
ChiragAgg5k wants to merge 3 commits intomasterfrom
fix/cli-console-auth-and-rendering
Open

fix(cli): console auth for console-only services and improved output rendering#1399
ChiragAgg5k wants to merge 3 commits intomasterfrom
fix/cli-console-auth-and-rendering

Conversation

@ChiragAgg5k
Copy link
Copy Markdown
Member

@ChiragAgg5k ChiragAgg5k commented Mar 28, 2026

Summary

  • Fix console-only service auth: Services like projects, organizations, console, etc. now use sdkForConsole instead of sdkForProject, fixing 401 errors on commands like projects create-key. Detection is based on x-appwrite.platforms metadata from the spec — services where all methods are console-only get sdkForConsole, mixed services keep sdkForProject.
  • Fix init project override flow: When declining to override an existing project config, the CLI no longer continues to ask project name/ID questions before exiting.
  • Fix BigInt serialization: Added BigInt.prototype.toJSON polyfill to fix JSON.stringify cannot serialize BigInt errors on API responses.
  • Improve output rendering: Wide responses (>6 columns) now render as condensed aligned key-value output instead of unreadable tables, filtering out null, empty, and nested object fields. Table cells for complex values show summaries like {N keys} / [N items].
  • Add --raw flag: --json now outputs filtered JSON (same fields as default view), --raw outputs the full unfiltered response.
  • Filter toString from output: Function-typed keys on API response objects are excluded from rendering.
  • Teams service hint: When teams commands fail due to missing project config, a hint suggests using organizations instead.

Test plan

  • appwrite projects create-key no longer returns 401
  • appwrite organizations list renders cleanly with aligned key-value output
  • appwrite organizations list --json outputs filtered JSON
  • appwrite organizations list --raw outputs full JSON
  • appwrite projects list-keys still renders as table (few columns)
  • appwrite teams list (without project) shows hint about organizations
  • Init project flow exits immediately when override is declined
  • No toString line in output
  • No BigInt serialization errors

Summary by CodeRabbit

  • New Features

    • Added --raw CLI flag for unfiltered JSON output.
    • Console-only service support to select the appropriate client at runtime.
    • BigInt JSON serialization support.
  • Improvements

    • Condensed table rendering, improved cell formatting and truncation.
    • JSON filtering: omit nulls/empty strings/functions and stringify big-number types.
    • Prompts and help text refined for project/team flows.

…e output rendering

- Use sdkForConsole for console-only services (projects, organizations, etc.) based on
  x-appwrite.platforms metadata, fixing 401 errors on commands like `projects create-key`
- Fix init project flow continuing to ask questions after user declines override
- Add BigInt.prototype.toJSON polyfill to fix JSON.stringify errors on API responses
- Improve table rendering: fall back to condensed key-value output when columns exceed 6,
  filtering out null/empty/object fields for readability
- Add --raw flag for full unfiltered JSON output; --json now outputs filtered JSON
- Filter out function-typed keys (toString) from rendered output
- Add hint for teams service suggesting organizations command when no project is configured
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

Adds a CLI "raw" JSON output mode and propagates a computed isConsoleOnly flag from Swagger parsing into SDK/template generation, enabling templates to choose console vs project SDK and adjust CLI output/filtering logic.

Changes

Cohort / File(s) Summary
Spec parsing & SDK generation
src/Spec/Swagger2.php, src/SDK/SDK.php
Populate method platforms from x-appwrite.platforms; add SDK::isConsoleOnly(array $methods): bool and pass service.isConsoleOnly into templates.
CLI core option & types
templates/cli/cli.ts.twig, templates/cli/lib/types.ts
Add -R, --raw option and cliConfig.raw: boolean; wire option event to set raw mode.
CLI parser & output formatting
templates/cli/lib/parser.ts
Add BigInt JSON polyfill, cliConfig.raw, filterData()/filterObject(), formatCellValue(), modified drawTable/drawJSON flows; raw mode prints unfiltered JSON, json mode prints filtered JSON.
Service commands template
templates/cli/lib/commands/services/services.ts.twig
Conditional import/initialization of sdkForConsole vs sdkForProject using service.isConsoleOnly; special teams try/catch to emit a hint when project is not set.
Interactive prompts
templates/cli/lib/questions.ts
project and id prompts now gated by both override allowance and answer.start !== "existing".
Minor whitespace
templates/cli/lib/sdks.ts
Add trailing newline at EOF.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Swagger as SwaggerSpec
participant Generator as SDK_Generator
participant Template as TemplateEngine
participant CLI as CLI_Binary
participant SDK as SDK_Runtime

Swagger->>Generator: parse methods + x-appwrite.platforms
Generator-->>Template: emit service metadata (including isConsoleOnly)
Template-->>CLI: generated CLI code (conditional imports/logic)
CLI->>SDK: initialize client (sdkForConsole or sdkForProject) based on service.isConsoleOnly
CLI->>CLI: user invokes command with flags (--raw / --json)
CLI->>CLI: if --raw -> draw unfiltered JSON; else -> filterData() -> format -> draw

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through specs and templates bright,
Marked console-only with careful sight,
A raw flag now for JSON unbound,
Or filtered views that tidy round,
Hop, code, repeat — carrots all around 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 accurately summarizes the main changes: adding console authentication for console-only services and improving CLI output rendering, which are the core objectives of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cli-console-auth-and-rendering

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 28, 2026

Greptile Summary

This PR addresses several real pain points in the Appwrite CLI: console-only service authentication, the init project override flow, BigInt serialization errors, and wide-response rendering. The approach is generally sound, but two P1 issues need attention before merging.

Key changes:

  • isConsoleOnly() in SDK.php classifies services based on x-appwrite.platforms metadata — but the logic treats methods with an empty (unspecified) platforms array the same as ['console'], which can produce false positives and wrongly route generic services through sdkForConsole
  • drawTable condensed path (allKeys.length > 6) calls Math.max(...emptyArray) when all row values are filtered, producing -Infinity and a RangeError crash in \"─\".repeat(-Infinity)
  • The --json flag now emits filtered output (dropping object fields) instead of the full response — a silent breaking change for existing automation scripts; the new --raw flag carries the previous --json semantics
  • BigInt.prototype.toJSON polyfill is patched globally at module load; a replacer function in drawJSON would scope the side-effect more narrowly
  • The questionsInitProject fix (adding whenOverride guards) and the teams hint are clean and correct

Confidence Score: 3/5

Two P1 issues on changed code paths should be resolved before merging

The isConsoleOnly false-positive can silently misroute generic services to console auth (the inverse of the intended fix), and the Math.max on an empty spread is a real RangeError crash in the new condensed table rendering. Both affect primary user paths.

src/SDK/SDK.php (isConsoleOnly logic) and templates/cli/lib/parser.ts (condensed table Math.max guard)

Important Files Changed

Filename Overview
src/SDK/SDK.php Adds isConsoleOnly() helper to classify services — logic has a false-positive: methods with empty platforms (unspecified) are treated the same as ['console'], which can incorrectly mark generic services as console-only
src/Spec/Swagger2.php Adds platforms field from x-appwrite.platforms to the parsed method output — straightforward and correct
templates/cli/lib/parser.ts Adds BigInt polyfill, --raw flag, filterData/filterObject helpers, and condensed key-value table mode; condensed path has a Math.max(-Infinity) crash when all row values are filtered; --json behavior change is a breaking change
templates/cli/lib/commands/services/services.ts.twig Switches console-only services to sdkForConsole and adds a teams hint; teams has a hardcoded sdkForProject call (correct) despite the isConsoleOnly path, which is fine but potentially fragile
templates/cli/lib/questions.ts Correctly adds whenOverride guard to project name and id questions so the init flow exits immediately when override is declined
templates/cli/cli.ts.twig Adds --raw / -R CLI option and wires cliConfig.raw; straightforward and correct
templates/cli/lib/types.ts Adds raw boolean field to CliConfig interface — minimal, correct change
templates/cli/lib/sdks.ts Adds trailing newline only — no functional change

Reviews (1): Last reviewed commit: "fix(cli): use correct SDK client for con..." | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@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: 4

🧹 Nitpick comments (1)
templates/cli/lib/parser.ts (1)

1-2: Guard the BigInt polyfill before overriding the prototype.

This runs at module load and unconditionally replaces any existing BigInt.prototype.toJSON. A polyfill should only install itself when the method is absent.

🛠️ Suggested fix
-// `@ts-expect-error` BigInt toJSON polyfill for JSON.stringify support
-BigInt.prototype.toJSON = function () { return this.toString(); };
+if (typeof BigInt.prototype.toJSON !== "function") {
+  // `@ts-expect-error` BigInt toJSON polyfill for JSON.stringify support
+  BigInt.prototype.toJSON = function () {
+    return this.toString();
+  };
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/cli/lib/parser.ts` around lines 1 - 2, Guard the BigInt polyfill so
it only installs when missing: check that BigInt exists and
BigInt.prototype.toJSON is not already defined before assigning; e.g. wrap the
assignment in a conditional like if (typeof BigInt !== "undefined" && !("toJSON"
in BigInt.prototype)) { BigInt.prototype.toJSON = function () { return
this.toString(); }; } so you don't unconditionally overwrite an existing
BigInt.prototype.toJSON implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SDK/SDK.php`:
- Around line 1278-1287: The isConsoleOnly method incorrectly treats missing or
empty 'platforms' as console-only; update isConsoleOnly to require an explicit
platforms array equal to ['console'] for every method—if the 'platforms' key is
not set or is empty or any method's platforms is not exactly ['console'], return
false; locate and change this logic in the protected function
isConsoleOnly(array $methods): bool to ensure only methods that explicitly
declare platforms = ['console'] contribute to a true result.

In `@templates/cli/lib/commands/services/services.ts.twig`:
- Around line 50-57: The catch around sdkForProject() unconditionally shows the
'teams' hint; change the catch in the service.name == 'teams' branch to inspect
the thrown error from sdkForProject() and only call hint(...) when the error
indicates a missing-project condition (e.g., check error.code for a
PROJECT/NO_PROJECT/NOT_FOUND value or error.message contains "project" or "no
project"); for all other errors (like authentication/session errors) rethrow
without the teams hint so logged-out users are not misdirected. Ensure this
logic is applied in the catch that currently wraps sdkForProject().

In `@templates/cli/lib/parser.ts`:
- Around line 181-208: When rendering condensed output, guard against the case
where every field is filtered out by checking if rowEntries.flat() is empty
before computing maxKeyLen/separatorLen; if empty, fall back to the existing
JSON/verbose renderer (e.g., console.log(JSON.stringify(rows, null, 2))) and
return. Implement this check in the block that builds rowEntries (referencing
rowEntries, maxKeyLen, separatorLen, rows, MAX_COL_WIDTH) so you never call
Math.max on an empty array or repeat a negative length; additionally ensure
separatorLen is bounded with Math.max(0, computedValue) if you keep the repeat
call.
- Around line 61-95: filterObject and filterData currently drop any value where
typeof value === "object", which removes BigNumber fields that parse() and
formatCellValue treat as scalars; update both functions to detect and allow
BigNumber instances instead of skipping them. Change the object-check logic in
filterObject and the else-if branch in filterData so that you only skip plain
objects (and still handle arrays), but pass through BigNumber values by checking
via BigNumber.isBigNumber(value) or a safe constructor-name/instance check
(e.g., value?.constructor?.name === "BigNumber" or an imported BigNumber type),
ensuring BigNumber fields are included in the returned result.

---

Nitpick comments:
In `@templates/cli/lib/parser.ts`:
- Around line 1-2: Guard the BigInt polyfill so it only installs when missing:
check that BigInt exists and BigInt.prototype.toJSON is not already defined
before assigning; e.g. wrap the assignment in a conditional like if (typeof
BigInt !== "undefined" && !("toJSON" in BigInt.prototype)) {
BigInt.prototype.toJSON = function () { return this.toString(); }; } so you
don't unconditionally overwrite an existing BigInt.prototype.toJSON
implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a01e8e0-c40b-4e28-985b-84e6bea97964

📥 Commits

Reviewing files that changed from the base of the PR and between 5899a28 and 8f156d3.

📒 Files selected for processing (8)
  • src/SDK/SDK.php
  • src/Spec/Swagger2.php
  • templates/cli/cli.ts.twig
  • templates/cli/lib/commands/services/services.ts.twig
  • templates/cli/lib/parser.ts
  • templates/cli/lib/questions.ts
  • templates/cli/lib/sdks.ts
  • templates/cli/lib/types.ts

- Require explicit ['console'] platforms in isConsoleOnly (empty/missing no longer matches)
- Guard Math.max against empty entries in condensed renderer
- Scope teams hint to missing-project errors only, not session errors
- Preserve BigNumber values in filtered JSON output
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@templates/cli/lib/parser.ts`:
- Around line 196-204: The condensed renderer loop in parser.ts is erroneously
dropping BigNumber instances because it excludes all objects (if (typeof value
=== "object") continue); update the loop that builds entries from row so
BigNumber instances are detected before the generic object check and are
preserved by converting them to string (or delegating to formatCellValue),
mirroring the behavior of filterObject and filterData; specifically adjust the
logic around row, value and entries to treat BigNumber instances as primitives
rather than skipping them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e766b9cd-91aa-4213-9846-f7d6da9f4c1d

📥 Commits

Reviewing files that changed from the base of the PR and between 8f156d3 and f78c194.

📒 Files selected for processing (3)
  • src/SDK/SDK.php
  • templates/cli/lib/commands/services/services.ts.twig
  • templates/cli/lib/parser.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/SDK/SDK.php
  • templates/cli/lib/commands/services/services.ts.twig

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (2)
templates/cli/lib/parser.ts (2)

1-2: Consider using JSONBig.stringify instead of polyfilling BigInt.prototype.toJSON.

Modifying built-in prototypes affects global state. The codebase already has JSONBig.stringify in lib/json.ts designed for BigInt serialization. Using that in drawJSON would avoid prototype pollution and keep serialization consistent.

♻️ Proposed alternative
-// `@ts-expect-error` BigInt toJSON polyfill for JSON.stringify support
-BigInt.prototype.toJSON = function () { return this.toString(); };
-
 import chalk from "chalk";
 import { InvalidArgumentError } from "commander";
 import Table from "cli-table3";
 import packageJson from "../package.json" with { type: "json" };
+import { JSONBig } from "./json.js";

Then update drawJSON:

 export const drawJSON = (data: unknown): void => {
-  console.log(JSON.stringify(data, null, 2));
+  console.log(JSONBig.stringify(data, null, 2));
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/cli/lib/parser.ts` around lines 1 - 2, The file currently polyfills
BigInt.prototype.toJSON which mutates global state; remove that polyfill and
update the JSON serialization to use the existing JSONBig.stringify
implementation from lib/json.ts instead. Specifically, delete the
BigInt.prototype.toJSON assignment and modify the drawJSON callers (or the
drawJSON implementation) to call JSONBig.stringify(...) for serializing data
containing BigInt values so serialization remains consistent without prototype
pollution.

61-104: Consider using the isBigNumber type guard from json.ts for robustness.

The value?.constructor?.name === "BigNumber" pattern is fragile (can break with minification or multiple library instances). The codebase already has a robust isBigNumber type guard in lib/json.ts that checks _isBigNumber property and method signatures.

♻️ Example of reusing isBigNumber

Export and import the helper:

// In json.ts, export the function
export function isBigNumber(value: unknown): value is BigNumberLike { ... }

// In parser.ts
import { isBigNumber } from "./json.js";

Then replace checks like:

-if (value?.constructor?.name === "BigNumber") {
+if (isBigNumber(value)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/cli/lib/parser.ts` around lines 61 - 104, Replace fragile
constructor-name checks with the exported isBigNumber type guard from json.ts:
import isBigNumber from "./json.js" (or named import as exported) and update all
places in filterObject and filterData that check value?.constructor?.name ===
"BigNumber" (and the similar check inside the Array.map for items) to use
isBigNumber(value) / isBigNumber(item) instead, and keep the same behavior of
converting BigNumber to String; ensure imports and type-narrowing follow the
existing isBigNumber signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@templates/cli/lib/parser.ts`:
- Around line 1-2: The file currently polyfills BigInt.prototype.toJSON which
mutates global state; remove that polyfill and update the JSON serialization to
use the existing JSONBig.stringify implementation from lib/json.ts instead.
Specifically, delete the BigInt.prototype.toJSON assignment and modify the
drawJSON callers (or the drawJSON implementation) to call JSONBig.stringify(...)
for serializing data containing BigInt values so serialization remains
consistent without prototype pollution.
- Around line 61-104: Replace fragile constructor-name checks with the exported
isBigNumber type guard from json.ts: import isBigNumber from "./json.js" (or
named import as exported) and update all places in filterObject and filterData
that check value?.constructor?.name === "BigNumber" (and the similar check
inside the Array.map for items) to use isBigNumber(value) / isBigNumber(item)
instead, and keep the same behavior of converting BigNumber to String; ensure
imports and type-narrowing follow the existing isBigNumber signature.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: df85c68d-7c57-4a7b-988f-a8e19d2830a1

📥 Commits

Reviewing files that changed from the base of the PR and between f78c194 and 1e85199.

📒 Files selected for processing (1)
  • templates/cli/lib/parser.ts

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.

1 participant