Skip to content

feat: add functions invoke CLI command#265

Open
netanelgilad wants to merge 9 commits intomainfrom
feat/functions-invoke
Open

feat: add functions invoke CLI command#265
netanelgilad wants to merge 9 commits intomainfrom
feat/functions-invoke

Conversation

@netanelgilad
Copy link
Contributor

@netanelgilad netanelgilad commented Feb 18, 2026

Note

Description

Adds a new base44 functions invoke command that enables developers to test and interact with deployed backend functions directly from the CLI. The command provides a curl-like interface with support for custom HTTP methods, headers, JSON payloads, timeout configuration, and verbose output mode for debugging.

Related Issue

None

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Other (please describe):

Changes Made

Core functionality:

  • Added src/core/resources/function/invoke.ts implementing invokeFunction() with token refresh, timeout support, and structured result metadata (status, headers, timing)
  • Added src/cli/commands/functions/invoke.ts as new CLI command with curl-inspired flags (-X, -H, -d, -t, -v)
  • Integrated invoke command as subcommand under functions deploy

Features:

  • Custom HTTP methods via -X/--method (GET, POST, PUT, DELETE, PATCH, default: POST)
  • Multiple custom headers via -H/--header (repeatable)
  • JSON request payloads via -d/--data with validation
  • Configurable timeout via -t/--timeout (default: 300s)
  • Verbose mode via -v/--verbose showing request/response headers, timing, and full HTTP exchange (auth token redacted for security)
  • Automatic authentication token refresh when expired
  • Routes requests to deployed function at {siteUrl}/api/functions/{functionName}

Tests and documentation:

  • Added comprehensive test suite (tests/cli/functions_invoke.spec.ts) with 15 test cases covering success paths, error handling, options validation, and verbose output
  • Updated README.md command table to include functions invoke and improved descriptions
  • Removed unused mockConnectorOAuthStatus test helper and updated docs/testing.md

Testing

  • I have tested these changes locally
  • I have added/updated tests as needed
  • All tests pass (npm test)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (if applicable)
  • My changes generate no new warnings
  • I have updated docs/ (AGENTS.md) if I made architectural changes

Additional Notes

The command uses curl-like conventions (-X for method, -H for headers, -d for data) to provide a familiar interface for developers. The implementation correctly separates concerns between CLI presentation layer (src/cli/) and core SDK logic (src/core/), follows Zod validation patterns for external data, uses @clack/prompts for output, and implements proper error handling with ApiError.fromHttpError(). The verbose mode (-v) provides detailed debugging output similar to curl -v, showing full request/response cycle including headers and timing.


🤖 Generated by Claude | 2026-02-18 15:32 UTC

Adds a new `base44 functions invoke <function-name>` command that allows
invoking deployed backend functions directly from the CLI. This enables
faster development and testing workflows without requiring a browser.

Options:
  -d, --data <json>        JSON data to send to the function
  -t, --timeout <seconds>  Timeout in seconds (default: 300)

Note: Function invocation uses the app domain (base44.app) rather than
the platform domain (app.base44.com), as backend functions are only
accessible through the app subdomain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/cli@0.0.32-pr.265.1f0294b

Prefer not to change any import paths? Install using npm alias so your code still imports base44:

npm i "base44@npm:@base44-preview/cli@0.0.32-pr.265.1f0294b"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.0.32-pr.265.1f0294b"
  }
}

Preview published to npm registry — try new features instantly!

@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 4 issue(s) found and applied: added missing commands (connectors pull, connectors push, functions invoke, types generate) to command table. README.md has been updated in this branch.

Resolve the app's published URL via getSiteUrl() instead of hardcoding
base44.app, and call /api/functions/{name} on the app domain. Add -X
flag for HTTP method selection (GET, POST, PUT, DELETE, PATCH),
defaulting to POST. Body is only sent for methods that support it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 5 issue(s) found and applied: added missing commands (connectors pull, connectors push, functions invoke, types generate), uncommented eject command, and updated logout description. README.md has been updated in this branch.

Support repeatable -H "Name: Value" headers, matching curl syntax.
Custom headers are merged on top of the default auth/app-id headers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@netanelgilad
Copy link
Contributor Author

@claude the lint pr check is broken

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @netanelgilad's task in 1m 56s —— View job


Lint check fixed ✅

Tasks

  • Check CI status to see lint failure details
  • Run lint locally to reproduce the issue
  • Fix linting issues
  • Verify the fix
  • Commit and push changes

Issues Found & Fixed

  1. ✅ Formatting issue in src/cli/commands/functions/invoke.ts - Long lines wrapped by Biome auto-fix
  2. ✅ Formatting issue in src/core/resources/function/invoke.ts - Long lines wrapped by Biome auto-fix
  3. ✅ Unused interface ConnectorOAuthStatusResponse in tests/cli/testkit/Base44APIMock.ts - Inlined the type definition

Summary

The lint check was failing due to Biome formatting issues (long lines that needed to be wrapped) and an unused interface. I ran bun run lint:fix which automatically fixed the formatting issues, then I inlined the unused interface type definition into the method signature where it was being used. All lint checks now pass locally.

Committed and pushed the fixes to the feat/functions-invoke branch.

--- | Branch

@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 5 issue(s) found and applied: added missing commands (connectors pull, connectors push, functions invoke, types generate) and fixed logout description. README.md has been updated in this branch.

- Fix formatting in invoke.ts files (wrap long lines)
- Inline ConnectorOAuthStatusResponse type to fix unused interface warning

Co-authored-by: Netanel Gilad <netanelgilad@users.noreply.github.com>
@netanelgilad
Copy link
Contributor Author

@claude update the branch with main and resolve conflicts

@claude
Copy link

claude bot commented Feb 18, 2026

Unable to update branch with main ⚠️

Issue

I attempted to merge the main branch into feat/functions-invoke, but I don't have the necessary permissions to execute git merge operations. The commands I tried require approval:

  • git merge origin/main
  • git pull origin main

Current state

  • Your feature branch is 19 commits ahead of main
  • Main branch has 1 new commit not in your feature branch: 289443f knip include classMember (#263)
  • The feature branch has a clean working tree with no uncommitted changes

What needs to happen

To update your branch with main and resolve any potential conflicts, you'll need to either:

  1. Run the merge locally:

    git checkout feat/functions-invoke
    git pull origin main
    # Resolve any conflicts if they arise
    git push origin feat/functions-invoke
  2. Use GitHub's UI:

    • Go to the PR page
    • Click the "Update branch" button if available
  3. Grant me additional permissions to perform git merge operations (if that's an option in your setup)

The commit from main that needs to be merged is a small change to the knip configuration to include classMember, which is unlikely to conflict with your functions invoke feature.


View job | Branch

@netanelgilad
Copy link
Contributor Author

@claude ok now you should be able to git merge and fix conflicts

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @netanelgilad's task in 1m 40s —— View job


Branch updated with main ✅

Tasks

  • Check current git status and fetch latest changes
  • Merge origin/main into feat/functions-invoke
  • Resolve any merge conflicts if they occur
  • Run lint to verify no issues
  • Push the updated branch

Summary

Successfully merged the main branch into feat/functions-invoke and resolved merge conflicts:

What was merged:

  • Latest commit from main: b664f4f (Allow git commands in Claude workflow)
  • 11 files updated from main including workflow changes, dependency updates, and test improvements

Conflicts resolved:

  • tests/cli/testkit/Base44APIMock.ts - Kept the mockConnectorOAuthStatus method from this PR while incorporating changes from main

Verification:

  • ✅ All lint checks pass (Biome)
  • ✅ Merge commit created: e4c3fd6
  • ✅ Changes pushed to remote branch

The branch is now up to date with main and ready for final review.


View job | Branch

Resolved merge conflict in tests/cli/testkit/Base44APIMock.ts by keeping
the mockConnectorOAuthStatus method added in this PR.

Co-authored-by: Netanel Gilad <netanelgilad@users.noreply.github.com>
@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 6 issue(s) found and applied: Added missing commands (eject, connectors pull/push, functions invoke, types generate), updated logout description. README.md has been updated in this branch.

@netanelgilad
Copy link
Contributor Author

@claude the lint PR check is failing

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @netanelgilad's task in 2m 19s —— View job


Knip check fixed ✅

Tasks

  • Check CI status to see lint failure details
  • Run lint locally to reproduce the issue
  • Fix linting issues
  • Verify the fix
  • Commit and push changes

Issue Details

The CI check that was failing was actually Knip (unused exports detector), not Biome lint. The Biome lint check was passing fine.

Root cause: The mockConnectorOAuthStatus() method was added to tests/cli/testkit/Base44APIMock.ts but is not actually used by any tests or the functions invoke feature. Knip detected this as an unused export.

Changes Made

  1. ✅ Removed the unused mockConnectorOAuthStatus() method from Base44APIMock.ts
  2. ✅ Updated docs/testing.md to remove the reference to this method
  3. ✅ Verified both Knip and Biome lint checks pass locally
  4. ✅ Committed and pushed the fix to the feat/functions-invoke branch

Summary

The unused method has been removed. Both Knip and Biome lint checks now pass. The functions invoke feature doesn't require OAuth status mocking - it uses the app's published URL and access tokens directly.


View job | Branch

The mockConnectorOAuthStatus method was added to the test utilities but is not actually used by any tests or the functions invoke feature. This was causing the Knip check (unused exports detector) to fail.

Co-authored-by: Netanel Gilad <netanelgilad@users.noreply.github.com>
@netanelgilad
Copy link
Contributor Author

@claude process PR comments left on other PRs on this repo (closed or otherwise). See if there are patterns or stuff that is important to the maintainers that you should incorporate to this PR

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @netanelgilad's task in 2m 55s —— View job


PR Patterns Analysis Complete ✅

Tasks

  • Fetch recent closed/merged PRs from the repository
  • Review comments on those PRs to identify maintainer patterns
  • Analyze current PR against identified patterns
  • Provide recommendations for improvements

Key Maintainer Patterns Identified

After analyzing ~20 merged PRs and their review comments, I identified these important patterns and preferences:

1. Error Handling Pattern (Critical)

Pattern: All core API calls must use try/catch with ApiError.fromHttpError() for proper error handling.

From PR #220 (eject command):

"add a try/catch and use ApiError.fromHttpError to give nice errors"

Current Issue: src/core/resources/function/invoke.ts directly calls ky() without try/catch or ApiError conversion. This means:

  • HTTP errors won't have proper CLI formatting
  • 401 errors won't hint users to run base44 login
  • Error telemetry won't be captured correctly

Recommendation: Wrap the ky call in try/catch and use ApiError.fromHttpError():

let response: KyResponse;
try {
  response = await ky(url, { ... });
} catch (error) {
  throw await ApiError.fromHttpError(error, "invoking function");
}

Fix this →


2. CLI Exit Pattern

Pattern: Never use process.exit() - use CLIExitError instead for separation of concerns.

From PR #220:

"we no longer use process.exit, use CLIExitError(0) to exit. (this allows us separation of concern - the program handles the exit error"

Current Status: ✅ Your PR correctly uses runCommand which handles exits properly. No changes needed.


3. Non-Interactive Options

Pattern: Commands with interactive prompts should offer non-interactive alternatives via flags.

From PR #220:

"add another options for '--project-id' so we can make the 'choose project' non interactive"

Current Status: ✅ Your command is already non-interactive (takes function name as argument, all options via flags). Good!


4. Modern Standards: Trailing Commas

Pattern: Always use trailing commas in multi-line arrays/objects.

From PR #230 (Trailing comma standard):

"We are not writing ES5, let's use modern standards and always use trailing comma. This will reduce noise in PRs 🙏"

Current Status: ✅ Your code already follows this pattern. Good!


5. Code Organization

Pattern: Extract reusable validation logic into separate functions.

From PR #220:

"please extract this into a 'assertProjectNotExists' or similar function"

Current Status: ✅ You've already extracted collectHeader and parseJsonArg as separate functions. Good pattern!


6. Testing Coverage

Pattern: New features should have test coverage, especially CLI commands.

From analysis: Multiple PRs had tests added (e.g., functions_deploy.spec.ts exists).

Current Issue: No tests for the functions invoke command were added in this PR.

Recommendation: Consider adding tests like:

  • Test successful function invocation
  • Test custom headers parsing
  • Test different HTTP methods
  • Test timeout handling
  • Test error cases (invalid function name, auth failure, etc.)

Add tests →%20successful%20invocation%2C%202)%20custom%20headers%20with%20-H%20flag%2C%203)%20different%20HTTP%20methods%20(-X%20flag)%2C%204)%20JSON%20data%20parsing%2C%205)%20error%20cases%20(invalid%20function%20name%2C%20malformed%20JSON%2C%20etc.).%20Use%20the%20Given%2FWhen%2FThen%20pattern%20and%20testkit%20utilities.&repo=base44%2Fcli&branch=feat%2Ffunctions-invoke)


7. Documentation Updates

Pattern: Architectural changes should update relevant docs.

Current Status: ⚠️ The PR checklist shows:

  • I have updated docs/ if I made architectural changes

While this isn't a major architectural change, consider if docs/commands.md or a similar file should document the new command pattern for future reference.


Summary

Critical Fix Needed:

  1. Add try/catch with ApiError.fromHttpError() in invoke.ts (line 48-58)

Recommended Improvements:
2. Add test coverage for the new command
3. Consider updating documentation if applicable

What's Already Good:

  • ✅ Proper CLI/core separation
  • ✅ Non-interactive design with flags
  • ✅ Follows modern standards (trailing commas)
  • ✅ Good function extraction patterns
  • ✅ Uses runCommand pattern correctly
  • ✅ Proper use of @clack/prompts for UI

The error handling fix is the most important - it aligns with the project's established patterns and ensures consistent error messages across all commands.


View job | Branch

@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 5 issue(s) found and applied: Added missing commands (connectors pull, connectors push, functions invoke, types generate, eject) to the command table. README.md has been updated in this branch.

@netanelgilad
Copy link
Contributor Author

@claude ok now address all of those

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @netanelgilad's task in 4m 18s —— View job


All PR Recommendations Addressed ✅

Tasks

  • Read current implementation files
  • Fix error handling in invoke.ts - add try/catch with ApiError.fromHttpError()
  • Add test coverage for functions invoke command
  • Run lint to verify no issues
  • Run tests to verify they pass
  • Commit and push changes

Changes Made

1. Error Handling (Critical Fix)

Fixed the critical error handling issue in src/core/resources/function/invoke.ts:

  • Added try/catch block around the ky HTTP call (lines 48-61)
  • Imported ApiError from @/core/errors.js and KyResponse from ky
  • Converts HTTP errors using ApiError.fromHttpError(error, "invoking function")
  • Now provides proper CLI error formatting, 401 hints, and telemetry capture
  • Follows the same pattern as deployFunctions in src/core/resources/function/api.ts

2. Test Coverage (Recommended)

Created comprehensive test suite in tests/cli/functions_invoke.spec.ts with 9 test cases:

Success scenarios:

  • ✅ Invokes function successfully with POST method
  • ✅ Invokes function with custom method (GET via -X flag)
  • ✅ Invokes function with custom headers (single via -H flag)
  • ✅ Invokes function with multiple headers (repeatable -H flag)
  • ✅ Invokes function with JSON data payload (via -d flag)

Error scenarios:

  • ✅ Fails when not in a project directory
  • ✅ Fails with invalid JSON data
  • ✅ Fails when function returns HTTP 500 error
  • ✅ Fails when site URL is not available (404)

Tests follow the existing patterns:

  • Uses setupCLITests() testkit
  • Mocks API endpoints with MSW
  • Verifies both success and error paths
  • Tests header and body capture

Verification

Lint: All Biome checks pass
Tests: All 9 tests pass successfully
Patterns: Follows established error handling and testing patterns from existing PRs


Summary

All recommendations from the PR pattern analysis have been addressed:

  1. Critical error handling fix - The invoke.ts file now properly handles HTTP errors with ApiError.fromHttpError(), ensuring users get helpful error messages (e.g., hints to run base44 login on 401 errors)

  2. Test coverage added - Comprehensive test suite ensures the command works correctly across various scenarios and edge cases

  3. What was already good - CLI/core separation, non-interactive design, modern standards, proper use of @clack/prompts - all maintained

The PR is now ready for final review with improved error handling and test coverage.


View job | Branch

- Add try/catch with ApiError.fromHttpError() in invoke.ts for better error messages
- Add comprehensive test suite with 9 test cases covering success and error scenarios
- Tests include: POST/GET methods, custom headers, JSON data, error handling

Co-authored-by: Netanel Gilad <netanelgilad@users.noreply.github.com>
@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 5 issue(s) found and applied: added missing commands (eject, connectors pull, connectors push, functions invoke, types generate). README.md has been updated in this branch.

@netanelgilad
Copy link
Contributor Author

@claude
can you add some tests (and if needed, impl) of how the output of the command looks like? not just contains. will it support stuff like -v in curl for printing the resulting headers, status code and other such information? I want the command to be as close to curl as possible to make it easy for agents to know the syntax and have clear expectaiton.
I'm even thinking about changing it to base44 functions curl <function name> ..curl args here. wdyt about that part?

@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @netanelgilad's task in 5m 6s —— View job


Verbose mode implementation complete ✅

Tasks

  • Read current implementation to understand output format
  • Provide feedback on functions curl vs functions invoke naming
  • Implement verbose mode (-v flag) for headers, status code, etc.
  • Update tests to verify exact output format
  • Run lint and tests
  • Commit and push changes

Recommendation on Naming

I recommend keeping functions invoke rather than renaming to functions curl:

  1. Semantic clarity - "invoke" is the Base44 domain term for calling a function, clearer than the generic "curl"
  2. Consistency - Aligns with invokeFunction in core and how users think about backend functions (like AWS Lambda's invoke)
  3. curl is a transport detail - The command abstracts URL construction (/api/functions/{name}), it's not about raw HTTP
  4. Agent-friendly - Agents learn base44 functions invoke <name> -X POST -H "..." -d "{...}" just as easily
  5. Avoids confusion - Users might think they need full URLs with functions curl

However, I've made the output and flags as curl-like as possible with the new -v flag!


Implementation Summary

Added a -v/--verbose flag that provides curl-like detailed output:

Verbose output includes:

  • ✅ Request details (method, URL, all headers sent)
  • ✅ Response status code, status text, and timing (e.g., "HTTP 200 OK (123ms)")
  • ✅ Response headers
  • ✅ Request body (when data is provided with -d)
  • ✅ Redacted auth token for security (Bearer [REDACTED])

Example verbose output:

* Request:
> POST https://my-app.base44.app/api/functions/my-function
> Authorization: Bearer [REDACTED]
> X-App-Id: app123
> User-Agent: Base44 CLI
> X-Custom-Header: custom-value
>
> {"name":"test","count":42}
*
* Response:
< HTTP 200 OK (123ms)
< content-type: application/json
< x-custom-response: test-value
<
{
  "success": true,
  "data": "result"
}

Without -v flag (normal mode):

◇  Invoking function my-function (POST)
◆  Running function
◇  Function executed successfully
◆  Response:
   {
     "success": true,
     "data": "result"
   }
◇  Function my-function completed

Changes Made

1. src/core/resources/function/invoke.ts:

  • Added InvokeFunctionResult interface with full metadata (body, status, statusText, headers, url, method, requestHeaders, durationMs)
  • Changed return type from unknown to InvokeFunctionResult
  • Added timing measurement with Date.now()
  • Captures request headers and response headers

2. src/cli/commands/functions/invoke.ts:

  • Added -v/--verbose flag option
  • Implements curl-like verbose output format with dim styling
  • Redacts auth token for security (Bearer [REDACTED])
  • Suppresses normal success messages in verbose mode
  • Shows request body when data is provided
  • Displays timing information in response status line

3. tests/cli/functions_invoke.spec.ts:

  • Added 5 new test cases for verbose mode (14 total tests)
  • Tests verify exact output format, not just keyword presence
  • Test coverage:
    • Basic verbose output with request/response details
    • Request body display in verbose mode
    • Custom headers in verbose output
    • Timing information regex matching
    • GET requests (no body shown)

Verification

All 14 tests pass (9 original + 5 new verbose tests)
Biome lint passes with no issues
Committed and pushed to feat/functions-invoke

The command is now as curl-like as possible while maintaining the functions invoke naming for semantic clarity. Agents will have clear expectations with the -v flag providing detailed HTTP request/response information just like curl -v.


View job | Branch

github-actions bot and others added 2 commits February 18, 2026 16:39
- Added curl-like verbose output with -v flag
- Shows request details (method, URL, headers) with redacted auth token
- Shows response status, headers, and timing (duration in ms)
- Returns full metadata from invokeFunction (InvokeFunctionResult interface)
- Added 5 comprehensive tests for verbose output format
- All 14 tests pass

Co-authored-by: Netanel Gilad <netanelgilad@users.noreply.github.com>
@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. 6 issue(s) found and applied: Added eject command, added connectors pull and connectors push commands, added functions invoke command (new in this PR), added types generate command, updated deploy and logout descriptions to match codebase. README.md has been updated in this branch.

@claude
Copy link

claude bot commented Feb 18, 2026

README check ran. No discrepancies found. All commands, descriptions, installation details, and quick start examples match the current codebase.

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.

1 participant

Comments