@myapihq/cli 2.10.0 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/commands/email/mailbox.js +11 -0
  2. package/dist/commands/import-key.test.d.ts +1 -0
  3. package/dist/commands/import-key.test.js +69 -0
  4. package/dist/commands/org.js +5 -1
  5. package/dist/commands/setup.d.ts +5 -1
  6. package/dist/commands/setup.js +67 -6
  7. package/dist/commands/storage.js +151 -14
  8. package/dist/config.d.ts +2 -0
  9. package/dist/errors.d.ts +4 -0
  10. package/dist/errors.js +30 -3
  11. package/dist/helpers.d.ts +20 -1
  12. package/dist/helpers.js +79 -1
  13. package/dist/index.js +6 -1
  14. package/dist/org-not-found.test.d.ts +1 -0
  15. package/dist/org-not-found.test.js +42 -0
  16. package/dist/org-notice.test.d.ts +1 -0
  17. package/dist/org-notice.test.js +37 -0
  18. package/dist/output.d.ts +6 -0
  19. package/dist/output.js +8 -1
  20. package/dist/skills/my-api-hq/SKILL.md +34 -14
  21. package/dist/skills/my-audience-api/SKILL.md +16 -1
  22. package/dist/skills/my-auth-api/SKILL.md +17 -2
  23. package/dist/skills/my-company-api/SKILL.md +16 -1
  24. package/dist/skills/my-container-api/SKILL.md +22 -7
  25. package/dist/skills/my-crm-api/SKILL.md +16 -1
  26. package/dist/skills/my-database-api/SKILL.md +13 -17
  27. package/dist/skills/my-domain-api/SKILL.md +16 -1
  28. package/dist/skills/my-email-api/SKILL.md +12 -16
  29. package/dist/skills/my-email-verify-api/SKILL.md +16 -1
  30. package/dist/skills/my-feedback-api/README.md +33 -0
  31. package/dist/skills/my-feedback-api/SKILL.md +118 -0
  32. package/dist/skills/my-feedback-api/claude/.claude-plugin/plugin.json +7 -0
  33. package/dist/skills/my-function-api/README.md +34 -0
  34. package/dist/skills/my-function-api/SKILL.md +16 -1
  35. package/dist/skills/my-funnel-api/SKILL.md +16 -1
  36. package/dist/skills/my-git-api/SKILL.md +17 -1
  37. package/dist/skills/my-image-api/SKILL.md +17 -1
  38. package/dist/skills/my-llm-api/SKILL.md +20 -6
  39. package/dist/skills/my-payments-api/README.md +33 -0
  40. package/dist/skills/my-payments-api/SKILL.md +16 -1
  41. package/dist/skills/my-people-api/SKILL.md +16 -1
  42. package/dist/skills/my-pixel-api/SKILL.md +26 -3
  43. package/dist/skills/my-queue-api/SKILL.md +35 -2
  44. package/dist/skills/my-storage-api/SKILL.md +37 -29
  45. package/dist/skills/my-task-api/SKILL.md +35 -2
  46. package/dist/skills/my-url-to/SKILL.md +16 -1
  47. package/dist/skills/my-webhook-api/SKILL.md +23 -3
  48. package/dist/skills/my-workflow-api/SKILL.md +32 -6
  49. package/package.json +2 -2
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: my-storage-api
3
- version: 1.0.0
3
+ version: 1.1.0
4
4
  description: >
5
5
  Edge-hosted asset storage. Upload a local file of any content type directly, or have the server fetch from a public URL. Each asset gets a stable public CDN URL.
6
6
  triggers: [storage, upload, ingest, asset, cdn, image hosting, file upload, get-url, download, public url]
7
- checksum: sha256-1f3e7f6de3435e0334a808b9d2faa978c9cb70982509a376abc0e539cb44e1ed
7
+ checksum: sha256-1452c30c103d0bb8b76a8f6d8e1688cadd556922b8c60e7ac754222c33b65524
8
8
  ---
9
9
 
10
10
  # MyStorageAPI
@@ -13,7 +13,7 @@ Per-org asset storage with edge CDN delivery. Two ways in: direct upload (local
13
13
 
14
14
  ## Capabilities
15
15
  <!-- llm:start -->
16
- Storage is the asset layer. Anything you upload or ingest is served from the edge under a permanent public URL — embed it in funnel pages, email templates, anywhere.
16
+ Storage is the asset layer. By default an upload is served from the edge under a permanent public URL — embed it in funnel pages, email templates, anywhere. Pass `--private` for anything holding personal data: no public URL is created and reads go through a signed, expiring link (see **Notes**).
17
17
 
18
18
  `upload` accepts **any content type** from the local filesystem. There is no
19
19
  extension allowlist — an unrecognized type is stored as an opaque blob and
@@ -49,6 +49,9 @@ Use `get` for a round-trip metadata fetch. Use `get-url` when you just need the
49
49
  | `myapi storage ingest <url>` | Server fetches a public URL into storage |
50
50
  | `myapi storage get <asset_id>` | Round-trip the API for full metadata (`--json` or human block) |
51
51
  | `myapi storage get-url <asset_id>` | Pure local URL constructor — no API call, no auth |
52
+ | `myapi storage visibility <asset_id> <public\|private>` | Flip an asset's visibility. Going private stops the plain URL serving, immediately |
53
+ | `myapi storage sign <asset_id> [--ttl <seconds>]` | Time-limited link to a private asset (default 900s, max 86400). Billable |
54
+ | `myapi storage revoke-links <asset_id>` | Kill every signed link, including unexpired ones |
52
55
  | `myapi storage delete <asset_id>` | Permanently delete the asset |
53
56
  <!-- generated:end -->
54
57
 
@@ -70,6 +73,14 @@ URL=$(myapi storage get-url <asset_id>)
70
73
  echo "<img src=\"$URL\" />"
71
74
  curl -O "$URL"
72
75
 
76
+ # Anything holding personal data: upload private, hand out signed links
77
+ myapi storage upload ./lease.pdf --private # no public URL is created
78
+ myapi storage sign <asset_id> --ttl 900 # 15-minute link to send
79
+
80
+ # Close an exposure on a file already uploaded public
81
+ myapi storage visibility <asset_id> private # plain URL stops serving now
82
+ myapi storage revoke-links <asset_id> # and kill links already sent
83
+
73
84
  # Clean up
74
85
  myapi storage delete <asset_id>
75
86
  ```
@@ -89,16 +100,18 @@ Both produce identical asset records — `list` doesn't distinguish.
89
100
 
90
101
  ## Notes
91
102
 
92
- - **Assets are public, permanently, with no auth.** Anyone with the URL can
93
- fetch it; there is no private mode, no signed URL, and no revocation. The id
94
- being long and random is **not** access control — treat the URL as public the
95
- moment it exists.
96
- - **Private assets exist as of 2026-07-28** upload with `visibility: private`,
97
- or `PATCH` an existing asset to close an exposure, which takes effect
98
- immediately. Fetch it with a signed URL (15 minutes default, 24 hours max);
99
- `revoke-links` kills every link already handed out, including unexpired ones.
100
- A private upload deliberately returns **no plain `url`**, because that URL
101
- does not serve the file and would look like the answer.
103
+ - **Public is the default, and public means forever with no credential.**
104
+ Anyone holding the URL can read it. A long random id is
105
+ **not** access control — treat the URL as public the moment it exists.
106
+ - **Private assets exist — use them for anything holding personal data.**
107
+ `storage upload --private` stores a file with no public URL;
108
+ `storage visibility <id> private` closes an exposure on one already uploaded,
109
+ and takes effect at once. Read a private asset back with
110
+ `storage sign <id> --ttl <seconds>` (default 900, max 86400) — the link
111
+ carries its own authorisation, so it can go to someone with no MyAPI account.
112
+ `storage revoke-links <id>` kills every link already handed out, including
113
+ unexpired ones. A private upload deliberately returns **no plain `url`**,
114
+ because that URL does not serve the file and would look like the answer.
102
115
  - **Encrypting before upload is still worth doing for the strictest cases.**
103
116
  Private assets protect against the internet; client-side encryption protects
104
117
  against the platform, and those are different threat models. A team shipping
@@ -107,25 +120,20 @@ Both produce identical asset records — `list` doesn't distinguish.
107
120
  - Delete is immediate and unrecoverable — run `myapi storage list` first to confirm the asset, pass `--org` explicitly, and pass `--yes` in non-interactive runs.
108
121
  - The URL is permanent until you `myapi storage delete <id>` — embed it freely.
109
122
 
123
+ ## HTTP (from deployed code)
110
124
 
111
- ## Calling this from deployed code (HTTP)
112
-
113
- The CLI is not what runs in production — a deployed function or container calls
114
- the HTTP API directly. That surface was previously only discoverable by
115
- grepping the CLI bundle, which cost one team an hour per slot.
116
-
125
+ <!-- http:start -->
126
+ <!-- generated by `npm run canonical-sync` — do not edit -->
117
127
  ```
118
- base https://api.mystorageapi.com ← not the gateway
119
- path /storage/orgs/{org_id}/assets/upload (multipart, field: file)
120
- auth Authorization: Bearer <api key>
121
- (inside a function: env.__MYAPI_KEY · inside a container: env.MYAPI_KEY)
122
- body multipart/form-data
123
- reply { "success": true, "data": …, "error": null, "meta": {…} }
124
- Unwrap `data`. On failure `success` is false and `error` is
125
- { code, message }.
128
+ base https://api.mystorageapi.com
129
+ path POST /storage/orgs/{org_id}/assets/upload
130
+ body multipart/form-data field name is `file`
131
+ auth Authorization: Bearer <key> (fn: env.__MYAPI_KEY · container: env.MYAPI_KEY)
132
+ reply { "success": true, "data": …, "error": null, "meta": {…} }
126
133
  ```
127
134
 
128
- **The org id goes in the PATH, not a header.** There is no `X-Org-Id`.
129
- **Base URLs differ per slot** — do not assume one host for everything.
135
+ - **Per-slot host** do not assume one host serves every slot.
136
+ - **Org id goes in the PATH** — there is no `X-Org-Id` header.
137
+ <!-- http:end -->
130
138
 
131
139
  Run `myapi storage --help` for full flag reference.
@@ -4,7 +4,7 @@ version: 1.0.0
4
4
  description: >
5
5
  Agent-task queue — file units of work, rank them, claim under a lease, then resolve, fail, or cancel. The agent-loop hot path.
6
6
  triggers: [task, task queue, agent loop, work queue, claim task, resolve task, lease, backlog, to-do, assignee]
7
- checksum: sha256-ceb6cdfffe465d8b0cd232eaa16868c1b8c8b10288f1cf9b4174fdd48a8d2c18
7
+ checksum: sha256-d674b4bc9a1cd49e7f9778e3d70418bee0496a85cf49e3381019b618bdca9994
8
8
  ---
9
9
 
10
10
  # MyTaskAPI
@@ -25,7 +25,7 @@ The loop is: **`list` → `get <id> --body` → `claim` → `resolve`/`fail`**.
25
25
 
26
26
  Task fields at creation: `description` (~100-token triage key), `body` (full Markdown), `importance`, `due`, `assignee` (emails them a magic link), `tags`, `depends_on` (immutable DAG — a task with unresolved deps starts blocked), `dedup_key` (idempotent), `resolve_on` (an event matcher — a matching platform event auto-resolves the task), `source`.
27
27
 
28
- **task vs workflow vs queue** — see `docs/orchestration-decision-guide.md`.
28
+ **task vs workflow vs queue** — see the section at the end of this skill.
29
29
  <!-- llm:end -->
30
30
 
31
31
  ## Commands
@@ -79,4 +79,37 @@ myapi task create "Ship once payment clears" \
79
79
  - `--origin <s>` — records what created the task, and filters `task list`.
80
80
  (Formerly `--source`, which still works and is undocumented.)
81
81
 
82
+ ## HTTP (from deployed code)
83
+
84
+ <!-- http:start -->
85
+ <!-- generated by `npm run canonical-sync` — do not edit -->
86
+ ```
87
+ base https://api.myapihq.com
88
+ path POST /task/orgs/{org_id}/tasks
89
+ auth Authorization: Bearer <key> (fn: env.__MYAPI_KEY · container: env.MYAPI_KEY)
90
+ reply { "success": true, "data": …, "error": null, "meta": {…} }
91
+ ```
92
+
93
+ - **Per-slot host** — do not assume one host serves every slot.
94
+ - **Org id goes in the PATH** — there is no `X-Org-Id` header.
95
+ <!-- http:end -->
96
+
97
+ ## workflow vs queue vs task
98
+
99
+ | If you are saying… | Use |
100
+ |---|---|
101
+ | "When this webhook arrives, do these steps." | **workflow** |
102
+ | "Run this reliably, eventually — retry it, don't block on it." | **queue** |
103
+ | "Someone (agent or human) needs to look at this and decide." | **task** |
104
+
105
+ **Retry is not the distinction** — workflow and queue both retry. What differs
106
+ is where the work runs: a workflow step runs inline during the delivery that
107
+ triggered it; a queue job runs asynchronously against an external
108
+ `consumer_url` under a concurrency cap. A task waits for a worker to `claim` it.
109
+
110
+ They chain one way: a workflow's `enqueue_job` step hands durable work to a
111
+ queue. And they listen to two different surfaces — workflow fires on inbound
112
+ **webhook deliveries**; task `resolve_on` matches the internal **platform
113
+ events** bus, which is not the CRM timeline.
114
+
82
115
  Run `myapi task --help` for the full flag reference.
@@ -4,7 +4,7 @@ version: 1.0.0
4
4
  description: >
5
5
  Stateful URL shortening service. Generate compact `myurlto.com` redirect links to long URLs. Often invoked implicitly by other backend services for outbound links.
6
6
  triggers: [shorten url, short link, url shortener, myurlto, redirect, short_code]
7
- checksum: sha256-2b83a7774da020adc3e61e411ff63b7ced7d9f160d22eb0a9291b701ad0fcf73
7
+ checksum: sha256-11285f6fe1a88115b4f7da4abe4aa0e7706e77e591673b8c5c6377712c0aff85
8
8
  ---
9
9
 
10
10
  # MyURLToAPI
@@ -52,4 +52,19 @@ curl -L "https://myurlto.com/example.com/8f2a1b9c"
52
52
  - Short codes are stable — once minted, they don't change.
53
53
  - Required: a non-empty `url`. `400` if missing.
54
54
 
55
+ ## HTTP (from deployed code)
56
+
57
+ <!-- http:start -->
58
+ <!-- generated by `npm run canonical-sync` — do not edit -->
59
+ ```
60
+ base https://api.myurlto.com
61
+ path POST /url/orgs/{org_id}/shorten
62
+ auth Authorization: Bearer <key> (fn: env.__MYAPI_KEY · container: env.MYAPI_KEY)
63
+ reply { "success": true, "data": …, "error": null, "meta": {…} }
64
+ ```
65
+
66
+ - **Per-slot host** — do not assume one host serves every slot.
67
+ - **Org id goes in the PATH** — there is no `X-Org-Id` header.
68
+ <!-- http:end -->
69
+
55
70
  Run `myapi url --help` for flag reference.
@@ -4,7 +4,7 @@ version: 1.0.0
4
4
  description: >
5
5
  Inbound webhook endpoints for non-funnel sources — Stripe, GitHub, custom services. Funnel forms use the my-funnel-api proxy.
6
6
  triggers: [webhook, inbound, receiver, stripe events, github webhook, slack notification, delivery, payload, event ingest]
7
- checksum: sha256-17b358d780333cabe76cb01df3be3c3f11db10a2b068449bcf9e10e2ed89393d
7
+ checksum: sha256-82459af69db91d535209978c09e011f5b893ba0f04f90d8b6a658058e0dc2374
8
8
  ---
9
9
 
10
10
  # MyWebhookAPI
@@ -56,9 +56,14 @@ myapi webhook deliveries
56
56
  myapi webhook delivery <delivery_id>
57
57
  ```
58
58
 
59
- ### End-to-end recipe — contact form on your site
59
+ ### End-to-end recipe — contact form on a site you host yourself
60
60
 
61
- A contact form on yoursite.com that sends a thank-you email and a Slack ping when submitted:
61
+ **Not for a MyAPI funnel.** This snippet puts the raw inbound URL in page
62
+ source, which is exactly what the scope note above tells you not to do on a
63
+ funnel. Use it only for a page MyAPI does not serve; on a funnel use
64
+ `myapi funnel form` instead.
65
+
66
+ A contact form that sends a thank-you email and a Slack ping when submitted:
62
67
 
63
68
  ```bash
64
69
  WID=$(myapi webhook create "contact-form" --json | jq -r .id)
@@ -108,4 +113,19 @@ The form sends `{name, email, message}` → webhook stores it → workflow runs
108
113
  `webhook deliveries` rather than silent.
109
114
  - `--description <text>` — free text, shown in `webhook list`.
110
115
 
116
+ ## HTTP (from deployed code)
117
+
118
+ <!-- http:start -->
119
+ <!-- generated by `npm run canonical-sync` — do not edit -->
120
+ ```
121
+ base https://api.mywebhookapi.com
122
+ path POST /webhook/orgs/{org_id}/endpoints
123
+ auth Authorization: Bearer <key> (fn: env.__MYAPI_KEY · container: env.MYAPI_KEY)
124
+ reply { "success": true, "data": …, "error": null, "meta": {…} }
125
+ ```
126
+
127
+ - **Per-slot host** — do not assume one host serves every slot.
128
+ - **Org id goes in the PATH** — there is no `X-Org-Id` header.
129
+ <!-- http:end -->
130
+
111
131
  Run `myapi webhook --help` for full flag reference.
@@ -4,7 +4,7 @@ version: 1.0.0
4
4
  description: >
5
5
  Run actions when a webhook fires. Trigger emails, Slack notifications, or HTTP calls in response to inbound webhook deliveries — without writing a backend.
6
6
  triggers: [workflow, automation, on webhook, send email on, slack notification, payload templating, drip, trigger, run]
7
- checksum: sha256-eddc70a8542c3cdfd01866f241ea283164e71fbe748426a13358d1c7ef635cb1
7
+ checksum: sha256-35b09cb26aa3781c78abdc2b362bdb8f0817a9580467bf94e65e0f2f335d502a
8
8
  ---
9
9
 
10
10
  # MyWorkflowAPI
@@ -97,11 +97,37 @@ myapi workflow enable <id>
97
97
  - Disable to stop firing without losing the configuration.
98
98
  - Deleting a workflow purges its run history; the webhook endpoint remains. Look before you delete: `myapi workflow list` first, pass `--org` explicitly; delete asks for confirmation — `--yes` required in non-interactive runs.
99
99
 
100
- ## See also
100
+ ## workflow vs queue vs task
101
101
 
102
- `workflow` is one of three orchestration slots. Use **workflow** to react to
103
- inbound webhooks; use **my-queue-api** for durable retried machine work; use
104
- **my-task-api** for work that needs an agent/human decision. Full comparison:
105
- `docs/orchestration-decision-guide.md`.
102
+ | If you are saying… | Use |
103
+ |---|---|
104
+ | "When this webhook arrives, do these steps." | **workflow** |
105
+ | "Run this reliably, eventually — retry it, don't block on it." | **queue** |
106
+ | "Someone (agent or human) needs to look at this and decide." | **task** |
107
+
108
+ **Retry is not the distinction** — workflow and queue both retry. What differs
109
+ is where the work runs: a workflow step runs inline during the delivery that
110
+ triggered it; a queue job runs asynchronously against an external
111
+ `consumer_url` under a concurrency cap.
112
+
113
+ They chain one way: the `enqueue_job` step above hands durable work to a queue.
114
+ And they listen to two different surfaces — workflow fires on inbound **webhook
115
+ deliveries**; task `resolve_on` matches the internal **platform events** bus,
116
+ which is not the CRM timeline.
117
+
118
+ ## HTTP (from deployed code)
119
+
120
+ <!-- http:start -->
121
+ <!-- generated by `npm run canonical-sync` — do not edit -->
122
+ ```
123
+ base https://api.myworkflowapi.com
124
+ path POST /workflow/orgs/{org_id}/workflows
125
+ auth Authorization: Bearer <key> (fn: env.__MYAPI_KEY · container: env.MYAPI_KEY)
126
+ reply { "success": true, "data": …, "error": null, "meta": {…} }
127
+ ```
128
+
129
+ - **Per-slot host** — do not assume one host serves every slot.
130
+ - **Org id goes in the PATH** — there is no `X-Org-Id` header.
131
+ <!-- http:end -->
106
132
 
107
133
  Run `myapi workflow --help` for full flag reference.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@myapihq/cli",
3
3
  "license": "Apache-2.0",
4
- "version": "2.10.0",
4
+ "version": "2.11.1",
5
5
  "description": "MyAPI command-line interface",
6
6
  "repository": {
7
7
  "type": "git",
@@ -46,7 +46,7 @@
46
46
  "lint:skills:strict": "node scripts/copy-skills.js && node scripts/lint-skills.js --strict"
47
47
  },
48
48
  "dependencies": {
49
- "@myapihq/sdk": "^2.10.0"
49
+ "@myapihq/sdk": "^2.11.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^25.6.0",