Skip to content

Conversation

@bigcat88
Copy link
Contributor

@bigcat88 bigcat88 commented Dec 31, 2025

Summary

WIP

Changes

  • What:
  • Breaking:
  • Dependencies:

Review Focus

Screenshots (if applicable)

┆Issue is synchronized with this Notion page by Unito

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Replaces static node pricing with a JSONata-driven runtime pricing system: adds the jsonata dependency, introduces a price_badge schema, implements async compile/evaluate/caching in a new composable, and updates badge rendering to subscribe to pricing revisions and batch canvas redraws.

Changes

Cohort / File(s) Summary
Dependency / Workspace
package.json, pnpm-workspace.yaml
Added jsonata dependency and registered it in the pnpm workspace catalog.
Pricing Schema
src/schemas/nodeDefSchema.ts
Added zPriceBadge, zPriceBadgeDepends, zWidgetDependency, exported PriceBadge and WidgetDependency; extended zComfyNodeDef with optional price_badge.
Runtime Pricing Composable
src/composables/node/useNodePricing.ts
New JSONata-based pricing pipeline: rule extraction from node defs, compile/cache per node type, async evaluation with a normalized widget/input context, signature-based re-eval, non-blocking scheduling, and public API (getNodeDisplayPrice, getNodePricingConfig, getRelevantWidgetNames, pricingRevision). New types and error-tolerant behavior added.
Badge Rendering / Node Badge
src/composables/node/useNodeBadge.ts
Changed badge wiring to use a cached getter and requestAnimationFrame redraw queue; subscribes to pricingRevision and uses widget watchers only to trigger redraws rather than compute badge values directly.
Node Definitions Store
src/stores/nodeDefStore.ts
Added price_badge?: PriceBadge to ComfyNodeDefImpl and initialized it from input.
Tests
src/composables/node/useNodePricing.test.ts
Reworked tests and helpers to construct PriceBadge-backed mock nodes; added coverage for JSONata expressions, widget normalization, input connectivity, and getNodePricingConfig.

Sequence Diagrams

sequenceDiagram
    autonumber
    participant Badge as Badge Renderer
    participant Pricing as useNodePricing
    participant Store as NodeDefStore
    participant Cache as Compiled Rule Cache
    participant Jsonata as JSONata Engine
    participant UI as Canvas Renderer

    Note over Badge,Pricing: getNodeDisplayPrice flow (fast-path vs async)
    Badge->>Pricing: getNodeDisplayPrice(node)
    alt cached label available
        Pricing-->>Badge: return cached label
    else
        Pricing->>Store: fetch node definition (price_badge)
        Store-->>Pricing: return price_badge
        Pricing->>Cache: lookup compiled rule for node type
        alt compiled rule cached
            Cache-->>Pricing: compiled rule
        else
            Pricing->>Jsonata: compile rule.expr
            Jsonata-->>Pricing: compiled rule
            Pricing->>Cache: store compiled rule
        end
        Pricing->>Jsonata: evaluate rule with context (async)
        Jsonata-->>Pricing: evaluation result
        Pricing->>Pricing: format & cache display label
        Pricing->>Badge: bump pricingRevision (reactive)
    end
    Badge->>UI: queue redraw (requestAnimationFrame)
    UI->>UI: batch render on next frame
Loading

Possibly related PRs


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.

@DrJKL
Copy link
Contributor

DrJKL commented Jan 5, 2026

@coderabbitai review full

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

@DrJKL I'll perform a full review of all the changes in this PR.

✅ Actions performed

Full review triggered.

1 similar comment
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

@DrJKL I'll perform a full review of all the changes in this PR.

✅ Actions performed

Full review triggered.

Copy link
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: 8

Fix all issues with AI Agents 🤖
In @src/composables/node/useNodePricing.ts:
- Around line 408-436: In getNodeDisplayPrice, the bare read pricingTick.value
is an intentional reactive dependency for Vue but looks like a no-op; add a
short inline comment immediately above or on the same line explaining that the
read is deliberate to trigger recomputation (e.g., "intentional reactive
dependency to bump computed re-evaluation; do not remove") so future readers
won't remove it; keep the comment concise and reference pricingTick.value and
the purpose of scheduling async evaluation via scheduleEvaluation.
- Around line 336-374: Add a timeout wrapper around the JSONata evaluation so
rule._compiled.evaluate(ctx) cannot hang indefinitely: create a withTimeout
helper that races the evaluation promise against a setTimeout rejection (e.g.,
1s or configurable), then replace the current
Promise.resolve(rule._compiled.evaluate(...)) call with withTimeout(...). Ensure
the resulting promise is still stored in inflight via inflight.set(node, { sig,
promise }) and that the existing .catch and .finally logic that updates cache,
desiredSig checks, and increments pricingTick.value handles timeout rejections
the same as other errors (i.e., log in development and cache an empty label for
the same sig).
- Around line 166-170: Remove the explicit any in the filter callback so
TypeScript infers the input type from node.inputs; update the connectedCount
computation to use a typed callback like node.inputs?.filter(inp =>
inp?.name?.startsWith(prefix) && inp?.link != null).length ?? 0 (or add a proper
Input type and annotate node.inputs as Input[] if needed) and leave g[groupName]
= connectedCount unchanged.
- Around line 151-160: The loop uses unsafe any types for widget/input lookups;
replace (x: any) with the actual types for node.widgets and node.inputs (e.g.,
Widget and Input or the project's defined interfaces) so the find callbacks and
subsequent access (x?.name, widget?.value, slot?.link) are type-checked; update
the variable declarations for widget and slot in the block referencing
rule.depends_on.widgets and rule.depends_on.inputs, ensure normalizeWidgetValue
accepts the Widget.value type, and adjust the i Record type if needed to reflect
the real Input shape rather than relying on any.
- Around line 255-263: compileRule currently forces the jsonata(...) result to
any which bypasses typings; change this to use jsonata's proper Expression type
(or create a local alias) and update CompiledJsonataPricingRule._compiled to
Expression | null; then replace the cast "as any" with a typed assignment like
const compiled: Expression = jsonata(rule.expr) and return { ...rule, _compiled:
compiled } so the code uses correct jsonata types without any casting while
keeping the catch path returning _compiled: null.
- Around line 453-472: Add a readonly price_badge?: PriceBadge property to the
ComfyNodeDefImpl class so price_badge is properly typed (remove the need for the
as any cast in getRelevantWidgetNames), and change the getRelevantWidgetNames
const arrow function into a named function declaration (function
getRelevantWidgetNames(nodeType: string): string[]) keeping the same body and
behavior; locate ComfyNodeDefImpl to add the property and replace the const
getRelevantWidgetNames = (...) => { ... } with a function declaration to match
codebase conventions.

In @src/schemas/nodeDefSchema.ts:
- Around line 222-228: The default value for the depends_on field on zPriceBadge
omits input_groups which can cause type mismatches with zPriceBadgeDepends;
update the default object used in zPriceBadge.depends_on to include
input_groups: [] (so the default becomes { widgets: [], inputs: [],
input_groups: [] }) and ensure the shape matches zPriceBadgeDepends to avoid
narrowing issues.

Caution

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

⚠️ Outside diff range comments (1)
src/composables/node/useNodeBadge.ts (1)

148-156: Clarify the intent of the discarded computed value.

The call to computedWithWidgetWatch(() => 0) registers widget listeners but discards the returned computed. While the comments explain this, the pattern is unusual and could confuse future maintainers.

Consider extracting this into a dedicated function in useWatchWidget that explicitly only registers listeners without returning a computed, or add a more prominent comment explaining why this pattern is necessary.

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14528aa and 15b124b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • package.json
  • pnpm-workspace.yaml
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
🧰 Additional context used
📓 Path-based instructions (11)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • package.json
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
🧠 Learnings (5)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodePricing.ts
🧬 Code graph analysis (2)
src/composables/node/useNodeBadge.ts (3)
src/scripts/app.ts (1)
  • app (1772-1772)
src/utils/migration/migrateReroute.ts (1)
  • node (91-107)
src/stores/commandStore.ts (1)
  • label (52-54)
src/composables/node/useNodePricing.ts (3)
src/schemas/nodeDefSchema.ts (1)
  • PriceBadge (230-230)
src/stores/commandStore.ts (1)
  • label (52-54)
src/stores/nodeDefStore.ts (2)
  • useNodeDefStore (293-455)
  • nodeDef (82-108)
🔇 Additional comments (9)
package.json (1)

174-174: LGTM!

The jsonata dependency addition aligns with the PR's objective to use JSONata expressions for pricing evaluation. The catalog reference correctly points to the version defined in pnpm-workspace.yaml.

src/schemas/nodeDefSchema.ts (2)

200-215: Schema and documentation look good.

The zPriceBadgeDepends schema is well-documented, explaining the autogrow input group behavior and how the count is exposed in the JSONata context. The use of optional().default([]) for array fields ensures safe access.


259-266: LGTM!

The price_badge field is appropriately added as optional to zComfyNodeDef with clear documentation explaining its purpose for API node pricing.

src/composables/node/useNodeBadge.ts (3)

76-84: LGTM! Clean debouncing implementation.

The queueCanvasRedraw function properly batches multiple redraw requests within a single animation frame using a guard flag. This prevents excessive redraws when multiple pricing evaluations complete in quick succession.


86-93: LGTM! Reactive pricing revision watcher.

The watcher correctly triggers canvas redraws only when showApiPricingBadge is enabled. Using flush: 'sync' ensures immediate response to pricing changes.


158-170: LGTM! Efficient badge caching strategy.

The creditsBadgeGetter pattern correctly caches the badge instance and only recreates it when the price label actually changes. This avoids unnecessary object allocations on each badge access while maintaining reactivity.

src/composables/node/useNodePricing.ts (2)

1-12: LGTM! Clear documentation of async behavior.

The header comment effectively documents the JSONata v2.x async nature and explains the implementation strategy (sync getter, async evaluation, reactive tick). This context is valuable for future maintainers.


474-479: LGTM! Clean public API surface.

The composable exposes a minimal, well-documented API: sync getter, config accessor, widget names helper, and a readonly reactive signal for UI updates.

pnpm-workspace.yaml (1)

67-67: LGTM!

The jsonata version ^2.1.0 is appropriately pinned to the latest release in the workspace catalog. The caret allows for minor and patch updates, which is the correct approach. The placement maintains alphabetical ordering.

?.value
)
// Reactive tick to force UI updates when async evaluations resolve.
// We purposely read pricingTick.value inside getNodeDisplayPrice to create a dependency.
Copy link
Contributor

Choose a reason for hiding this comment

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

👍🏻

Copy link
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: 7

Fix all issues with AI Agents 🤖
In @src/composables/node/useNodePricing.ts:
- Around line 151-160: The lookup loops use (x: any) which violates the no-any
rule; replace the explicit any annotations by using the correct domain types
(e.g., Widget and InputSlot or whatever concrete interfaces represent
node.widgets and node.inputs) or let TypeScript infer types by removing the
inline annotations; update the .find callbacks and local variables (widget,
slot, i) to use those types and keep the existing logic calling
normalizeWidgetValue and checking slot.link so behavior is unchanged (refer to
rule.depends_on.widgets, node.widgets, normalizeWidgetValue,
rule.depends_on.inputs, node.inputs, i, widget, slot to find the exact spots).
- Around line 166-170: The filter callback currently uses the unsafe any type
for inp; remove the ": any" and let TypeScript infer the type from node.inputs
(or explicitly cast node.inputs to the correct element type, e.g., Input[] or
NodeInput[] if that type exists) so the predicate becomes (inp) =>
inp?.name?.startsWith(prefix) && inp?.link != null; update the surrounding
typing of node or import/declare the proper input type if needed to ensure
node.inputs is strongly typed before computing connectedCount and assigning
g[groupName].
- Line 336: Repeated casts using (node.constructor as any)?.nodeData should be
replaced by a small typed helper to avoid any and centralize access; add a
getNodeData(node: LGraphNode): NodeData | undefined (with NodeData containing
name?, api_node?, price_badge?) that returns (node.constructor as { nodeData?:
NodeData })?.nodeData, then update all usages such as the nodeName assignment
(currently using (node.constructor as any)?.nodeData?.name ?? '') and other
occurrences (lines referencing api_node and price_badge) to call
getNodeData(node) and read properties from its result.
- Around line 255-263: The compileRule function currently uses an unsafe 'as
any' cast for the jsonata(rule.expr) result; import the jsonata Expression type
and change the compiled field typing so _compiled is typed as Expression | null
(update CompiledJsonataPricingRule accordingly) and cast jsonata(rule.expr) to
Expression instead of any, keeping the try/catch behavior in compileRule.

In @src/schemas/nodeDefSchema.ts:
- Around line 222-228: The default value for the depends_on property in
zPriceBadge omits input_groups, causing inconsistency with zPriceBadgeDepends;
update the default object in the zPriceBadge declaration (depends_on) to include
input_groups: [] alongside widgets: [] and inputs: [] so the default matches
zPriceBadgeDepends and avoids type narrowing issues.

Caution

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

⚠️ Outside diff range comments (1)
src/composables/node/useNodeBadge.ts (1)

148-156: Clarify the intent of discarding the computed return value.

The computedWithWidgetWatch(() => 0) call discards its return value, which is unusual. While the comment explains this registers widget listeners, consider adding a more explicit comment or using a dedicated function if the composable supports it.

🔎 Suggested clarification
-            // Ensure watchers are installed; ignore the returned value.
-            // (This call is what registers the widget listeners in most implementations.)
-            computedWithWidgetWatch(() => 0)
+            // Register widget change listeners to trigger canvas redraws.
+            // The returned computed value is intentionally unused; we only need
+            // the side effect of installing widget watchers.
+            void computedWithWidgetWatch(() => 0)
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14528aa and 15b124b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • package.json
  • pnpm-workspace.yaml
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • package.json
  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
🧠 Learnings (13)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/schemas/nodeDefSchema.ts
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Do not use `any` type or `as any` type assertions; fix the underlying type issue instead

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper TypeScript types throughout the codebase

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Use function declarations instead of function expressions when possible

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-13T05:34:22.209Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7415
File: browser_tests/tests/mobileBaseline.spec.ts:7-15
Timestamp: 2025-12-13T05:34:22.209Z
Learning: In Playwright tests in the Comfy-Org/ComfyUI_frontend repository, the `toPass()` assertion method implements incremental backoff during retries, so increasing the timeout value (e.g., to 5000ms) is sufficient for handling async operations without being overly aggressive.

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Write code that is expressive and self-documenting; avoid redundant comments and clean as you go

Applied to files:

  • src/composables/node/useNodePricing.ts
🧬 Code graph analysis (1)
src/composables/node/useNodePricing.ts (2)
src/schemas/nodeDefSchema.ts (1)
  • PriceBadge (230-230)
src/stores/nodeDefStore.ts (2)
  • useNodeDefStore (293-455)
  • nodeDef (82-108)
🔇 Additional comments (8)
package.json (1)

174-174: LGTM!

The jsonata dependency is appropriately added to runtime dependencies using the catalog specifier, consistent with the project's dependency management pattern.

src/schemas/nodeDefSchema.ts (2)

200-215: LGTM!

The zPriceBadgeDepends schema is well-documented with clear explanations for each field, especially the input_groups field which includes a helpful usage example for autogrow inputs.


259-265: LGTM!

The price_badge field is appropriately added to zComfyNodeDef as an optional field with clear documentation explaining its purpose for API node pricing.

src/composables/node/useNodePricing.ts (1)

408-436: LGTM with note on intentional reactive dependency.

The bare pricingTick.value read on line 411 is an intentional reactive dependency pattern. Consider using void pricingTick.value to make the intent clearer and prevent accidental removal.

The sync getter with async fallback pattern is well-designed for avoiding flicker while handling JSONata's async evaluation.

src/composables/node/useNodeBadge.ts (3)

76-93: LGTM!

Good optimization using requestAnimationFrame to batch canvas redraws. The redrawQueued flag prevents redundant RAF calls, and the watch with { flush: 'sync' } ensures pricing updates are immediately reflected.


158-170: Mutable closure state for badge caching.

The lastLabel and lastBadge variables create mutable closure state. This is acceptable here since it's a simple memoization pattern, but consider using a WeakMap for consistency with the caching pattern in useNodePricing.ts if this grows in complexity.


132-139: LGTM!

The hasDynamicPricing check correctly identifies nodes with widget or input dependencies, aligning with the JSONata-based pricing system.

pnpm-workspace.yaml (1)

67-67: The jsonata version ^2.1.0 is the current stable release on npm and is actively maintained. The catalog entry is appropriate.

@bigcat88 bigcat88 force-pushed the feat/backend-api-nodes-pricing-def branch from 55e67be to 7d3f77e Compare January 6, 2026 17:28
@bigcat88 bigcat88 force-pushed the feat/backend-api-nodes-pricing-def branch from 7d3f77e to 110224b Compare January 6, 2026 17:37
@github-actions
Copy link

github-actions bot commented Jan 6, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/07/2026, 03:39:24 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 01/07/2026, 03:44:32 PM UTC

📈 Summary

  • Total Tests: 513
  • Passed: 504 ✅
  • Failed: 0
  • Flaky: 1 ⚠️
  • Skipped: 8 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 494 / ❌ 0 / ⚠️ 0 / ⏭️ 8
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 7 / ❌ 0 / ⚠️ 1 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

Bundle Size Report

Summary

  • Raw size: 17.7 MB baseline 17.5 MB — 🔴 +195 kB
  • Gzip: 3.61 MB baseline 3.58 MB — 🔴 +34.2 kB
  • Brotli: 2.75 MB baseline 2.72 MB — 🔴 +27 kB
  • Bundles: 99 current • 99 baseline • 56 added / 56 removed

Category Glance
Vendor & Third-Party 🔴 +246 kB (9.44 MB) · Graph Workspace 🟢 -66.4 kB (941 kB) · App Entry Points 🔴 +15.4 kB (3.26 MB) · Other ⚪ 0 B (3.5 MB) · Panels & Settings ⚪ 0 B (300 kB) · UI Components ⚪ 0 B (198 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.26 MB (baseline 3.25 MB) • 🔴 +15.4 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BU7ysOZx.js (new) 3.07 MB 🔴 +3.07 MB 🔴 +645 kB 🔴 +489 kB
assets/index-DGprfyJZ.js (removed) 3.05 MB 🟢 -3.05 MB 🟢 -641 kB 🟢 -487 kB
assets/index-6gTUAQXK.js (removed) 194 kB 🟢 -194 kB 🟢 -42.3 kB 🟢 -35.2 kB
assets/index-CK3iAjtF.js (new) 194 kB 🔴 +194 kB 🔴 +42.3 kB 🔴 +35.1 kB
assets/index-CKmdBs_H.js (new) 345 B 🔴 +345 B 🔴 +244 B 🔴 +209 B
assets/index-D93Jxbat.js (removed) 345 B 🟢 -345 B 🟢 -244 B 🟢 -229 B

Status: 3 added / 3 removed

Graph Workspace — 941 kB (baseline 1.01 MB) • 🟢 -66.4 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-DWlH1xZZ.js (removed) 1.01 MB 🟢 -1.01 MB 🟢 -196 kB 🟢 -149 kB
assets/GraphView-Dwt3-tc3.js (new) 941 kB 🔴 +941 kB 🔴 +187 kB 🔴 +142 kB

Status: 1 added / 1 removed

Views & Navigation — 6.63 kB (baseline 6.63 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-CzkoD7QV.js (removed) 6.63 kB 🟢 -6.63 kB 🟢 -2.15 kB 🟢 -1.9 kB
assets/UserSelectView-Ddj3rzrP.js (new) 6.63 kB 🔴 +6.63 kB 🔴 +2.15 kB 🔴 +1.9 kB

Status: 1 added / 1 removed

Panels & Settings — 300 kB (baseline 300 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-BFCY1-MF.js (new) 22.7 kB 🔴 +22.7 kB 🔴 +5.26 kB 🔴 +4.6 kB
assets/LegacyCreditsPanel-D1DaWtRu.js (removed) 22.7 kB 🟢 -22.7 kB 🟢 -5.26 kB 🟢 -4.6 kB
assets/KeybindingPanel-BhhajOg8.js (removed) 14.8 kB 🟢 -14.8 kB 🟢 -3.57 kB 🟢 -3.12 kB
assets/KeybindingPanel-Bhx-P2AY.js (new) 14.8 kB 🔴 +14.8 kB 🔴 +3.57 kB 🔴 +3.13 kB
assets/ExtensionPanel-CalASrdR.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -2.62 kB 🟢 -2.29 kB
assets/ExtensionPanel-CSBG4aeM.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +2.62 kB 🔴 +2.3 kB
assets/AboutPanel-Brmga1Gk.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-zRYJQds4.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-BnDC4vUv.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +2.04 kB 🔴 +1.81 kB
assets/ServerConfigPanel-D3OGvt11.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -2.04 kB 🟢 -1.8 kB
assets/UserPanel-B0gy0g6u.js (removed) 6.88 kB 🟢 -6.88 kB 🟢 -1.79 kB 🟢 -1.57 kB
assets/UserPanel-CbnA7Xop.js (new) 6.88 kB 🔴 +6.88 kB 🔴 +1.79 kB 🔴 +1.56 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BIdKi-OT.js 26.2 kB 26.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Bu3OR-lX.js 24.6 kB 24.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-ByL6gy5c.js 25.4 kB 25.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CjlRFMdL.js 32.8 kB 32.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DkGwvylK.js 26.9 kB 26.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Dyd027Dx.js 24.7 kB 24.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-MzsBgiwB.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-wwBxqLH5.js 21.3 kB 21.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-xx2Yb6R2.js 23.8 kB 23.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 198 kB (baseline 198 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LazyImage.vue_vue_type_script_setup_true_lang-2t5k-tFK.js (new) 62.9 kB 🔴 +62.9 kB 🔴 +12.9 kB 🔴 +11.2 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-DzediK2H.js (removed) 62.9 kB 🟢 -62.9 kB 🟢 -12.9 kB 🟢 -11.2 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-DtK01mFI.js (new) 56 kB 🔴 +56 kB 🔴 +8.76 kB 🔴 +7.51 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-hxz97aPG.js (removed) 56 kB 🟢 -56 kB 🟢 -8.75 kB 🟢 -7.52 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-BKaHfPt9.js (new) 49 kB 🔴 +49 kB 🔴 +10.5 kB 🔴 +9.13 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-CjDPUhjH.js (removed) 49 kB 🟢 -49 kB 🟢 -10.5 kB 🟢 -9.13 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-B5jB9_TY.js (new) 10.9 kB 🔴 +10.9 kB 🔴 +2.89 kB 🔴 +2.55 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-CAM0Xbzt.js (removed) 10.9 kB 🟢 -10.9 kB 🟢 -2.89 kB 🟢 -2.54 kB
assets/ComfyQueueButton-gHvnBS7U.js (removed) 8.83 kB 🟢 -8.83 kB 🟢 -2.58 kB 🟢 -2.29 kB
assets/ComfyQueueButton-sKvnhUzQ.js (new) 8.83 kB 🔴 +8.83 kB 🔴 +2.58 kB 🔴 +2.29 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-BNRL-mIU.js (new) 3.72 kB 🔴 +3.72 kB 🔴 +1.46 kB 🔴 +1.32 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-D_8syzs6.js (removed) 3.72 kB 🟢 -3.72 kB 🟢 -1.45 kB 🟢 -1.31 kB
assets/WidgetButton-DxOQGrTs.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -996 B 🟢 -890 B
assets/WidgetButton-zJbFlZUI.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +997 B 🔴 +874 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-BxEr6H4z.js (new) 2.14 kB 🔴 +2.14 kB 🔴 +891 B 🔴 +770 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-n_gbp9QU.js (removed) 2.14 kB 🟢 -2.14 kB 🟢 -890 B 🟢 -772 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-D2sFSC5I.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -688 B 🟢 -596 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-DSgluvSM.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +687 B 🔴 +598 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-C75NRRw_.js (removed) 897 B 🟢 -897 B 🟢 -503 B 🟢 -444 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-CWr6q7lr.js (new) 897 B 🔴 +897 B 🔴 +503 B 🔴 +443 B

Status: 10 added / 10 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-BOj69KeA.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/keybindingService-CSF8Z4jv.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/serverConfigStore-D0YZbIqE.js (new) 2.83 kB 🔴 +2.83 kB 🔴 +908 B 🔴 +794 B
assets/serverConfigStore-vzHjAhYO.js (removed) 2.83 kB 🟢 -2.83 kB 🟢 -909 B 🟢 -797 B
assets/audioService-BUlfwHOh.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -960 B 🟢 -826 B
assets/audioService-DC4pLrTY.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +963 B 🔴 +826 B

Status: 3 added / 3 removed

Utilities & Hooks — 1.41 kB (baseline 1.41 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-BldjnUqG.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -650 B 🟢 -549 B
assets/audioUtils-CDhF-4ee.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +650 B 🔴 +544 B

Status: 1 added / 1 removed

Vendor & Third-Party — 9.44 MB (baseline 9.19 MB) • 🔴 +246 kB

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-BWfELC0f.js (new) 4.14 MB 🔴 +4.14 MB 🔴 +887 kB 🔴 +710 kB
assets/vendor-other-B0-E2a1W.js (removed) 3.9 MB 🟢 -3.9 MB 🟢 -848 kB 🟢 -678 kB
assets/vendor-three-C4jjJQHt.js (new) 2.08 MB 🔴 +2.08 MB 🔴 +430 kB 🔴 +308 kB
assets/vendor-three-U-rzyCAc.js (removed) 2.08 MB 🟢 -2.08 MB 🟢 -430 kB 🟢 -308 kB
assets/vendor-primevue-8yyuhoFO.js (removed) 1.95 MB 🟢 -1.95 MB 🟢 -333 kB 🟢 -201 kB
assets/vendor-primevue-DJcA7avg.js (new) 1.95 MB 🔴 +1.95 MB 🔴 +333 kB 🔴 +201 kB
assets/vendor-chart-CBtRS9ZM.js (new) 452 kB 🔴 +452 kB 🔴 +99 kB 🔴 +81 kB
assets/vendor-chart-DKN42gM5.js (removed) 452 kB 🟢 -452 kB 🟢 -99 kB 🟢 -81 kB
assets/vendor-tiptap-B8SQZ7yI.js (removed) 232 kB 🟢 -232 kB 🟢 -45.7 kB 🟢 -37.7 kB
assets/vendor-tiptap-BStTNUsY.js (new) 232 kB 🔴 +232 kB 🔴 +45.7 kB 🔴 +37.7 kB
assets/vendor-vue-B7S_YYz9.js (removed) 160 kB 🟢 -160 kB 🟢 -37 kB 🟢 -31.3 kB
assets/vendor-vue-ByAyIg3X.js (new) 160 kB 🔴 +160 kB 🔴 +37 kB 🔴 +31.3 kB
assets/vendor-xterm-BF8peZ5_.js 420 kB 420 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

Other — 3.5 MB (baseline 3.5 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SubscriptionRequiredDialogContent-ChyVPcHk.js (new) 29.3 kB 🔴 +29.3 kB 🔴 +6.51 kB 🔴 +5.65 kB
assets/SubscriptionRequiredDialogContent-wkB_1Irn.js (removed) 29.3 kB 🟢 -29.3 kB 🟢 -6.51 kB 🟢 -5.64 kB
assets/WidgetRecordAudio-C68S2K01.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.63 kB
assets/WidgetRecordAudio-DRoUqu8S.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.63 kB
assets/AudioPreviewPlayer-Bu5mpClO.js (new) 13.3 kB 🔴 +13.3 kB 🔴 +3.35 kB 🔴 +2.99 kB
assets/AudioPreviewPlayer-CapxEQTZ.js (removed) 13.3 kB 🟢 -13.3 kB 🟢 -3.35 kB 🟢 -2.99 kB
assets/ValueControlPopover-BDyplfm8.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.71 kB 🟢 -1.52 kB
assets/ValueControlPopover-tuW1UFkR.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.71 kB 🔴 +1.52 kB
assets/WidgetGalleria-B-wWW_84.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.3 kB
assets/WidgetGalleria-BOyo6NDw.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.3 kB
assets/WidgetColorPicker-atYqaovD.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.24 kB
assets/WidgetColorPicker-Ho2rvYkp.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetImageCompare-B4ZqWXBo.js (new) 3.18 kB 🔴 +3.18 kB 🔴 +1.1 kB 🔴 +982 B
assets/WidgetImageCompare-DlNxYBJ7.js (removed) 3.18 kB 🟢 -3.18 kB 🟢 -1.1 kB 🟢 -952 B
assets/WidgetTextarea-BlVwGRYb.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.22 kB 🔴 +1.08 kB
assets/WidgetTextarea-Bz_tHJSr.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.21 kB 🟢 -1.08 kB
assets/WidgetMarkdown-BCDV4dDB.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.13 kB
assets/WidgetMarkdown-BrGf9__h.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetAudioUI-Cs6HdyRj.js (removed) 2.89 kB 🟢 -2.89 kB 🟢 -1.17 kB 🟢 -1.06 kB
assets/WidgetAudioUI-D_OMDVkC.js (new) 2.89 kB 🔴 +2.89 kB 🔴 +1.17 kB 🔴 +1.06 kB
assets/MediaVideoTop-B297IpwP.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -1.02 kB 🟢 -870 B
assets/MediaVideoTop-CbCFUeZe.js (new) 2.65 kB 🔴 +2.65 kB 🔴 +1.01 kB 🔴 +869 B
assets/WidgetChart-DMoani6N.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +930 B 🔴 +816 B
assets/WidgetChart-Du6foKGb.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -931 B 🟢 -816 B
assets/WidgetInputText-D3s-4WaD.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +922 B 🔴 +859 B
assets/WidgetInputText-mDJ7O_a_.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -917 B 🟢 -851 B
assets/WidgetToggleSwitch-Chpz9mWf.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -835 B 🟢 -729 B
assets/WidgetToggleSwitch-DMhlLsH1.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +836 B 🔴 +734 B
assets/MediaImageTop-BaBlYZTy.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -840 B 🟢 -719 B
assets/MediaImageTop-DxmxFgc4.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +841 B 🔴 +714 B
assets/MediaImageBottom-BVGnuqz_.js (new) 1.55 kB 🔴 +1.55 kB 🔴 +737 B 🔴 +641 B
assets/MediaImageBottom-D6ifmlY0.js (removed) 1.55 kB 🟢 -1.55 kB 🟢 -736 B 🟢 -643 B
assets/MediaAudioBottom-BDxhgr-c.js (new) 1.51 kB 🔴 +1.51 kB 🔴 +734 B 🔴 +648 B
assets/MediaAudioBottom-D8KU7V13.js (removed) 1.51 kB 🟢 -1.51 kB 🟢 -735 B 🟢 -649 B
assets/Media3DBottom-BC1Y5hj9.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -732 B 🟢 -646 B
assets/Media3DBottom-CxXpyZGP.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +734 B 🔴 +648 B
assets/MediaVideoBottom-BUJRPJua.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -732 B 🟢 -646 B
assets/MediaVideoBottom-CmRLh_52.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +733 B 🔴 +648 B
assets/Media3DTop-chkhaQ5h.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -768 B 🟢 -653 B
assets/Media3DTop-Dd8IfJWv.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +769 B 🔴 +654 B
assets/MediaAudioTop-CR7u_N6X.js (new) 1.46 kB 🔴 +1.46 kB 🔴 +738 B 🔴 +617 B
assets/MediaAudioTop-D6xQ7BTZ.js (removed) 1.46 kB 🟢 -1.46 kB 🟢 -738 B 🟢 -620 B
assets/WidgetSelect-C3IsrvFV.js (new) 733 B 🔴 +733 B 🔴 +361 B 🔴 +322 B
assets/WidgetSelect-DNa9v_Pm.js (removed) 733 B 🟢 -733 B 🟢 -360 B 🟢 -329 B
assets/WidgetInputNumber-DI-9uU7z.js (removed) 673 B 🟢 -673 B 🟢 -349 B 🟢 -288 B
assets/WidgetInputNumber-oMLzp9OK.js (new) 673 B 🔴 +673 B 🔴 +348 B 🔴 +287 B
assets/Load3D-4Zdvu30y.js (new) 424 B 🔴 +424 B 🔴 +269 B 🔴 +226 B
assets/Load3D-BqCmMoCU.js (removed) 424 B 🟢 -424 B 🟢 -269 B 🟢 -223 B
assets/WidgetLegacy-ClhGlW8m.js (new) 364 B 🔴 +364 B 🔴 +237 B 🔴 +228 B
assets/WidgetLegacy-CXoK3Qi8.js (removed) 364 B 🟢 -364 B 🟢 -239 B 🟢 -195 B
assets/commands-bTEY9Mp6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CcfGaui5.js 14.4 kB 14.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CisfgZf5.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CkU12Foh.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CoH2DJa6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-COSt-Bjx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DalfIW5f.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DfTl0eCm.js 13.5 kB 13.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwSJL865.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bdc58rJq.js 97.1 kB 97.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-C9ZJBRdI.js 81.5 kB 81.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CAL83XT3.js 84.6 kB 84.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CHLLfvpG.js 82.4 kB 82.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DDqR5EuX.js 71.3 kB 71.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DLHyaEcz.js 92.1 kB 92.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-JzWMbEh0.js 91.2 kB 91.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-O7KfJeMO.js 79.9 kB 79.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-OzGsrlqJ.js 112 kB 112 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-aW9En70v.js 260 kB 260 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BDbge6_f.js 279 kB 279 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BIckSVgU.js 273 kB 273 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BiYpVi7D.js 263 kB 263 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CCEXtYfM.js 243 kB 243 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CvmVDWYd.js 323 kB 323 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D_wreoPJ.js 267 kB 267 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Dz-0ZIBN.js 297 kB 297 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-VZsNmhG7.js 264 kB 264 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2Worker-GDlTeC1j.js 4.69 kB 4.69 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 25 added / 25 removed

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Prettier formatting

@bigcat88 bigcat88 force-pushed the feat/backend-api-nodes-pricing-def branch from 9e81200 to 5ab4187 Compare January 6, 2026 20:02
@bigcat88 bigcat88 force-pushed the feat/backend-api-nodes-pricing-def branch from 5ab4187 to ff49062 Compare January 6, 2026 20:19
@DrJKL DrJKL added the claude-review Add to trigger a PR code review from Claude Code label Jan 7, 2026
engine: z.literal('jsonata').optional().default('jsonata'),
depends_on: zPriceBadgeDepends
.optional()
.default({ widgets: [], inputs: [] }),
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe?

Suggested change
.default({ widgets: [], inputs: [] }),
.default({ widgets: [], inputs: [], input_groups: [] }),

Comment on lines +29 to +30
widgets: Array<{ name: string; value: unknown }> = [],
inputs: Array<{ name: string; connected?: boolean }> = []
Copy link
Contributor

Choose a reason for hiding this comment

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

Could these use the types defined in nodeDefSchema?

"firebase": "catalog:",
"fuse.js": "^7.0.0",
"glob": "^11.0.3",
"jsonata": "catalog:",
Copy link

Choose a reason for hiding this comment

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

[architecture] high Priority

Issue: New jsonata dependency addition without clear evaluation of alternatives
Context: Adding jsonata as a new runtime dependency for pricing calculations - should evaluate if existing libraries like lodash template functions or custom expression parser could handle these use cases
Suggestion: Document why JSONata was chosen over alternatives, consider bundle size impact, and evaluate if simpler expression evaluation patterns would suffice

let lastBadge = priceBadge.getCreditsBadge(lastLabel)

const creditsBadgeGetter: () => LGraphBadge = () => {
const label = nodePricing.getNodeDisplayPrice(node)
Copy link

Choose a reason for hiding this comment

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

[performance] medium Priority

Issue: Badge creation pattern may cause unnecessary re-evaluations
Context: The creditsBadgeGetter function is called on every render and manually caches lastLabel/lastBadge, but this could lead to inconsistent state if pricing updates occur between renders
Suggestion: Use a proper Vue computed property that depends on the pricing revision signal, or implement the caching within the pricing service itself

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Comprehensive PR Review

This review is generated by Claude. It may not always be accurate, as with human reviewers. If you believe that any of the comments are invalid or incorrect, please state why for each. For others, please implement the changes in one way or another.

Review Summary

PR: Move price badges to python nodes (#7816)
Impact: 829 additions, 4427 deletions across 8 files

Issue Distribution

  • Critical: 1
  • High: 2
  • Medium: 3
  • Low: 1

Category Breakdown

  • Architecture: 1 issue
  • Security: 1 issue
  • Performance: 3 issues
  • Code Quality: 2 issues

Key Findings

Architecture & Design

This PR represents a significant architectural shift from frontend-hardcoded pricing logic to backend-driven JSONata expressions. The change enables more flexible pricing configurations but introduces complexity in async evaluation patterns and expression compilation. The addition of jsonata as a dependency should be evaluated against simpler alternatives before being merged.

Security Considerations

Critical Issue: JSONata expression compilation from user-controlled data poses a security risk. The current implementation compiles arbitrary expressions without validation, potentially allowing code injection if malicious node definitions are loaded. This needs immediate attention before deployment.

Performance Impact

The new async pricing evaluation pattern with WeakMap-based caching introduces potential performance concerns:

  1. Synchronous getters triggering async operations during render cycles
  2. Complex state management across multiple WeakMaps
  3. Manual badge caching that may lead to inconsistent state

Bundle size impact from the new jsonata dependency should also be evaluated.

Integration Points

The changes maintain backward compatibility while introducing new JSONata-based pricing for API nodes. The schema updates properly extend the existing node definition structure. The integration with Vue's reactivity system through the pricingTick ref is well-designed.

Positive Observations

  1. Comprehensive test coverage: The test file shows thorough coverage of the new JSONata evaluation patterns
  2. Strong type safety: Excellent TypeScript typing throughout the new pricing system
  3. Error handling: Non-fatal error handling ensures UI stability even with bad expressions
  4. Clean separation: Good separation between compilation, caching, and evaluation logic
  5. Schema validation: Proper Zod schema validation for the new price badge structures

References

Next Steps

  1. Address critical security issue before merge - implement expression validation
  2. Evaluate bundle size impact of jsonata dependency
  3. Consider performance optimizations for the async evaluation pattern
  4. Add integration tests for the pricing badge rendering pipeline
  5. Document JSONata expression patterns for node developers

This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.

@github-actions github-actions bot removed the claude-review Add to trigger a PR code review from Claude Code label Jan 7, 2026
Comment on lines 95 to 104
type JsonataPricingRule = {
engine: 'jsonata'
depends_on: {
widgets: WidgetDependency[]
inputs: string[]
input_groups: string[]
}
expr: string
result_defaults?: CreditFormatOptions
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this also use the type from the schema?

if (duration === '5') {
return generateAudio ? formatCreditsLabel(0.7) : formatCreditsLabel(0.35)
}
const r = result as PricingResult
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: This would be a good place to have a real type guard.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you type the parameter and enforce the type earlier on?

@DrJKL
Copy link
Contributor

DrJKL commented Jan 7, 2026

@coderabbitai review full

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

@DrJKL I'll perform a full review of all the changes in this PR.

✅ Actions performed

Full review triggered.

Copy link
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

Caution

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

⚠️ Outside diff range comments (1)
src/composables/node/useNodeBadge.ts (1)

148-156: Clarify the intent of discarding the computed return value.

The computedWithWidgetWatch(() => 0) call is made solely to install widget listeners, with the return value intentionally discarded. While the comments explain this, consider extracting this pattern into a more explicit helper like useWidgetWatchersOnly(node, { widgetNames }) to make the intent clearer.

🤖 Fix all issues with AI agents
In @src/composables/node/useNodePricing.ts:
- Line 367: Refactor the repeated unsafe cast by adding a typed helper (e.g.,
define a NodeData type with name?, api_node?, price_badge? and implement
getNodeData(node: LGraphNode): NodeData | undefined that returns
(node.constructor as { nodeData?: NodeData })?.nodeData) and replace all
occurrences of (node.constructor as any)?.nodeData (used when computing
nodeName, and at the other two sites around lines where api_node/price_badge are
accessed) to call getNodeData(node) and read properties from that typed result.
- Around line 439-442: The bare read of pricingTick.value inside
getNodeDisplayPrice is intended to create a reactive dependency but appears as
dead code; make that intent explicit by using a void read (e.g., `void
pricingTick.value`) so the reactive dependency is clear and linter readers
understand it’s deliberate—update the getNodeDisplayPrice function to replace
the bare pricingTick.value read with an explicit void usage.

In @src/schemas/nodeDefSchema.ts:
- Around line 236-238: The default value for depends_on is missing input_groups;
update the depends_on default object used with zPriceBadgeDepends to include
input_groups: [] so it matches zPriceBadgeDepends' shape (i.e., change the
default from { widgets: [], inputs: [] } to include input_groups: []). Ensure
the modification is applied where depends_on is defined so the schema default
aligns with zPriceBadgeDepends.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14d0ec7 and ff49062.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • package.json
  • pnpm-workspace.yaml
  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
  • src/stores/nodeDefStore.ts
🧰 Additional context used
📓 Path-based instructions (14)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/node/useNodeBadge.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • package.json
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/nodeDefStore.ts
**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia stores using the pattern *Store.ts

Files:

  • src/stores/nodeDefStore.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Use unit/component tests in tests-ui/ or src/**/*.test.ts with Vitest framework
For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files
Do not write change detector tests or tests dependent on non-behavioral features like utility classes or styles
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/node/useNodePricing.test.ts
🧠 Learnings (17)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/node/useNodeBadge.ts
  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
  • src/composables/node/useNodePricing.ts
  • src/schemas/nodeDefSchema.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/stores/nodeDefStore.ts
  • src/composables/node/useNodePricing.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/node/useNodePricing.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/node/useNodePricing.test.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Do not use `any` type or `as any` type assertions; fix the underlying type issue instead

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper TypeScript types throughout the codebase

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-13T05:34:22.209Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7415
File: browser_tests/tests/mobileBaseline.spec.ts:7-15
Timestamp: 2025-12-13T05:34:22.209Z
Learning: In Playwright tests in the Comfy-Org/ComfyUI_frontend repository, the `toPass()` assertion method implements incremental backoff during retries, so increasing the timeout value (e.g., to 5000ms) is sufficient for handling async operations without being overly aggressive.

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Write code that is expressive and self-documenting; avoid redundant comments and clean as you go

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2026-01-06T19:20:52.000Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:52.000Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Use function declarations instead of function expressions when possible

Applied to files:

  • src/composables/node/useNodePricing.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code

Applied to files:

  • src/composables/node/useNodePricing.ts
🧬 Code graph analysis (2)
src/stores/nodeDefStore.ts (1)
src/schemas/nodeDefSchema.ts (1)
  • PriceBadge (242-242)
src/composables/node/useNodePricing.test.ts (4)
src/base/credits/comfyCredits.ts (1)
  • formatCreditsFromUsd (84-93)
src/schemas/nodeDefSchema.ts (1)
  • PriceBadge (242-242)
src/lib/litegraph/src/LGraphNode.ts (1)
  • inputs (3305-3309)
src/composables/node/useNodePricing.ts (1)
  • useNodePricing (432-511)
🔇 Additional comments (17)
pnpm-workspace.yaml (1)

66-66: LGTM!

The jsonata version ^2.1.0 is correctly added to the workspace catalog, enabling consistent version resolution across the monorepo.

src/schemas/nodeDefSchema.ts (2)

200-209: LGTM!

The zWidgetDependency schema correctly captures widget dependencies with both name and type, enabling proper type-aware normalization in the pricing evaluation.


271-277: LGTM!

The price_badge field is correctly integrated as an optional field in zComfyNodeDef, with clear documentation explaining its purpose for API node pricing.

src/stores/nodeDefStore.ts (3)

17-19: LGTM!

The PriceBadge type import is correctly separated from the non-type imports, following the repository's lint rules.


70-75: LGTM!

The price_badge field is properly added as an optional readonly property with clear documentation explaining its purpose for JSONata-based pricing calculations.


144-144: LGTM!

The price_badge initialization correctly assigns from the input object, consistent with other optional fields in the constructor.

src/composables/node/useNodeBadge.ts (2)

76-93: LGTM - Good batching pattern for canvas redraws.

The requestAnimationFrame batching prevents excessive redraws when multiple pricing updates occur in quick succession. The flush: 'sync' on the watcher ensures immediate response to pricing revision changes.


158-170: Manual badge caching may have subtle timing issues.

The creditsBadgeGetter pattern caches lastLabel and lastBadge, updating only when the label changes. This works but creates a closure that captures mutable state.

Consider whether this could be simplified by having priceBadge.getCreditsBadge implement its own memoization, or by using a computed that directly depends on the pricing revision signal.

A previous review flagged potential inconsistencies with this caching pattern. The current implementation should work correctly since getNodeDisplayPrice handles the async coordination, but the manual caching adds complexity.

Likely an incorrect or invalid review comment.

src/composables/node/useNodePricing.test.ts (3)

26-57: LGTM - Well-structured test helper.

The createMockNodeWithPriceBadge helper properly constructs mock nodes with price_badge for testing the JSONata-based pricing system. Using the PriceBadge type from the schema ensures type consistency.


59-69: LGTM - Clean helper for constructing PriceBadge objects.

The priceBadge helper provides sensible defaults while allowing customization of widgets, inputs, and input groups.


360-376: LGTM - Good edge case coverage.

Tests for non-API nodes and nodes without price_badge correctly verify that empty strings are returned, ensuring graceful degradation.

src/composables/node/useNodePricing.ts (6)

1-21: LGTM - Clear module documentation.

The header comment clearly explains the JSONata 2.x async behavior and the sync getter / async evaluation / reactive tick pattern. The imports are well-organized with type imports separated.


95-104: LGTM - Type definitions use schema types.

The JsonataPricingRule type now correctly uses WidgetDependency[] for widgets, addressing the earlier review feedback about using types from the schema.


140-175: LGTM - Type-aware widget normalization.

The normalizeWidgetValue function correctly handles different widget types (INT, FLOAT, BOOLEAN, COMBO, STRING) with appropriate type conversions. The lowercase normalization for strings enables case-insensitive matching in JSONata expressions.


177-205: LGTM - Context building with proper types.

The buildJsonataContext function correctly uses IBaseWidget and INodeInputSlot types from litegraph, addressing the earlier review concern about any types in widget/input lookups.


286-293: LGTM - Expression type imported from jsonata.

The compileRule function now correctly uses the Expression type from jsonata, eliminating the need for as any cast on the compiled expression.


354-406: Async evaluation pipeline is well-designed.

The scheduleEvaluation function correctly handles:

  • Deduplication via signature matching
  • Stale result rejection via desiredSig check
  • Non-fatal error handling with cache population
  • Reactive updates via pricingTick increment

The WeakMap usage prevents memory leaks when nodes are removed.

const lower = String(v).toLowerCase()
if (lower === 'true') return true
if (lower === 'false') return false
const nodeName = (node.constructor as any)?.nodeData?.name ?? ''
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 7, 2026

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Extract helper to reduce repeated as any casts for nodeData access.

The pattern (node.constructor as any)?.nodeData is repeated at lines 367, 414, and 444-446. Consider extracting a typed helper function to isolate this cast.

This was flagged in a previous review. Suggested helper:

type NodeData = {
  name?: string
  api_node?: boolean
  price_badge?: PriceBadge
}

function getNodeData(node: LGraphNode): NodeData | undefined {
  return (node.constructor as { nodeData?: NodeData })?.nodeData
}
🤖 Prompt for AI Agents
In @src/composables/node/useNodePricing.ts at line 367, Refactor the repeated
unsafe cast by adding a typed helper (e.g., define a NodeData type with name?,
api_node?, price_badge? and implement getNodeData(node: LGraphNode): NodeData |
undefined that returns (node.constructor as { nodeData?: NodeData })?.nodeData)
and replace all occurrences of (node.constructor as any)?.nodeData (used when
computing nodeName, and at the other two sites around lines where
api_node/price_badge are accessed) to call getNodeData(node) and read properties
from that typed result.

Copy link
Contributor

Choose a reason for hiding this comment

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

@coderabbitai Are there other places in the codebase that could benefit from such a utility?

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for patterns of accessing nodeData through constructor casts
echo "=== Pattern 1: (constructor as any)?.nodeData ==="
rg -n --type=ts -C2 '\(.*\.constructor as any\)\??\.nodeData' 

echo ""
echo "=== Pattern 2: constructor as any (broader search) ==="
rg -n --type=ts -l 'constructor as any'

echo ""
echo "=== Pattern 3: Direct .nodeData access (to see context) ==="
rg -n --type=ts -C1 '\.nodeData\b' | head -100

Length of output: 7736


🏁 Script executed:

#!/bin/bash
# Check the other files that use "constructor as any"
echo "=== workflowStore.ts usage ==="
rg -n --type=ts -C3 'constructor as any' src/platform/workflow/management/stores/workflowStore.ts

echo ""
echo "=== LGraphNode.test.ts usage ==="
rg -n --type=ts -C3 'constructor as any' src/lib/litegraph/src/LGraphNode.test.ts

echo ""
echo "=== litegraphService.ts with type errors/casts ==="
rg -n --type=ts -B2 -A2 'ts-expect-error|nodeData as ComfyNodeDefImpl' src/services/litegraphService.ts | head -30

Length of output: 2845


@DrJKL Yes, there are several other places in the codebase that would benefit from a typed getNodeData helper:

Files that would benefit:

  1. src/services/litegraphService.ts (line 205)

    • Uses node.constructor.nodeData as ComfyNodeDefImpl with a @ts-expect-error comment
    • Also has multiple direct .nodeData accesses (lines 87, 302-303, 361, 379, 403-404, 409, 469, 492)
  2. src/stores/nodeDefStore.ts (line 360)

    • Uses node.constructor?.nodeData?.name directly
  3. src/utils/nodeFilterUtil.ts (line 11)

    • Uses node.constructor.nodeData?.output_node directly
  4. src/utils/executableGroupNodeDto.ts (line 14)

    • Uses node.constructor?.nodeData?.[GROUP] directly
  5. src/extensions/core/nodeTemplates.ts (line 371)

    • Uses node?.constructor.nodeData directly
  6. src/extensions/core/groupNode.ts (multiple lines)

    • Has its own nodeData property management

Summary:
The typed helper would improve type safety in at least 6 files across the codebase. The most impactful would be litegraphService.ts, which has both an explicit cast with @ts-expect-error and numerous direct accesses to .nodeData.

I recommend creating this helper as a shared utility (e.g., in src/utils/nodeDataUtils.ts) so all these files can benefit from consistent, type-safe access to node metadata.


🧬 Code Graph Analysis Results

<src/schemas/nodeDefSchema.ts> (lines 242-242)

export type PriceBadge = z.infer<typeof zPriceBadge>

<src/base/credits/comfyCredits.ts> (lines 84-93)

export const formatCreditsFromUsd = ({
  usd,
  locale,
  numberOptions
}: FormatFromUsdOptions): string =>
  formatCredits({
    value: usdToCredits(usd),
    locale,
    numberOptions
  })

@bigcat88 bigcat88 force-pushed the feat/backend-api-nodes-pricing-def branch from 9698efc to d78cd9e Compare January 7, 2026 15:00
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.

4 participants