fix(ext-api): add knip entry + @publicAPI tags for v2 surface

knip flagged the new src/extension-api/* files and exports as unused
because nothing internal consumes them — by design. They are the public
API surface published by PKG2 (#12143).

Changes:
- knip.config.ts: add src/extension-api/index.ts as entry point (per
  AGENTS.md, this barrel is the explicit exception to the
  no-barrel-files-in-src rule because it IS the package entry).
- knip.config.ts: ignore src/types/extensionV2.ts (deprecated stub,
  removed once PKG2 ships).
- knip.config.ts: register `-publicAPI` tag.
- Tag externally-consumed exports with @publicAPI:
  - lifecycle.ts: defineNodeExtension/Extension/WidgetExtension declares
    + back-compat type re-exports
  - extension-api-service.ts: _setDispatchImplForTesting, NodeInstanceScope
  - worldInstance.ts: World

Verifies the full lint-format CI matrix locally:
  pnpm lint        
  pnpm stylelint   (unaffected, CSS-only)
  pnpm format:check 
  pnpm knip        
This commit is contained in:
Connor Byrne
2026-05-12 12:13:34 -07:00
parent 3476d06fc9
commit 5b05f2b793
4 changed files with 38 additions and 3 deletions

View File

@@ -9,6 +9,10 @@ const config: KnipConfig = {
'src/assets/css/style.css',
'src/scripts/ui/menu/index.ts',
'src/types/index.ts',
// Public extension API surface — published package entry point.
// Per AGENTS.md, this barrel is the explicit exception to the
// no-barrel-files-in-src rule because it IS the package entry.
'src/extension-api/index.ts',
'src/storybook/mocks/**/*.ts'
],
project: ['**/*.{js,ts,vue}', '*.{js,ts,mts}', '!.claude/**']
@@ -60,7 +64,11 @@ const config: KnipConfig = {
// Agent review check config, not part of the build
'.agents/checks/eslint.strict.config.js',
// Devtools extensions, included dynamically
'tools/devtools/web/**'
'tools/devtools/web/**',
// Deprecated stub re-exporting from `@/extension-api`. Will be removed
// once PKG2 (`@comfyorg/extension-api`) ships and downstream imports
// migrate to the package path.
'src/types/extensionV2.ts'
],
vite: {
config: ['vite?(.*).config.mts']
@@ -79,7 +87,11 @@ const config: KnipConfig = {
tags: [
'-knipIgnoreUnusedButUsedByCustomNodes',
'-knipIgnoreUnusedButUsedByVueNodesBranch',
'-knipIgnoreUsedByStackedPR'
'-knipIgnoreUsedByStackedPR',
// Public API surface consumed externally by extension authors and the
// TypeDoc docgen pipeline (PKG2). Mark exports with @publicAPI when they
// are part of `@comfyorg/extension-api` but not internally referenced.
'-publicAPI'
]
}

View File

@@ -26,6 +26,13 @@
// without forming a circular import. This module re-exports them so the
// existing public path `@/extension-api/lifecycle` keeps working.
/**
* @publicAPI
* Back-compat re-exports of the extension option contracts. Prefer importing
* from `@comfyorg/extension-api` (or `@/extension-api`); the
* `@/extension-api/lifecycle` path is preserved for downstream code that
* imported these types from the original module.
*/
export type {
NodeExtensionOptions,
ExtensionOptions,
@@ -52,6 +59,7 @@ import type {
* extension registration order with a lexicographic tie-break on `name` (D10b).
*
* @stability stable
* @publicAPI
* @example
* ```ts
* import { defineNodeExtension } from '@comfyorg/extension-api'
@@ -82,6 +90,7 @@ export declare function defineNodeExtension(
* `init`, `setup`, sidebar tabs, commands, and other app-level concerns.
*
* @stability stable
* @publicAPI
* @example
* ```ts
* import { defineExtension } from '@comfyorg/extension-api'
@@ -103,6 +112,7 @@ export declare function defineExtension(
* a new widget kind.
*
* @stability experimental
* @publicAPI
*/
export declare function defineWidgetExtension(
options: WidgetExtensionOptions

View File

@@ -132,8 +132,10 @@ let _dispatchImpl: ((cmd: Record<string, unknown>) => unknown) | null = null
/**
* @internal
* @publicAPI
* Test-only: override dispatch implementation. Pass null to restore the stub.
* DO NOT use in extensions — this is an internal testing hook.
* DO NOT use in extensions — this is an internal testing hook used by the
* test framework PR (#12145) and Phase B ECS dispatch tests.
*/
export function _setDispatchImplForTesting(
impl: ((cmd: Record<string, unknown>) => unknown) | null
@@ -159,6 +161,11 @@ function dispatch(_command: Record<string, unknown>): unknown {
// on graph deletion (world entitiesWith diff triggers unmount).
// See decisions/D3.5, D10, D12.
/**
* @publicAPI
* Per-(extension, node) scope record. Exposed so the test framework PR
* (#12145) and Phase B dispatch can introspect scope binding.
*/
export interface NodeInstanceScope {
/** Branded entity ID this scope is bound to. */
readonly nodeEntityId: NodeEntityId

View File

@@ -4,6 +4,12 @@
import type { ComponentKey } from './componentKey'
import type { EntityId } from './entityIds'
/**
* @publicAPI
* ECS World contract. Phase A surface; replaced by Alex's PR #11939
* (ECS substrate slice 2). Consumed externally by the test framework PR
* (#12145) and Phase B dispatch.
*/
export interface World {
getComponent<TData, TEntity extends EntityId>(
entityId: TEntity,