Fix channel rule commands handling of null and correct property names#98
Fix channel rule commands handling of null and correct property names#98
null and correct property names#98Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughRenamed Namespace payload field from channelNamespace to id and updated create command to map name to id. Adjusted logging conditions for batchingInterval and conflationInterval across create, update, and delete commands to use loose null checks (!= null). No changes to command signatures or overall control flow. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant CLI as Channel Rules CLI
participant API as Control API
U->>CLI: apps channel-rules create/update/delete
Note over CLI: Build payload using Namespace.id<br/>(renamed from channelNamespace)
CLI->>API: createNamespace/updateNamespace/deleteNamespace
API-->>CLI: Response (Namespace)
alt --json flag
CLI-->>U: JSON output
else human-readable
Note over CLI: Log batchingInterval / conflationInterval<br/>when value != null
CLI-->>U: Text summary
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/commands/apps/channel-rules/create.ts (1)
122-136: Update tests to expectidinstead ofchannelNamespace
Tests intest/unit/commands/channel-rule/create.test.ts.skipandtest/integration/control-api.test.tsstill assert onchannelNamespacein the POST body—change those toidto match the updated payload key.src/services/control-api.ts (1)
221-238: Update tests to useidinstead ofchannelNamespace
All assertions intest/unit/commands/channel-rule/create.test.ts.skipandtest/integration/control-api.test.tsstill post{ channelNamespace: … }. Replace everychannelNamespacekey withidto match the updated payload.
🧹 Nitpick comments (4)
src/services/control-api.ts (2)
47-64: Align Namespace types with API nulls for intervals.The API may return null for batchingInterval and conflationInterval. Reflect this in types to avoid unsoundness.
Apply:
export interface Namespace { appId: string; authenticated?: boolean; batchingEnabled?: boolean; - batchingInterval?: number; + batchingInterval?: number | null; conflationEnabled?: boolean; - conflationInterval?: number; + conflationInterval?: number | null; conflationKey?: string; created: number; exposeTimeSerial?: boolean; id: string; modified: number; persistLast?: boolean; persisted: boolean; populateChannelRegistry?: boolean; pushEnabled: boolean; tlsOnly?: boolean; }
555-571: Preserve API error codes to enable friendly auth errors in commands.To support handling error.code === 40100 in commands (per guidelines), include the response code when available.
As a minimal change, attach code if present:
- let errorMessage = `API request failed (${response.status} ${response.statusText})`; + let errorMessage = `API request failed (${response.status} ${response.statusText})`; + let errorCode: unknown = undefined; if ( typeof responseData === "object" && responseData !== null && "message" in responseData && typeof responseData.message === "string" ) { errorMessage += `: ${responseData.message}`; + if ("code" in responseData) { + // preserve code for downstream handling + // eslint-disable-next-line @typescript-eslint/no-explicit-any + errorCode = (responseData as any).code; + } } else if ( typeof responseData === "string" && responseData.length < 100 ) { // Include short string responses directly errorMessage += `: ${responseData}`; } - throw new Error(errorMessage); + const err = new Error(errorMessage) as Error & { code?: unknown; status?: number }; + if (errorCode !== undefined) err.code = errorCode; + err.status = response.status; + throw err;Commands can then check for (error as any).code === 40100 to print a login hint. As per coding guidelines.
src/commands/apps/channel-rules/delete.ts (1)
45-51: Avoid appId shadowing inside try.Inner let appId shadows the outer variable, so catch blocks may log undefined appId. Assign to the outer variable instead.
Apply:
- let appId = flags.app; + appId = flags.app; if (!appId) { appId = await this.resolveAppId(flags); }src/commands/apps/channel-rules/create.ts (1)
94-100: Remove appId shadowing inside try.Inner let appId hides the outer variable; errors in the try block will yield undefined appId in catch output. Assign to the outer variable.
Apply:
- let appId = flags.app; + appId = flags.app; if (!appId) { appId = await this.resolveAppId(flags); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/commands/apps/channel-rules/create.ts(3 hunks)src/commands/apps/channel-rules/delete.ts(2 hunks)src/commands/apps/channel-rules/update.ts(2 hunks)src/services/control-api.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/commands/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/AI-Assistance.mdc)
src/commands/**/*.ts: Commands should follow the oclif structure: export default class MyCommand extends Command { ... }
Command should support auth via the standard auth helper (import { getAuth } from '../../helpers/auth') and use it in the run method.
Use try/catch for error handling in commands, and provide user-friendly error messages (e.g., handle error.code === 40100 for authentication failures).
Do not use direct HTTP requests (e.g., fetch) for data plane APIs; use the Ably SDK instead.
Do not use hardcoded endpoint URLs; use configuration values (e.g., flags.controlHost, config.controlHost) when constructing URLs.
Do not use non-standard command structures (e.g., export default class { async execute(args) { ... } }); always use the oclif Command class.
Files:
src/commands/apps/channel-rules/update.tssrc/commands/apps/channel-rules/create.tssrc/commands/apps/channel-rules/delete.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/Development.mdc)
**/*.{ts,tsx}: Use TypeScript and follow best practice naming conventions
ESLint is used to ensure all code adheres best practices; ensure you check that all code passes the linter before concluding your work.
Files:
src/commands/apps/channel-rules/update.tssrc/commands/apps/channel-rules/create.tssrc/services/control-api.tssrc/commands/apps/channel-rules/delete.ts
src/commands/**/*.{ts,js}
📄 CodeRabbit inference engine (.cursor/rules/Development.mdc)
Follow oclif framework best practices as described in the oclif documentation.
Files:
src/commands/apps/channel-rules/update.tssrc/commands/apps/channel-rules/create.tssrc/commands/apps/channel-rules/delete.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: setup
- GitHub Check: e2e-cli
- GitHub Check: test
🔇 Additional comments (3)
src/commands/apps/channel-rules/update.ts (1)
308-312: Good null-handling; avoids toString on null.Switching to != null correctly skips logging when values are null or undefined, preventing runtime errors and matching API behavior.
Also applies to: 320-324
src/commands/apps/channel-rules/delete.ts (1)
138-142: Correct null-handling for interval logging.Using != null avoids logging and formatting null values. Good fix.
Also applies to: 150-154
src/commands/apps/channel-rules/create.ts (1)
212-216: Correctly handle null intervals in output.The != null checks prevent logging nulls and avoid calling toString on null. Good.
Also applies to: 224-228
| ); | ||
| } | ||
|
|
||
| if (createdNamespace.batchingInterval !== undefined) { |
There was a problem hiding this comment.
should these be falsy checks?
if (!createdNamespace.batchingInterval) {There was a problem hiding this comment.
Pull request overview
Fixes the apps channel-rules CLI commands to use the correct namespace identifier field and to avoid errors when the Control API returns null for interval fields.
Changes:
- Switch namespace create payload from
channelNamespacetoid. - Handle
nullvalues forbatchingIntervalandconflationIntervalin create/update/delete command output. - Update integration test namespace creation payload to use
id.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/integration/control-api.test.ts | Updates namespace creation test payload to use id and normalizes whitespace. |
| src/services/control-api.ts | Updates createNamespace input type to use id instead of channelNamespace. |
| src/commands/apps/channel-rules/create.ts | Sends id in create request; adjusts interval display guards to handle null. |
| src/commands/apps/channel-rules/update.ts | Adjusts interval display guards to handle null. |
| src/commands/apps/channel-rules/delete.ts | Adjusts interval display guards to handle null. |
Comments suppressed due to low confidence (6)
src/commands/apps/channel-rules/delete.ts:142
!= nullis a non-strict comparison and will be flagged by ESLinteqeqeq(enabled via recommended rules). Prefer a strict null/undefined guard (ortypeof ... === "number") before calling.toString().
if (namespace.batchingInterval != null) {
this.log(
`Batching Interval: ${chalk.green(namespace.batchingInterval.toString())}`,
);
}
src/commands/apps/channel-rules/delete.ts:154
- Non-strict null check (
!= null) will violate ESLinteqeqeqand is inconsistent with the strict checks used elsewhere in this file. Use a strict guard for null/undefined (ortypeof ... === "number") before.toString().
if (namespace.conflationInterval != null) {
this.log(
`Conflation Interval: ${chalk.green(namespace.conflationInterval.toString())}`,
);
}
src/commands/apps/channel-rules/create.ts:216
- Non-strict null check (
!= null) will trip ESLint'seqeqeqrule (enabled via the base recommended rules) and is inconsistent with the rest of this file’s strict!== undefinedchecks. Use a strict guard instead (e.g.,!== null && !== undefinedortypeof ... === "number") before calling.toString().
if (createdNamespace.batchingInterval != null) {
this.log(
`Batching Interval: ${chalk.green(createdNamespace.batchingInterval.toString())}`,
);
}
src/commands/apps/channel-rules/create.ts:228
- Non-strict null check (
!= null) is likely to fail linting undereqeqeqand diverges from nearby strict!== undefinedpatterns. Prefer a strict guard (e.g.,!== null && !== undefinedortypeof ... === "number") before.toString().
if (createdNamespace.conflationInterval != null) {
this.log(
`Conflation Interval: ${chalk.green(createdNamespace.conflationInterval.toString())}`,
);
}
src/commands/apps/channel-rules/update.ts:312
- Using
!= nullwill violate ESLinteqeqeqand is inconsistent with the strict comparisons used elsewhere in this command. Switch to a strict null/undefined guard (ortypeof ... === "number") before calling.toString().
if (updatedNamespace.batchingInterval != null) {
this.log(
`Batching Interval: ${chalk.green(updatedNamespace.batchingInterval.toString())}`,
);
}
src/commands/apps/channel-rules/update.ts:324
- Non-strict null check (
!= null) will faileqeqeqlinting and differs from the surrounding strict!== undefinedchecks. Use a strict guard for null/undefined (ortypeof ... === "number") before calling.toString().
if (updatedNamespace.conflationInterval != null) {
this.log(
`Conflation Interval: ${chalk.green(updatedNamespace.conflationInterval.toString())}`,
);
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| authenticated?: boolean; | ||
| batchingEnabled?: boolean; | ||
| batchingInterval?: number; | ||
| channelNamespace: string; | ||
| id: string; | ||
| conflationEnabled?: boolean; | ||
| conflationInterval?: number; | ||
| conflationKey?: string; |
There was a problem hiding this comment.
Now that the CLI explicitly handles batchingInterval/conflationInterval potentially being null, the Namespace model (and related method return types) should reflect that (number | null) rather than only number. Keeping the type accurate will prevent future code from accidentally calling number methods on null and removes the need for non-strict null checks in consumers.
There was a problem hiding this comment.
@coderabbitai do you think aboe suggestion is correct? Provide detailed explaination for the same
There was a problem hiding this comment.
@sacOO7, yes, Copilot's suggestion is correct. Here's a detailed explanation:
Current Type Definition
The Namespace interface currently defines these fields as:
batchingInterval?: number;
conflationInterval?: number;The ? operator makes these optional properties, which means their type is number | undefined. A property is undefined when it's absent/not set.
The Problem
According to the PR objectives, the API can explicitly return null for these fields (not just omit them). However, null is not the same as undefined in TypeScript:
undefined= property is absent/not setnull= property is explicitly set to null
Since the current types are number | undefined, TypeScript won't catch type errors if code assumes these are always numbers when the property exists:
// This would compile fine with current types, but crash at runtime if value is null
const interval = namespace.batchingInterval; // Type: number | undefined
if (interval !== undefined) {
console.log(interval.toFixed(2)); // ❌ Runtime error if interval is null
}The Fix
The checks in your PR were changed from !== undefined to != null (loose equality) specifically because the API returns null. The types should match this reality:
batchingInterval?: number | null;
conflationInterval?: number | null;This expands to number | null | undefined, which accurately represents:
- Field might be absent (
undefined) - Field might be explicitly null (
null) - Field might contain a number
Recommendation
Update the Namespace interface to reflect the actual API behavior:
export interface Namespace {
// ... other fields ...
batchingInterval?: number | null;
conflationInterval?: number | null;
// ... other fields ...
}This makes the type system more accurate and helps prevent runtime errors by forcing explicit null checks.
There was a problem hiding this comment.
@coderabbitai https://github.com/coderabbitai It's also suggested to change channelNamespace into id, is it expected or no?
There was a problem hiding this comment.
@sacOO7, yes, changing channelNamespace to id is expected and correct. Here's why:
The Namespace Interface Uses id
Looking at the Namespace interface (which is the return type of createNamespace), the field is defined as:
export interface Namespace {
// ...
id: string; // ← The field name in the interface
// ...
}There is no channelNamespace field in the Namespace interface.
Input Should Match Output
The createNamespace method:
- Accepts parameters to create a namespace
- Returns a
Namespaceobject
The parameter field names should align with the field names in the returned Namespace type. Since the API returns an object with an id field (not channelNamespace), the input parameter should also use id.
Bug Fix Per PR Objectives
The PR description explicitly states:
"Previously failed because it sent
channelNamepsaceinstead ofidin the request."
This confirms it was a bug - the API expects id as the field name, but the code was incorrectly sending channelNamespace.
Summary
✅ The change is correct: The parameter should be id to match:
- The
Namespaceinterface field name - What the Control API expects
- Consistency between input parameters and output types
Description
This PR fixes issues with the
channel-rulescommands;channel-rules createchannel-rules updatechannel-rules deletechannel-rules createchannelNamepsaceinstead ofidin the request.nullbeing returned forbatchingIntervalandconflationInterval.channel-rules updateandchannel-rules deletenullbeing returned forbatchingIntervalandconflationInterval.Summary by CodeRabbit