diff --git a/credentials/FeatherApi.credentials.ts b/credentials/FeatherApi.credentials.ts index a774ed0..d2a0807 100644 --- a/credentials/FeatherApi.credentials.ts +++ b/credentials/FeatherApi.credentials.ts @@ -51,7 +51,7 @@ export class FeatherApi implements ICredentialType { test: ICredentialTestRequest = { request: { baseURL: - '={{$credentials.environment === "production" ? "https://featherhq.com" : "https://sandbox.featherhq.com"}}', + '={{$credentials.environment === "production" ? "https://prod.featherhq.com" : "https://sandbox.featherhq.com"}}', url: '/api/v1/workflow?limit=1', headers: { accept: 'application/json, text/plain, */*', diff --git a/nodes/Feather/Feather.node.json b/nodes/Feather/Feather.node.json index e67ef40..741f552 100644 --- a/nodes/Feather/Feather.node.json +++ b/nodes/Feather/Feather.node.json @@ -1,17 +1,20 @@ { - "node": "n8n-nodes-feather", + "node": "@featherhq/n8n-nodes-feather", "nodeVersion": "1.0", "codexVersion": "1.0", - "categories": ["Development", "Developer Tools"], + "categories": ["Communication", "AI", "Voice AI", "AI Call Center"], "resources": { "credentialDocumentation": [ { - "url": "https://github.com/org/repo?tab=readme-ov-file#credentials" + "url": "https://github.com/OneLoop-HQ/n8n-node?tab=readme-ov-file#credentials" } ], "primaryDocumentation": [ { - "url": "https://github.com/org/repo?tab=readme-ov-file" + "url": "https://github.com/OneLoop-HQ/n8n-node?tab=readme-ov-file" + }, + { + "url": "https://docs.featherhq.com" } ] } diff --git a/nodes/Feather/resources/company/getAll.ts b/nodes/Feather/resources/company/getAll.ts deleted file mode 100644 index d67638a..0000000 --- a/nodes/Feather/resources/company/getAll.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; - -const showOnlyForCompanyGetMany = { - operation: ['getAll'], - resource: ['company'], -}; - -export const companyGetManyDescription: INodeProperties[] = [ - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - ...showOnlyForCompanyGetMany, - returnAll: [false], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 50, - routing: { - send: { - type: 'query', - property: 'limit', - }, - output: { - maxResults: '={{$value}}', - }, - }, - description: 'Max number of results to return', - }, - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: showOnlyForCompanyGetMany, - }, - default: false, - description: 'Whether to return all results or only up to a given limit', - routing: { - send: { - paginate: '={{ $value }}', - }, - operations: { - pagination: { - type: 'offset', - properties: { - limitParameter: 'limit', - offsetParameter: 'offset', - pageSize: 100, - type: 'query', - }, - }, - }, - }, - }, -]; diff --git a/nodes/Feather/resources/company/index.ts b/nodes/Feather/resources/company/index.ts deleted file mode 100644 index 53267ed..0000000 --- a/nodes/Feather/resources/company/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { companyGetManyDescription } from './getAll'; - -const showOnlyForCompanies = { - resource: ['company'], -}; - -export const companyDescription: INodeProperties[] = [ - { - displayName: 'Operation', - name: 'operation', - type: 'options', - noDataExpression: true, - displayOptions: { - show: showOnlyForCompanies, - }, - options: [ - { - name: 'Get Many', - value: 'getAll', - action: 'Get companies', - description: 'Get companies', - routing: { - request: { - method: 'GET', - url: '/companies', - }, - }, - }, - ], - default: 'getAll', - }, - ...companyGetManyDescription, -]; diff --git a/nodes/Feather/resources/user/create.ts b/nodes/Feather/resources/user/create.ts deleted file mode 100644 index 7cfcf15..0000000 --- a/nodes/Feather/resources/user/create.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; - -const showOnlyForUserCreate = { - operation: ['create'], - resource: ['user'], -}; - -export const userCreateDescription: INodeProperties[] = [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: '', - required: true, - displayOptions: { - show: showOnlyForUserCreate, - }, - description: 'The name of the user', - routing: { - send: { - type: 'body', - property: 'name', - }, - }, - }, -]; diff --git a/nodes/Feather/resources/user/get.ts b/nodes/Feather/resources/user/get.ts deleted file mode 100644 index e73681f..0000000 --- a/nodes/Feather/resources/user/get.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; - -const showOnlyForUserGet = { - operation: ['get'], - resource: ['user'], -}; - -export const userGetDescription: INodeProperties[] = [ - { - displayName: 'User ID', - name: 'userId', - type: 'string', - displayOptions: { show: showOnlyForUserGet }, - default: '', - description: "The user's ID to retrieve", - }, -]; diff --git a/nodes/Feather/resources/user/index.ts b/nodes/Feather/resources/user/index.ts deleted file mode 100644 index 954130e..0000000 --- a/nodes/Feather/resources/user/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { userCreateDescription } from './create'; -import { userGetDescription } from './get'; - -const showOnlyForUsers = { - resource: ['user'], -}; - -export const userDescription: INodeProperties[] = [ - { - displayName: 'Operation', - name: 'operation', - type: 'options', - noDataExpression: true, - displayOptions: { - show: showOnlyForUsers, - }, - options: [ - { - name: 'Get Many', - value: 'getAll', - action: 'Get users', - description: 'Get many users', - routing: { - request: { - method: 'GET', - url: '/users', - }, - }, - }, - { - name: 'Get', - value: 'get', - action: 'Get a user', - description: 'Get the data of a single user', - routing: { - request: { - method: 'GET', - url: '=/users/{{$parameter.userId}}', - }, - }, - }, - { - name: 'Create', - value: 'create', - action: 'Create a new user', - description: 'Create a new user', - routing: { - request: { - method: 'POST', - url: '/users', - }, - }, - }, - ], - default: 'getAll', - }, - ...userGetDescription, - ...userCreateDescription, -]; diff --git a/package-lock.json b/package-lock.json index e8c4c7f..8f0ee74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "n8n-nodes-feather", - "version": "0.1.0", + "name": "@featherhq/n8n-nodes-feather", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "n8n-nodes-feather", - "version": "0.1.0", + "name": "@featherhq/n8n-nodes-feather", + "version": "1.0.0", "license": "MIT", "devDependencies": { "@n8n/node-cli": "^0.11.0", @@ -4047,9 +4047,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz", + "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==", "dev": true, "license": "MIT", "dependencies": { @@ -6068,6 +6068,19 @@ "node": ">= 0.6" } }, + "node_modules/release-it/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6246,9 +6259,9 @@ "peer": true }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -6729,9 +6742,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index abb2b97..e42252c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "n8n-nodes-feather", + "name": "@featherhq/n8n-nodes-feather", "version": "1.0.0", "description": "n8n community node to work with the Feather API", "license": "MIT", @@ -28,7 +28,12 @@ "lint": "n8n-node lint", "lint:fix": "n8n-node lint --fix", "release": "n8n-node release", - "prepublishOnly": "n8n-node prerelease" + "test:patch": "./publish.sh patch", + "test:minor": "./publish.sh minor", + "test:major": "./publish.sh major", + "publish:patch": "./publish.sh patch --publish", + "publish:minor": "./publish.sh minor --publish", + "publish:major": "./publish.sh major --publish" }, "files": [ "dist" diff --git a/public-check.sh b/public-check.sh new file mode 100755 index 0000000..d73e08f --- /dev/null +++ b/public-check.sh @@ -0,0 +1 @@ +npx @n8n/scan-community-package '@featherhq/n8n-nodes-feather' \ No newline at end of file diff --git a/publish.sh b/publish.sh new file mode 100755 index 0000000..8caff09 --- /dev/null +++ b/publish.sh @@ -0,0 +1,198 @@ +#!/bin/bash + +# Script to publish package to npm +# Usage: ./publish.sh [patch|minor|major] [--publish] +# Examples: +# ./publish.sh patch - Test build only (dry-run, default) +# ./publish.sh minor --publish - Actually publish to npm and create branch + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${GREEN}✓${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +# Parse arguments +DRY_RUN=true # Default to dry-run mode +VERSION_TYPE="" + +for arg in "$@"; do + case $arg in + --publish) + DRY_RUN=false + ;; + patch|minor|major) + VERSION_TYPE=$arg + ;; + *) + print_error "Unknown argument: $arg" + echo "Usage: ./publish.sh [patch|minor|major] [--publish]" + exit 1 + ;; + esac +done + +# Default to patch if not specified +VERSION_TYPE=${VERSION_TYPE:-patch} + +if [[ "$DRY_RUN" == true ]]; then + print_warning "DRY RUN MODE (default) - No git changes or npm publish will be performed" + print_warning "Use --publish flag to actually publish to npm" +fi + +# Check if git working tree is clean (skip in dry-run) +if [[ "$DRY_RUN" == false ]]; then + if [[ -n $(git status -s) ]]; then + print_error "Git working tree is not clean. Please commit or stash your changes first." + git status -s + exit 1 + fi + print_info "Git working tree is clean" + + # Ensure we're on main branch + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + if [[ "$CURRENT_BRANCH" != "main" ]]; then + print_error "Please switch to main branch first" + exit 1 + fi + + # Pull latest changes + print_info "Pulling latest changes from main..." + git pull origin main +fi + +# Run linting +print_info "Running linter..." +npm run lint + +# Clean up dist directory +print_info "Cleaning up dist directory..." +rm -rf dist || true + +# Build the project +print_info "Building project..." +npm run build + +# Check if dist directory exists +if [[ ! -d "dist" ]]; then + print_error "Build failed: dist directory not found" + exit 1 +fi +print_info "Build successful" + +# Get version bump type (default to patch) +VERSION_TYPE=${1:-patch} + +# Validate version type +if [[ ! "$VERSION_TYPE" =~ ^(patch|minor|major)$ ]]; then + print_error "Invalid version type. Use: patch, minor, or major" + exit 1 +fi + +# Show current version +CURRENT_VERSION=$(node -p "require('./package.json').version") +print_info "Current version: $CURRENT_VERSION" + +# Calculate what the new version would be +if [[ "$DRY_RUN" == true ]]; then + # Calculate new version without modifying package.json + IFS='.' read -r -a VERSION_PARTS <<< "$CURRENT_VERSION" + MAJOR=${VERSION_PARTS[0]} + MINOR=${VERSION_PARTS[1]} + PATCH=${VERSION_PARTS[2]} + + case $VERSION_TYPE in + major) + NEW_VERSION="$((MAJOR + 1)).0.0" + ;; + minor) + NEW_VERSION="$MAJOR.$((MINOR + 1)).0" + ;; + patch) + NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))" + ;; + esac + + print_info "Would bump $VERSION_TYPE version: $CURRENT_VERSION → $NEW_VERSION" +else + # Bump version + print_info "Bumping $VERSION_TYPE version..." + npm version $VERSION_TYPE --no-git-tag-version + + # Get new version + NEW_VERSION=$(node -p "require('./package.json').version") + print_info "New version: $NEW_VERSION" + + # Create release branch + RELEASE_BRANCH="release/v$NEW_VERSION" + print_info "Creating branch: $RELEASE_BRANCH" + git checkout -b "$RELEASE_BRANCH" + + # Commit version bump + git add package.json package-lock.json + git commit -m "chore: bump version to $NEW_VERSION" + + # Create git tag + git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION" + print_info "Created git tag v$NEW_VERSION" + + # Publish to npm + print_info "Publishing to npm..." + npm publish --access public + + print_info "Successfully published v$NEW_VERSION to npm!" + + # Push branch and tags to git + print_info "Pushing branch and tags to origin..." + git push -u origin "$RELEASE_BRANCH" + git push --tags + print_info "Pushed $RELEASE_BRANCH with tags" + + # Ask if user wants to create a PR + print_warning "Create a pull request? (y/n)" + read -r response + if [[ "$response" =~ ^[Yy]$ ]]; then + # Check if gh CLI is available + if command -v gh &> /dev/null; then + gh pr create --title "Release v$NEW_VERSION" --body "Release version $NEW_VERSION" --base main --head "$RELEASE_BRANCH" + print_info "Pull request created" + else + print_warning "GitHub CLI (gh) not found. Please create PR manually:" + print_warning "https://github.com/OneLoop-HQ/n8n-node/compare/main...$RELEASE_BRANCH" + fi + else + print_warning "Remember to create a PR to merge $RELEASE_BRANCH into main" + fi + + # Switch back to main branch + git checkout main + + print_info "✨ Publish complete!" + print_info "Next steps:" + print_info " 1. Review and merge the PR: $RELEASE_BRANCH -> main" + print_info " 2. The package v$NEW_VERSION is now live on npm" +fi + +if [[ "$DRY_RUN" == true ]]; then + print_info "✨ Dry run complete!" + print_info "Build successful. Ready to publish v$NEW_VERSION" + echo "" + print_info "To actually publish to npm, run:" + print_info " ./publish.sh $VERSION_TYPE --publish" + print_info " or: npm run publish:$VERSION_TYPE" +fi