my-function-api

$npx mdskill add myapihq/myapi/my-function-api

Deploy JavaScript functions to the MyAPI edge runtime with a live URL.

  • Register and deploy single-file JS bundles to Cloudflare Workers.
  • Depends on MyAPI CLI, Cloudflare Workers, and scoped API keys.
  • Uses a two-step lifecycle: create then deploy with a JS bundle.
  • Returns a live invocation URL and scoped capability key for cross-slot calls.

SKILL.md

.github/skills/my-function-apiView on GitHub ↗
---
name: my-function-api
version: 1.0.0
description: >
  Deploy JavaScript functions to the MyAPI edge runtime (Cloudflare Workers). Register a function, upload a single-file JS bundle, get a live HTTP invocation URL or run it on a cron schedule. Each function gets a scoped capability key for cross-slot calls.
triggers: [function, deploy function, edge function, serverless, cloudflare worker, cron, scoped api key, capability key, invocation url, bundle]
checksum: sha256-pending
---

# MyFunctionAPI

Deploy backend code without running a server. Register a function, upload a single-file JS bundle, and it goes live on the MyAPI edge runtime (Cloudflare Workers) with a public invocation URL — or runs on a cron schedule. Each function carries a scoped capability key so it can call other MyAPI slots with its own authority.

The full loop is live: **create → deploy → invoke → inspect runs → set secrets**.

## Capabilities
<!-- llm:start -->
**Two-step lifecycle: register, then deploy.** `myapi fn create --name <slug>` persists the function record and mints a `scoped_api_key`, returned **exactly once** (save it if you need it). `myapi fn deploy <id> <bundle.js>` uploads a single-file JavaScript bundle (≤4MB); the backend wraps it with the MYAPI shim and ships it to Cloudflare Workers. After deploy the function has a live `invocation_url`.

**Scoped key = capability key.** It is **org-locked**. By default it inherits the deployer's slot grants; narrow it at create time with `--scope <slot>[,<slot>...]` (comma-separated, e.g. `--scope email,storage`) — the primary way to deploy a deliberately narrow function. Grants can never exceed the caller's, so a function never out-reaches the credential that created it. It is rejected with `403 SCOPE_FORBIDDEN` at `/hq/*`, `/admin/*`, `/internal/*`. **Deploy rotates this key** — the fresh value is printed once on every deploy. (Minting a narrow account key first — `myapi keys create --grant ...` — is only needed when the *deploy credential itself* must be constrained, e.g. handing deploy rights to another system.)

**HTTP or cron triggers.** Default is `http` — the function gets a public invocation URL once deployed. Pass `--cron "<expr>"` at create time to run on a schedule (e.g. `"0 8 * * *"`) instead.

**Secrets via Worker Secrets.** `myapi fn env <id> <name> <value>` sets a secret (Stripe key, API token, …) as a Cloudflare Worker Secret on a deployed function. The value is encrypted at rest by Cloudflare and never stored or echoed by MyAPI. The function must already be deployed.

**Inspect invocations.** `myapi fn runs <id>` lists recent invocation records (most recent first, up to 100) with status, duration, and any error message.

Name rules (validated client- and server-side, kept identical):
- `^[a-z0-9][a-z0-9-]{0,49}$` — kebab-case, 1-50 chars
- Reserved server-side: `www`, `api`, `admin`, `system`, `default`
<!-- llm:end -->

## Commands
<!-- generated:start -->
| Command | What it does |
|---|---|
| `myapi fn create --name <name> [--cron <expr>] [--scope <slot>[,<slot>...]]` | Register a function record + receive scoped API key (returned once). `--scope` narrows the key's slot grants |
| `myapi fn deploy <id> <bundle.js>` | Upload a single-file JS bundle (≤4MB) and go live; rotates the scoped key |
| `myapi fn env <id> <name> <value>` | Set a Worker Secret on a deployed function |
| `myapi fn runs <id>` | List recent invocation records (status, duration, errors) |
| `myapi fn list` | List functions in your org |
| `myapi fn get <id>` | Inspect a function (name, trigger, invocation URL) |
| `myapi fn delete <id>` | Soft-delete the record + revoke the scoped key |
<!-- generated:end -->

## Examples
<!-- llm:start -->
```bash
# Register an HTTP function (invocation_url is empty until you deploy)
myapi fn create --name my-app-api
# → Function created: fn_abc123
#   Scoped API key (returned once — save it if you need it):
#     hq_live_...   (scoped keys are not visually distinct from account keys)

# Deploy a single-file JS bundle → goes live, scoped key is rotated
myapi fn deploy fn_abc123 ./dist/bundle.js
# → Deployed function fn_abc123
#   Invocation URL:  https://fn-abc123.<...>.workers.dev
#   Scoped API key was rotated. New value (returned once): hq_live_...

# Set a secret (encrypted at rest by Cloudflare; never echoed)
myapi fn env fn_abc123 STRIPE_KEY sk_live_...

# Inspect recent invocations
myapi fn runs fn_abc123

# Register a cron function instead of HTTP
myapi fn create --name daily-report --cron "0 8 * * *"

# Register with a narrowed key — the function can only call email + storage
myapi fn create --name mailer --scope email,storage

# List + inspect
myapi fn list
myapi fn get fn_abc123

# Delete (revokes the scoped key — future calls with it return 401)
myapi fn delete fn_abc123
```

### Using the scoped key

```bash
# Save the key returned at create/deploy time
SCOPED_KEY="hq_live_..."

# Call slots the key was granted — works (within its org + grants)
curl -H "Authorization: Bearer $SCOPED_KEY" \
  https://api.myapihq.com/database/orgs/$ORG_ID/namespaces

# Calling /hq/* with it — denied (403 SCOPE_FORBIDDEN)
curl -H "Authorization: Bearer $SCOPED_KEY" \
  https://api.myapihq.com/hq/orgs
# → 403 {"error":{"code":"SCOPE_FORBIDDEN"}}
```
<!-- llm:end -->

## Notes

- The bundle is a **single JavaScript file** (≤4MB). Bundle your dependencies before deploy (esbuild/rollup/etc.).
- `--cron` is set at create time; the trigger type is fixed for the function's lifetime.
- Deploy rotates the scoped key on every call — re-capture the printed value if other systems use it.

Run `myapi fn --help` or `myapi fn <subcommand> --help` for full flag reference.

More from myapihq/myapi