From 8da221b5db0befc80cecb8821f220999d7bfef8b Mon Sep 17 00:00:00 2001 From: Connor Byrne Date: Tue, 12 May 2026 18:20:11 -0700 Subject: [PATCH] =?UTF-8?q?refactor(ext-api):=20rename=20defineNodeExtensi?= =?UTF-8?q?on=20=E2=86=92=20defineNode,=20defineWidgetExtension=20?= =?UTF-8?q?=E2=86=92=20defineWidget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorter function names improve ergonomics while maintaining clarity: - defineNode() - register node-scoped extensions - defineWidget() - register widget type extensions Old names kept as deprecated aliases for backwards compatibility. Will be removed in v1.0. Updates all docs, examples, tests, and internal references. Addresses review discussion item #4 from design-review-12142.md Co-Authored-By: Claude Opus 4.5 --- src/extension-api/index.ts | 9 +++++--- src/extension-api/lifecycle.ts | 18 +++++++++++---- src/extension-api/node.ts | 4 ++-- src/extension-api/types.ts | 16 +++++++------- src/extension-api/widget.ts | 4 ++-- src/scripts/app.ts | 2 +- src/services/__tests__/scope-registry.test.ts | 22 +++++++++---------- src/services/extension-api-service.ts | 10 +++++++-- src/services/extensionService.ts | 2 +- src/types/extensionV2.ts | 7 +++++- 10 files changed, 59 insertions(+), 35 deletions(-) diff --git a/src/extension-api/index.ts b/src/extension-api/index.ts index 670f82dfeb..4a0d2dc52e 100644 --- a/src/extension-api/index.ts +++ b/src/extension-api/index.ts @@ -7,14 +7,14 @@ * Import directly — no dependency on `window.app` at module evaluation time: * * ```ts - * import { defineNodeExtension, defineExtension } from '@comfyorg/extension-api' + * import { defineNode, defineExtension } from '@comfyorg/extension-api' * ``` * * ## API surface overview * * | Export | Purpose | * |--------|---------| - * | `defineNodeExtension` | Register a node-scoped extension (the primary entry point) | + * | `defineNode` | Register a node-scoped extension (the primary entry point) | * | `defineExtension` | Register an app-scoped extension (init, setup, shell UI) | * | `onNodeMounted`, `onNodeRemoved` | Implicit-context lifecycle hooks (call inside nodeCreated) | * | `NodeHandle` | Controlled access to node state and events | @@ -57,10 +57,13 @@ export type { // ── Registration function implementations ──────────────────────────────────── // Runtime implementations live in the service; the types above are the // public contract. The barrel re-exports the concrete fns from the service -// so `import { defineNodeExtension } from '@comfyorg/extension-api'` works +// so `import { defineNode } from '@comfyorg/extension-api'` works // at both typecheck and runtime. export { defineExtension, + defineNode, + defineWidget, + // Deprecated aliases (remove in v1.0) defineNodeExtension, defineWidgetExtension, startExtensionSystem diff --git a/src/extension-api/lifecycle.ts b/src/extension-api/lifecycle.ts index 7b369be46b..c0d54125b6 100644 --- a/src/extension-api/lifecycle.ts +++ b/src/extension-api/lifecycle.ts @@ -1,5 +1,5 @@ /** - * Extension lifecycle — `defineExtension`, `defineNodeExtension`, and + * Extension lifecycle — `defineExtension`, `defineNode`, and * the implicit-context lifecycle hooks (`onNodeMounted`, `onNodeRemoved`). * * Key behaviors: @@ -58,9 +58,9 @@ import type { * @publicAPI * @example * ```ts - * import { defineNodeExtension } from '@comfyorg/extension-api' + * import { defineNode } from '@comfyorg/extension-api' * - * export default defineNodeExtension({ + * export default defineNode({ * name: 'Comfy.PreviewAny', * nodeTypes: ['PreviewAny'], * @@ -75,6 +75,11 @@ import type { * }) * ``` */ +export declare function defineNode( + options: NodeExtensionOptions +): NodeExtensionOptions + +/** @deprecated Use `defineNode` instead. Will be removed in v1.0. */ export declare function defineNodeExtension( options: NodeExtensionOptions ): NodeExtensionOptions @@ -82,7 +87,7 @@ export declare function defineNodeExtension( /** * Register an extension for app-wide lifecycle and shell UI contributions. * - * Use `defineNodeExtension` for node/widget interactions. Use this for + * Use `defineNode` for node/widget interactions. Use this for * `init`, `setup`, sidebar tabs, commands, and other app-level concerns. * * @publicAPI @@ -109,6 +114,11 @@ export declare function defineExtension( * @stability experimental * @publicAPI */ +export declare function defineWidget( + options: WidgetExtensionOptions +): WidgetExtensionOptions + +/** @deprecated Use `defineWidget` instead. Will be removed in v1.0. */ export declare function defineWidgetExtension( options: WidgetExtensionOptions ): WidgetExtensionOptions diff --git a/src/extension-api/node.ts b/src/extension-api/node.ts index f2d8514dc1..ce1bdd0b77 100644 --- a/src/extension-api/node.ts +++ b/src/extension-api/node.ts @@ -192,9 +192,9 @@ export interface NodeBeforeSerializeEvent { * * @example * ```ts - * import { defineNodeExtension } from '@comfyorg/extension-api' + * import { defineNode } from '@comfyorg/extension-api' * - * export default defineNodeExtension({ + * export default defineNode({ * name: 'my-size-enforcer', * nodeTypes: ['MyCustomNode'], * diff --git a/src/extension-api/types.ts b/src/extension-api/types.ts index cec186e7b1..52b82bfbb6 100644 --- a/src/extension-api/types.ts +++ b/src/extension-api/types.ts @@ -1,6 +1,6 @@ /** - * Extension option interfaces — the type contracts for `defineNodeExtension`, - * `defineExtension`, and `defineWidgetExtension`. + * Extension option interfaces — the type contracts for `defineNode`, + * `defineExtension`, and `defineWidget`. * * Lives in its own module so the runtime service (`@/services/extension-api-service`) * and the public lifecycle barrel (`@/extension-api/lifecycle`) can both depend on @@ -15,14 +15,14 @@ import type { NodeHandle } from './node' import type { WidgetHandle } from './widget' /** - * Options for `defineNodeExtension`. Describes an extension that reacts to + * Options for `defineNode`. Describes an extension that reacts to * node lifecycle events. * * @example * ```ts - * import { defineNodeExtension } from '@comfyorg/extension-api' + * import { defineNode } from '@comfyorg/extension-api' * - * export default defineNodeExtension({ + * export default defineNode({ * name: 'my-org.my-extension', * nodeTypes: ['KSampler'], * @@ -118,15 +118,15 @@ export interface ExtensionOptions { } /** - * Options for `defineWidgetExtension`. Describes an extension that provides a + * Options for `defineWidget`. Describes an extension that provides a * custom widget type with its own DOM rendering. * * @stability experimental * @example * ```ts - * import { defineWidgetExtension } from '@comfyorg/extension-api' + * import { defineWidget } from '@comfyorg/extension-api' * - * export default defineWidgetExtension({ + * export default defineWidget({ * name: 'my-org.color-picker', * type: 'COLOR_PICKER', * diff --git a/src/extension-api/widget.ts b/src/extension-api/widget.ts index fcd1a46e01..36b56117ea 100644 --- a/src/extension-api/widget.ts +++ b/src/extension-api/widget.ts @@ -232,9 +232,9 @@ export interface WidgetBeforeQueueEvent { * @typeParam T - The type of `getValue()` / `setValue()`. Defaults to `WidgetValue`. * @example * ```ts - * import { defineNodeExtension } from '@comfyorg/extension-api' + * import { defineNode } from '@comfyorg/extension-api' * - * export default defineNodeExtension({ + * export default defineNode({ * name: 'my-extension', * nodeCreated(node) { * const steps = node.getWidget('steps') diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 6af9d88e3a..6a7ca81a52 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -860,7 +860,7 @@ export class ComfyApp { void useSubgraphStore().fetchSubgraphs() await useExtensionService().loadExtensions() // Start the v2 node-extension reactive mount watcher (I-SR.3 / MIG1.E5). - // Must run after loadExtensions() so all defineNodeExtension() calls have + // Must run after loadExtensions() so all defineNode() calls have // pushed into nodeExtensions[] before the first watcher tick. startExtensionSystem() diff --git a/src/services/__tests__/scope-registry.test.ts b/src/services/__tests__/scope-registry.test.ts index 4f087afdf3..9726d816b2 100644 --- a/src/services/__tests__/scope-registry.test.ts +++ b/src/services/__tests__/scope-registry.test.ts @@ -49,7 +49,7 @@ vi.mock('@/extension-api/lifecycle', () => ({})) // ── Import service (after mocks are in place) ──────────────────────────────── import { _clearExtensionsForTesting, - defineNodeExtension, + defineNode, getCurrentScope, getScopeRegistry, mountExtensionsForNode, @@ -93,7 +93,7 @@ describe('scope-registry — D12 copy/paste reset semantics', () => { // The extension stores a ref so we can mutate it after mount. const counters = new Map>() - defineNodeExtension({ + defineNode({ name: 'z-counter', nodeCreated(handle) { const count = ref(0) @@ -141,7 +141,7 @@ describe('scope-registry — D12 copy/paste reset semantics', () => { let setupCallCount = 0 - defineNodeExtension({ + defineNode({ name: 'a-setup-counter', nodeCreated() { setupCallCount++ @@ -175,7 +175,7 @@ describe('scope-registry — D12 copy/paste reset semantics', () => { const SOURCE_ID = makeNodeId(3) const CLONE_ID = makeNodeId(4) - defineNodeExtension({ + defineNode({ name: 'b-flag', nodeCreated() { return { flag: ref(true) } @@ -220,7 +220,7 @@ describe('currentExtension global slot (D10a) + lifecycle hooks (I-SR.2.B3 / I-S const NODE_ID = makeNodeId(10) let scopeDuringSetup: ReturnType = null - defineNodeExtension({ + defineNode({ name: 'c-slot-check', nodeCreated() { scopeDuringSetup = getCurrentScope() @@ -238,7 +238,7 @@ describe('currentExtension global slot (D10a) + lifecycle hooks (I-SR.2.B3 / I-S it('getCurrentScope() is restored to null after setup completes', () => { const NODE_ID = makeNodeId(11) - defineNodeExtension({ + defineNode({ name: 'd-slot-restore', nodeCreated() { /* no-op */ @@ -255,7 +255,7 @@ describe('currentExtension global slot (D10a) + lifecycle hooks (I-SR.2.B3 / I-S const NODE_ID = makeNodeId(12) const removedCb = vi.fn() - defineNodeExtension({ + defineNode({ name: 'e-on-removed', nodeCreated() { onNodeRemoved(removedCb) @@ -299,7 +299,7 @@ describe('I-SR.6 — scope lifecycle invariants', () => { const NODE_ID = makeNodeId(30) let setupCount = 0 - defineNodeExtension({ + defineNode({ name: 'h-once', nodeCreated() { setupCount++ @@ -325,7 +325,7 @@ describe('I-SR.6 — scope lifecycle invariants', () => { const removedCb = vi.fn() let setupCount = 0 - defineNodeExtension({ + defineNode({ name: 'i-promotion', nodeCreated() { setupCount++ @@ -377,7 +377,7 @@ describe('LoadedFromWorkflow tag routes to correct hook (I-SR.3)', () => { const created = vi.fn() const loaded = vi.fn() - defineNodeExtension({ + defineNode({ name: 'f-routing', nodeCreated: created, loadedGraphNode: loaded @@ -401,7 +401,7 @@ describe('LoadedFromWorkflow tag routes to correct hook (I-SR.3)', () => { const created = vi.fn() const loaded = vi.fn() - defineNodeExtension({ + defineNode({ name: 'g-routing', nodeCreated: created, loadedGraphNode: loaded diff --git a/src/services/extension-api-service.ts b/src/services/extension-api-service.ts index bcc5b60efe..1eb4296a99 100644 --- a/src/services/extension-api-service.ts +++ b/src/services/extension-api-service.ts @@ -607,14 +607,20 @@ export function defineExtension(options: ExtensionOptions): void { appExtensions.push(options) } -export function defineNodeExtension(options: NodeExtensionOptions): void { +export function defineNode(options: NodeExtensionOptions): void { nodeExtensions.push(options) } -export function defineWidgetExtension(options: WidgetExtensionOptions): void { +export function defineWidget(options: WidgetExtensionOptions): void { widgetExtensions.push(options) } +/** @deprecated Use `defineNode` instead. Will be removed in v1.0. */ +export const defineNodeExtension = defineNode + +/** @deprecated Use `defineWidget` instead. Will be removed in v1.0. */ +export const defineWidgetExtension = defineWidget + /** @internal Test-only: clear all registered extensions and reset state. */ export function _clearExtensionsForTesting(): void { nodeExtensions.length = 0 diff --git a/src/services/extensionService.ts b/src/services/extensionService.ts index 897319f4a4..a3ec3e7d4a 100644 --- a/src/services/extensionService.ts +++ b/src/services/extensionService.ts @@ -220,7 +220,7 @@ export const useExtensionService = () => { _warnedBeforeRegisterNodeDef.add(ext.name) console.warn( `[ComfyUI] Extension "${ext.name}" uses deprecated hook "beforeRegisterNodeDef". ` + - 'Use defineNodeExtension({ nodeCreated(handle) { ... } }) with a nodeTypes filter instead. ' + + 'Use defineNode({ nodeCreated(handle) { ... } }) with a nodeTypes filter instead. ' + 'See https://docs.comfy.org/extensions/api for the v2 API.' ) } diff --git a/src/types/extensionV2.ts b/src/types/extensionV2.ts index 4f8c01ff0c..6a2521e503 100644 --- a/src/types/extensionV2.ts +++ b/src/types/extensionV2.ts @@ -21,4 +21,9 @@ export type { export type { NodeExtensionOptions, ExtensionOptions } from '@/extension-api' -export { defineNodeExtension, defineExtension } from '@/extension-api' +export { + defineNode, + defineExtension, + // Deprecated aliases + defineNodeExtension +} from '@/extension-api'