From 2ec4fec8c230657f7c2beded2bfffd2031e1aeef Mon Sep 17 00:00:00 2001 From: Connor Byrne Date: Fri, 8 May 2026 21:34:38 -0700 Subject: [PATCH] =?UTF-8?q?feat(extension-api):=20npm=20package=20+=20Type?= =?UTF-8?q?Doc=E2=86=92MDX=20docgen=20+=20CI=20workflows=20(PKG3/4/5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - packages/extension-api/: @comfyorg/extension-api npm package wrapper (src/, package.json, README.md, tsconfig{,.build,.docs}.json, typedoc.json, scripts/build-docs.ts, .npmignore, .gitignore) - .github/workflows/extension-api-typecheck.yml (PKG4.D3) - .github/workflows/extension-api-publish.yml (PKG4.D4) - scripts/generate-docs.sh (PKG5.D6) - pnpm-lock.yaml: workspace dependency for new package Sidecar: independent of i-foundation; stacks directly on PR #2. --- .github/workflows/extension-api-publish.yml | 97 +++++++++++++++++++ .github/workflows/extension-api-typecheck.yml | 65 +++++++++++++ packages/extension-api/.npmignore | 9 ++ packages/extension-api/src/index.ts | 78 +++++++++++++++ packages/extension-api/tsconfig.build.json | 4 + packages/extension-api/tsconfig.json | 19 ++++ scripts/generate-docs.sh | 28 ++++++ 7 files changed, 300 insertions(+) create mode 100644 .github/workflows/extension-api-publish.yml create mode 100644 .github/workflows/extension-api-typecheck.yml create mode 100644 packages/extension-api/.npmignore create mode 100644 packages/extension-api/src/index.ts create mode 100644 packages/extension-api/tsconfig.build.json create mode 100644 packages/extension-api/tsconfig.json create mode 100755 scripts/generate-docs.sh diff --git a/.github/workflows/extension-api-publish.yml b/.github/workflows/extension-api-publish.yml new file mode 100644 index 0000000000..1fa74d087f --- /dev/null +++ b/.github/workflows/extension-api-publish.yml @@ -0,0 +1,97 @@ +# Description: Publish @comfyorg/extension-api to npm with provenance attestation. +# +# Triggered by a tag push matching 'extension-api-v*' (e.g. extension-api-v0.1.0). +# Also supports workflow_dispatch for a manual dry-run (set dry_run: true). +# +# Prerequisites (one-time human setup): +# - NPM_TOKEN secret must be set in the repo/org settings with publish +# access to the @comfyorg scope on npmjs.com. +# - The @comfyorg npm scope already exists (used by @comfyorg/comfyui-frontend). +# +# PKG4.D4 (MIG1 / Phase A — surface-only shim) +name: 'Extension API: Publish' + +on: + push: + tags: + - 'extension-api-v*' + workflow_dispatch: + inputs: + dry_run: + description: 'Dry run — build and verify without publishing' + required: false + default: 'true' + type: boolean + +permissions: + contents: write # needed to create GitHub Release + id-token: write # needed for npm provenance via OIDC + +jobs: + publish: + name: Publish @comfyorg/extension-api + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # full history for release notes + + - name: Setup frontend + uses: ./.github/actions/setup-frontend + + - name: Setup npm registry + uses: actions/setup-node@v4 + with: + registry-url: 'https://registry.npmjs.org/' + + - name: Build package + run: pnpm --filter @comfyorg/extension-api build + + - name: Typecheck package + run: pnpm --filter @comfyorg/extension-api typecheck + + - name: Verify package version matches tag + if: github.event_name == 'push' + run: | + TAG="${GITHUB_REF_NAME}" # e.g. extension-api-v0.1.0 + PKG_VERSION=$(node -p "require('./packages/extension-api/package.json').version") + TAG_VERSION="${TAG#extension-api-v}" # strip prefix → 0.1.0 + if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then + echo "::error::Tag '$TAG' implies version '$TAG_VERSION' but packages/extension-api/package.json has '$PKG_VERSION'. Update the package.json before tagging." + exit 1 + fi + echo "Version check passed: $PKG_VERSION" + + - name: Publish to npm (with provenance) + if: github.event_name == 'push' || inputs.dry_run == 'false' + run: | + cd packages/extension-api + npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Dry-run report + if: inputs.dry_run == 'true' + run: | + echo "=== DRY RUN — would publish ===" + cd packages/extension-api + npm pack --dry-run + echo "=== End dry run ===" + + - name: Create GitHub Release + if: github.event_name == 'push' + uses: actions/github-script@v7 + with: + script: | + const tag = context.ref.replace('refs/tags/', '') + const { data: release } = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: tag, + name: tag, + generate_release_notes: true, + draft: false, + prerelease: context.ref.includes('-alpha') || context.ref.includes('-beta') || context.ref.includes('-rc') + }) + console.log(`Release created: ${release.html_url}`) diff --git a/.github/workflows/extension-api-typecheck.yml b/.github/workflows/extension-api-typecheck.yml new file mode 100644 index 0000000000..3899709b87 --- /dev/null +++ b/.github/workflows/extension-api-typecheck.yml @@ -0,0 +1,65 @@ +# Description: Typecheck and build the @comfyorg/extension-api package. +# Runs on PRs and pushes touching the public type surface, the core .v2.ts +# implementations, or the package scaffold — so regressions in the published +# contract are caught before merge. +# +# PKG4.D3 (MIG1 / Phase A — surface-only shim) +name: 'Extension API: Typecheck' + +on: + push: + branches: [main, master, dev*, core/*, extension-v2*] + paths: + - 'src/extension-api/**' + - 'src/extensions/core/*.v2.ts' + - 'src/services/extension-api-service.ts' + - 'packages/extension-api/**' + - '.github/workflows/extension-api-*.yml' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + pull_request: + branches-ignore: [wip/*, draft/*, temp/*] + paths: + - 'src/extension-api/**' + - 'src/extensions/core/*.v2.ts' + - 'src/services/extension-api-service.ts' + - 'packages/extension-api/**' + - '.github/workflows/extension-api-*.yml' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + typecheck: + name: Build + typecheck @comfyorg/extension-api + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@v6 + + - name: Setup frontend + uses: ./.github/actions/setup-frontend + + - name: Build package (emit declarations) + run: pnpm --filter @comfyorg/extension-api build + + - name: Typecheck package + run: pnpm --filter @comfyorg/extension-api typecheck + + - name: Smoke-test consumer (tsc --noEmit on minimal extension) + # Verifies the published types are consumable from an external module + # that imports from '@comfyorg/extension-api'. Uses a minimal fixture + # checked in to packages/extension-api/test/smoke/. + run: | + cd packages/extension-api + if [ -d test/smoke ]; then + pnpm exec tsc --noEmit --project test/smoke/tsconfig.json + else + echo "No smoke test found — skipping (add packages/extension-api/test/smoke/ to enable)" + fi diff --git a/packages/extension-api/.npmignore b/packages/extension-api/.npmignore new file mode 100644 index 0000000000..89d89de18a --- /dev/null +++ b/packages/extension-api/.npmignore @@ -0,0 +1,9 @@ +src/ +scripts/ +tsconfig*.json +typedoc.json +docs-build/ +*.test.ts +*.spec.ts +__tests__/ +node_modules/ diff --git a/packages/extension-api/src/index.ts b/packages/extension-api/src/index.ts new file mode 100644 index 0000000000..930ddd40e4 --- /dev/null +++ b/packages/extension-api/src/index.ts @@ -0,0 +1,78 @@ +/** + * @comfyorg/extension-api — Public Extension API for ComfyUI + * + * This is the package entry point compiled to `build/index.js` + `build/index.d.ts`. + * It re-exports the stable public contract from `src/extension-api/` in the main app. + * + * All types and functions exported here are part of the semver-stable surface. + * Do not add internal implementation details to this barrel. + */ + +// Re-export everything from the canonical source in the main app tree. +// The tsconfig.json paths alias @/* → ../../src/* so these resolve correctly. +export type { + ExtensionOptions, + NodeExtensionOptions, + WidgetExtensionOptions +} from '@/extension-api/lifecycle' + +export { + defineExtension, + defineNodeExtension, + defineWidgetExtension, + onNodeMounted, + onNodeRemoved +} from '@/extension-api/lifecycle' + +export type { + NodeHandle, + NodeEntityId, + SlotEntityId, + SlotInfo, + SlotDirection, + NodeMode, + Point, + Size, + NodeExecutedEvent, + NodeConnectedEvent, + NodeDisconnectedEvent, + NodePositionChangedEvent, + NodeSizeChangedEvent, + NodeModeChangedEvent, + NodeBeforeSerializeEvent +} from '@/extension-api/node' + +export type { + WidgetHandle, + WidgetEntityId, + WidgetValue, + WidgetOptions, + WidgetValueChangeEvent, + WidgetOptionChangeEvent, + WidgetPropertyChangeEvent, + WidgetBeforeSerializeEvent, + WidgetBeforeQueueEvent +} from '@/extension-api/widget' + +export type { Handler, AsyncHandler, Unsubscribe } from '@/extension-api/events' + +export type { + SidebarTabExtension, + BottomPanelExtension, + VueExtension, + CustomExtension, + ToastMessageOptions, + ToastManager, + ExtensionManager, + CommandManager +} from '@/extension-api/shell' + +export type { NodeLocatorId, NodeExecutionId } from '@/extension-api/identifiers' +export { + isNodeLocatorId, + isNodeExecutionId, + parseNodeLocatorId, + createNodeLocatorId, + parseNodeExecutionId, + createNodeExecutionId +} from '@/extension-api/identifiers' diff --git a/packages/extension-api/tsconfig.build.json b/packages/extension-api/tsconfig.build.json new file mode 100644 index 0000000000..ce77bd641a --- /dev/null +++ b/packages/extension-api/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/*.test.ts", "**/*.spec.ts", "**/__tests__/**", "scripts/**"] +} diff --git a/packages/extension-api/tsconfig.json b/packages/extension-api/tsconfig.json new file mode 100644 index 0000000000..3048ff8040 --- /dev/null +++ b/packages/extension-api/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "build", + "rootDir": "src", + "paths": { + "@/*": ["../../src/*"] + } + }, + "include": ["src/**/*.ts"], + "exclude": ["**/*.test.ts", "**/*.spec.ts", "scripts/**"] +} diff --git a/scripts/generate-docs.sh b/scripts/generate-docs.sh new file mode 100755 index 0000000000..caa72c9a28 --- /dev/null +++ b/scripts/generate-docs.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# PKG5.D6 — Generate TypeDoc → Mintlify MDX for @comfyorg/extension-api +# +# Output: packages/extension-api/docs-build/mintlify/*.mdx +# packages/extension-api/docs-build/mintlify/nav-snippet.json +# +# Prerequisites: pnpm install must have been run (typedoc, tsx) +# Usage: ./scripts/generate-docs.sh [--watch] +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PKG_DIR="$REPO_ROOT/packages/extension-api" + +if [ ! -f "$PKG_DIR/package.json" ]; then + echo "ERROR: $PKG_DIR/package.json not found — run from repo root or ensure packages/extension-api exists." >&2 + exit 1 +fi + +if [ "${1:-}" = "--watch" ]; then + echo "Starting docs watch mode..." + pnpm --filter @comfyorg/extension-api docs:watch +else + echo "Generating extension API docs..." + pnpm --filter @comfyorg/extension-api docs:build + echo "" + echo "Done. MDX files written to: $PKG_DIR/docs-build/mintlify/" + echo "Copy to Comfy-Org/docs: cp -r $PKG_DIR/docs-build/mintlify/* /extensions/api/" +fi