@myapihq/cli 1.3.13 → 2.0.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.
- package/dist/commands/account.d.ts +7 -1
- package/dist/commands/account.js +356 -18
- package/dist/commands/authproduct.d.ts +7 -0
- package/dist/commands/authproduct.js +286 -0
- package/dist/commands/billing.js +1 -1
- package/dist/commands/config.js +1 -1
- package/dist/commands/container.d.ts +1 -0
- package/dist/commands/container.js +115 -11
- package/dist/commands/domain.js +2 -2
- package/dist/commands/email/index.js +0 -13
- package/dist/commands/fn.d.ts +1 -0
- package/dist/commands/fn.js +64 -12
- package/dist/commands/keys.js +3 -3
- package/dist/commands/queue.d.ts +1 -0
- package/dist/commands/queue.js +10 -0
- package/dist/commands/setup.js +8 -8
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.js +11 -27
- package/dist/commands/storage.js +3 -1
- package/dist/commands/workflow.js +21 -6
- package/dist/completion.js +5 -4
- package/dist/config.js +1 -1
- package/dist/exposes.test.js +1 -2
- package/dist/index.js +31 -28
- package/dist/registrant.js +5 -5
- package/dist/sdk-queue.test.js +3 -2
- package/dist/skills/my-api-hq/SKILL.md +15 -12
- package/dist/skills/my-auth-api/README.md +33 -0
- package/dist/skills/my-auth-api/SKILL.md +112 -0
- package/dist/skills/my-auth-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-auth-api/openapi/.gitkeep +0 -0
- package/dist/skills/my-crm-api/SKILL.md +1 -1
- package/dist/skills/my-domain-api/SKILL.md +4 -4
- package/dist/skills/my-email-api/README.md +1 -1
- package/dist/skills/my-email-api/SKILL.md +7 -18
- package/dist/skills/my-email-api/claude/.claude-plugin/plugin.json +1 -1
- package/dist/skills/my-email-verify-api/SKILL.md +1 -1
- package/dist/skills/my-email-verify-api/claude/.claude-plugin/plugin.json +1 -1
- package/dist/skills/my-git-api/README.md +43 -0
- package/dist/skills/my-git-api/SKILL.md +115 -0
- package/dist/skills/my-git-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-git-api/openapi/.gitkeep +0 -0
- package/dist/skills/my-llm-api/claude/.claude-plugin/plugin.json +1 -1
- package/package.json +2 -2
- package/dist/commands/auth.d.ts +0 -11
- package/dist/commands/auth.js +0 -345
- package/dist/commands/email/campaign.d.ts +0 -4
- package/dist/commands/email/campaign.js +0 -200
package/dist/commands/fn.js
CHANGED
|
@@ -15,6 +15,8 @@ export const EXPOSES = [
|
|
|
15
15
|
];
|
|
16
16
|
export const SCHEMA = {
|
|
17
17
|
cron: 'string',
|
|
18
|
+
scope: 'string',
|
|
19
|
+
set: 'string',
|
|
18
20
|
};
|
|
19
21
|
// Backend: Story 1 (function CRUD + scoped key) and Story 2/4/5 (deploy a
|
|
20
22
|
// JS bundle to Cloudflare Workers, list runs, set env secrets).
|
|
@@ -67,6 +69,14 @@ export async function create(flags) {
|
|
|
67
69
|
};
|
|
68
70
|
if (cron)
|
|
69
71
|
payload.cron_schedule = cron;
|
|
72
|
+
// --scope narrows the minted key's slot grants. Repeatable, but the flag
|
|
73
|
+
// parser keeps only the last occurrence, so we also accept a comma-joined
|
|
74
|
+
// list (e.g. --scope email,storage). Grants can never exceed the caller's.
|
|
75
|
+
if (typeof flags.scope === 'string') {
|
|
76
|
+
const scopes = flags.scope.split(',').map(s => s.trim()).filter(Boolean);
|
|
77
|
+
if (scopes.length > 0)
|
|
78
|
+
payload.scopes = scopes;
|
|
79
|
+
}
|
|
70
80
|
const result = await sdkFn.createFunction(config.api_key, orgId, payload);
|
|
71
81
|
success(`Function created: ${result.function.id}`);
|
|
72
82
|
info(`Name: ${result.function.name}`);
|
|
@@ -77,7 +87,8 @@ export async function create(flags) {
|
|
|
77
87
|
info('');
|
|
78
88
|
info(`Scoped API key (returned once — save it if you need it):`);
|
|
79
89
|
info(` ${result.scoped_api_key}`);
|
|
80
|
-
|
|
90
|
+
const scopeNote = payload.scopes && payload.scopes.length > 0 ? `slots: ${payload.scopes.join(', ')}` : 'scopes: slot_call';
|
|
91
|
+
info(` (id: ${result.scoped_api_key_id}; ${scopeNote}; rejected at /hq/*, /admin/*, /internal/*)`);
|
|
81
92
|
if (!result.function.invocation_url) {
|
|
82
93
|
info('');
|
|
83
94
|
banner(`Next: deploy code with myapi fn deploy ${result.function.id} <bundle.js>`);
|
|
@@ -153,14 +164,48 @@ export async function deploy(id, bundlePath, flags) {
|
|
|
153
164
|
info(`Scoped API key was rotated. New value (returned once — save it if you need it):`);
|
|
154
165
|
info(` ${result.scoped_api_key}`);
|
|
155
166
|
}
|
|
156
|
-
//
|
|
167
|
+
// _parseSetPairs parses `--set K=V` entries into a map. Accepts a single
|
|
168
|
+
// string (comma-joined: K=V,K2=V2) or an array of strings (when the flag is
|
|
169
|
+
// repeated and the parser preserves them). Returns the map or an error
|
|
170
|
+
// message string (pure form, for tests).
|
|
171
|
+
export function _parseSetPairs(raw) {
|
|
172
|
+
const entries = [];
|
|
173
|
+
for (const chunk of Array.isArray(raw) ? raw : [raw]) {
|
|
174
|
+
for (const pair of chunk.split(',').map(s => s.trim()).filter(Boolean))
|
|
175
|
+
entries.push(pair);
|
|
176
|
+
}
|
|
177
|
+
const env = {};
|
|
178
|
+
for (const pair of entries) {
|
|
179
|
+
const eq = pair.indexOf('=');
|
|
180
|
+
if (eq < 1)
|
|
181
|
+
return `Invalid --set entry "${pair}". Use KEY=VALUE.`;
|
|
182
|
+
env[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
183
|
+
}
|
|
184
|
+
return env;
|
|
185
|
+
}
|
|
186
|
+
// env sets Worker Secret(s) (Stripe key, etc.) on a deployed function.
|
|
187
|
+
// Single form: myapi fn env <id> <name> <value>
|
|
188
|
+
// Bulk form: myapi fn env <id> --set K=V[,K2=V2 ...]
|
|
157
189
|
export async function setEnv(id, name, value, flags) {
|
|
158
190
|
const config = requireConfig();
|
|
159
|
-
const orgId = requireOrg(flags, config, 'myapi fn env <id> <name> <value> [--org <id>]');
|
|
191
|
+
const orgId = requireOrg(flags, config, 'myapi fn env <id> <name> <value> | --set K=V [--org <id>]');
|
|
160
192
|
if (!id)
|
|
161
|
-
error('Missing id.\nUsage: myapi fn env <id> <name> <value>');
|
|
193
|
+
error('Missing id.\nUsage: myapi fn env <id> <name> <value> (or --set K=V for bulk)');
|
|
194
|
+
// Bulk path: one --set string (comma-joined) or repeated --set occurrences.
|
|
195
|
+
if (flags.set !== undefined && flags.set !== true) {
|
|
196
|
+
const env = _parseSetPairs(flags.set);
|
|
197
|
+
if (typeof env === 'string')
|
|
198
|
+
error(env);
|
|
199
|
+
if (Object.keys(env).length === 0)
|
|
200
|
+
error('No secrets given. Usage: myapi fn env <id> --set KEY=VALUE');
|
|
201
|
+
const result = await sdkFn.setFunctionEnvBulk(config.api_key, orgId, id, env);
|
|
202
|
+
success(`Set ${result.set} secret${result.set === 1 ? '' : 's'} on function ${id}`);
|
|
203
|
+
info('Values are encrypted at rest by Cloudflare and never stored or echoed by MyAPI.');
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Single-secret path (original form).
|
|
162
207
|
if (!name)
|
|
163
|
-
error('Missing secret name.\nUsage: myapi fn env <id> <name> <value>');
|
|
208
|
+
error('Missing secret name.\nUsage: myapi fn env <id> <name> <value> (or --set K=V for bulk)');
|
|
164
209
|
if (value === undefined)
|
|
165
210
|
error('Missing secret value.\nUsage: myapi fn env <id> <name> <value>');
|
|
166
211
|
await sdkFn.setFunctionEnv(config.api_key, orgId, id, name, value);
|
|
@@ -191,7 +236,7 @@ export async function runs(id, flags) {
|
|
|
191
236
|
}
|
|
192
237
|
// ── Dispatcher ───────────────────────────────────────────────────────────────
|
|
193
238
|
const SUBCOMMAND_USAGE = {
|
|
194
|
-
'create': `myapi fn create --name <name> [--cron <expr>] [--org <id>]
|
|
239
|
+
'create': `myapi fn create --name <name> [--cron <expr>] [--scope <slot>[,<slot>...]] [--org <id>]
|
|
195
240
|
|
|
196
241
|
Persists a function record + issues a scoped API key. Deploy code separately
|
|
197
242
|
with "myapi fn deploy".
|
|
@@ -200,9 +245,15 @@ Triggers:
|
|
|
200
245
|
(default) HTTP — function gets a public invocation URL once deployed.
|
|
201
246
|
--cron <expr> Cron — function runs on the schedule (e.g. "0 8 * * *").
|
|
202
247
|
|
|
248
|
+
Scoping:
|
|
249
|
+
--scope <slot> Narrow the minted key's slot grants (comma-separated list,
|
|
250
|
+
e.g. --scope email,storage). Omit to inherit your grants.
|
|
251
|
+
The key can never out-reach the credential that created it.
|
|
252
|
+
|
|
203
253
|
Examples:
|
|
204
254
|
myapi fn create --name my-app-api
|
|
205
255
|
myapi fn create --name daily-report --cron "0 8 * * *"
|
|
256
|
+
myapi fn create --name mailer --scope email,storage
|
|
206
257
|
|
|
207
258
|
The response returns the scoped API key ONCE. It lets the function call
|
|
208
259
|
other MyAPI slots with its own permissions (scopes=slot_call; rejected at
|
|
@@ -218,13 +269,14 @@ once. After deploy the function has a live invocation URL.
|
|
|
218
269
|
Example:
|
|
219
270
|
myapi fn deploy <id> ./dist/bundle.js`,
|
|
220
271
|
'env': `myapi fn env <id> <name> <value> [--org <id>]
|
|
272
|
+
myapi fn env <id> --set KEY=VALUE[,KEY2=VALUE2 ...] [--org <id>]
|
|
221
273
|
|
|
222
|
-
Sets
|
|
223
|
-
a deployed function.
|
|
224
|
-
MyAPI or echoed back. The function must already be deployed.
|
|
274
|
+
Sets one or more secrets (Stripe key, API token, ...) as Cloudflare Worker
|
|
275
|
+
Secrets on a deployed function. Values are encrypted at rest and never stored
|
|
276
|
+
in MyAPI or echoed back. The function must already be deployed.
|
|
225
277
|
|
|
226
|
-
|
|
227
|
-
myapi fn env <id> STRIPE_KEY
|
|
278
|
+
Single: myapi fn env <id> STRIPE_KEY sk_live_...
|
|
279
|
+
Bulk: myapi fn env <id> --set STRIPE_KEY=sk_live_...,WEBHOOK_SECRET=whsec_...`,
|
|
228
280
|
'runs': `myapi fn runs <id> [--org <id>] [--json]
|
|
229
281
|
|
|
230
282
|
Lists recent invocation records (most recent first, up to 100).`,
|
|
@@ -242,7 +294,7 @@ Subcommands:
|
|
|
242
294
|
create Register a function and get its scoped API key (returned once)
|
|
243
295
|
delete <id> Soft-delete and revoke its scoped API key
|
|
244
296
|
deploy <id> <file> Upload a JS bundle and go live
|
|
245
|
-
env <id> <k> <v> Set a Worker Secret on a deployed function
|
|
297
|
+
env <id> <k> <v> Set a Worker Secret (or --set K=V for bulk) on a deployed function
|
|
246
298
|
get <id> Inspect a function
|
|
247
299
|
list List functions in your org
|
|
248
300
|
runs <id> List recent invocation records
|
package/dist/commands/keys.js
CHANGED
|
@@ -162,7 +162,7 @@ export async function revokeAll(flags) {
|
|
|
162
162
|
const res = await hq.revokeAllKeys(config.api_key, kind);
|
|
163
163
|
success(`Revoked ${res.revoked} key(s).`);
|
|
164
164
|
if (!kind) {
|
|
165
|
-
info('Your current key was revoked too — re-authenticate with: myapi
|
|
165
|
+
info('Your current key was revoked too — re-authenticate with: myapi account setup');
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
// ── Dispatcher ───────────────────────────────────────────────────────────────
|
|
@@ -186,7 +186,7 @@ create flags:
|
|
|
186
186
|
--org <org_id> Lock the key to one org. Omit for account-wide.
|
|
187
187
|
--spend-cap <usd> Per-key spend ceiling in dollars, e.g. --spend-cap 50
|
|
188
188
|
|
|
189
|
-
${prefix === 'keys' ? 'Alias for: myapi
|
|
189
|
+
${prefix === 'keys' ? 'Alias for: myapi account api-keys' : 'Alias: myapi keys <subcommand>'}`;
|
|
190
190
|
}
|
|
191
191
|
function subcommandUsage(prefix) {
|
|
192
192
|
return {
|
|
@@ -203,7 +203,7 @@ Omitting --grant mints an unrestricted key. --grant slots: ${[...hq.GRANTABLE_SL
|
|
|
203
203
|
'revoke-all': `myapi ${prefix} revoke-all [--kind function|manual|account] [--yes]
|
|
204
204
|
|
|
205
205
|
Kill switch. With no --kind, revokes EVERY active key in the account — including
|
|
206
|
-
the key this CLI is authenticated with (recovery: myapi
|
|
206
|
+
the key this CLI is authenticated with (recovery: myapi account setup). --kind
|
|
207
207
|
narrows it to one provenance class. Destructive — confirms unless --yes.`,
|
|
208
208
|
};
|
|
209
209
|
}
|
package/dist/commands/queue.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ export declare function get(name: string, flags: Flags): Promise<void>;
|
|
|
11
11
|
export declare function enqueue(name: string, flags: Flags): Promise<void>;
|
|
12
12
|
export declare function jobs(name: string, flags: Flags): Promise<void>;
|
|
13
13
|
export declare function job(jobId: string, flags: Flags): Promise<void>;
|
|
14
|
+
export declare function del(name: string, flags: Flags): Promise<void>;
|
|
14
15
|
export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
|
package/dist/commands/queue.js
CHANGED
|
@@ -165,11 +165,19 @@ export async function job(jobId, flags) {
|
|
|
165
165
|
if (j.last_error)
|
|
166
166
|
info(`Error: ${j.last_error}`);
|
|
167
167
|
}
|
|
168
|
+
export async function del(name, flags) {
|
|
169
|
+
const config = requireConfig();
|
|
170
|
+
const orgId = requireOrg(flags, config, 'myapi queue delete <name> [--org <id>]');
|
|
171
|
+
requireArg(name, 'name', 'myapi queue delete <name>');
|
|
172
|
+
await sdkQueue.deleteQueue(config.api_key, orgId, name);
|
|
173
|
+
success(`Deleted queue: ${name}`);
|
|
174
|
+
}
|
|
168
175
|
// ── Dispatcher ───────────────────────────────────────────────────────────────
|
|
169
176
|
const SUBCOMMAND_USAGE = {
|
|
170
177
|
'create': 'myapi queue create <name> --consumer-url <url> [--max-attempts <n>] [--max-concurrency <n>] [--org <id>]',
|
|
171
178
|
'list': 'myapi queue list [--org <id>] [--json]',
|
|
172
179
|
'get': 'myapi queue get <name> [--org <id>] [--json]',
|
|
180
|
+
'delete': 'myapi queue delete <name> [--org <id>]',
|
|
173
181
|
'enqueue': 'myapi queue enqueue <name> --payload <json> [--dedup-key <k>] [--delay <seconds>] [--depends-on <id,id>] [--org <id>]',
|
|
174
182
|
'jobs': 'myapi queue jobs <name> [--status <s>] [--limit <n>] [--org <id>] [--json]',
|
|
175
183
|
'job': 'myapi queue job <job_id> [--org <id>] [--json]',
|
|
@@ -185,6 +193,7 @@ Queues:
|
|
|
185
193
|
create <name> Create a queue (--consumer-url, --max-attempts, --max-concurrency)
|
|
186
194
|
list List queues
|
|
187
195
|
get <name> Show a queue's policy
|
|
196
|
+
delete <name> Delete a queue (and its jobs)
|
|
188
197
|
|
|
189
198
|
Jobs:
|
|
190
199
|
enqueue <name> Enqueue a job (--payload, --dedup-key, --delay, --depends-on)
|
|
@@ -208,6 +217,7 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
|
208
217
|
case 'create': return create(args[0], flags);
|
|
209
218
|
case 'list': return list(flags);
|
|
210
219
|
case 'get': return get(args[0], flags);
|
|
220
|
+
case 'delete': return del(args[0], flags);
|
|
211
221
|
case 'enqueue': return enqueue(args[0], flags);
|
|
212
222
|
case 'jobs': return jobs(args[0], flags);
|
|
213
223
|
case 'job': return job(args[0], flags);
|
package/dist/commands/setup.js
CHANGED
|
@@ -172,10 +172,10 @@ async function anonymousFlow() {
|
|
|
172
172
|
// ---------------------------------------------------------------------------
|
|
173
173
|
// Main setup command
|
|
174
174
|
// ---------------------------------------------------------------------------
|
|
175
|
-
const IMPORT_KEY_HELP = `Usage: myapi
|
|
175
|
+
const IMPORT_KEY_HELP = `Usage: myapi account import-key <api_key> [--install-skills] [--no-skills]
|
|
176
176
|
|
|
177
177
|
Imports an existing API key non-interactively. Use this in CI, Docker, or any
|
|
178
|
-
environment where the interactive "myapi
|
|
178
|
+
environment where the interactive "myapi account setup" flow is not practical.
|
|
179
179
|
|
|
180
180
|
The key is validated against the API before being saved. Your default org and
|
|
181
181
|
funnel are auto-detected from the account and written to the local config.
|
|
@@ -185,9 +185,9 @@ Flags:
|
|
|
185
185
|
--no-skills Skip skills installation even if previously installed
|
|
186
186
|
|
|
187
187
|
Examples:
|
|
188
|
-
myapi
|
|
189
|
-
myapi
|
|
190
|
-
const SETUP_HELP = `Usage: myapi
|
|
188
|
+
myapi account import-key hq_live_xxxxxxxxxxxxxxxxxxxx
|
|
189
|
+
myapi account import-key hq_live_xxxxxxxxxxxxxxxxxxxx --install-skills`;
|
|
190
|
+
const SETUP_HELP = `Usage: myapi account setup [--anonymous] [--yes] [--install-skills|--no-skills]
|
|
191
191
|
|
|
192
192
|
Configures your account and stores your default org and funnel so you don't
|
|
193
193
|
need to pass --org or --funnel on every command.
|
|
@@ -197,7 +197,7 @@ Flags:
|
|
|
197
197
|
--yes Skip confirmation prompts
|
|
198
198
|
--install-skills Auto-install skills pack
|
|
199
199
|
--no-skills Skip skills installation`;
|
|
200
|
-
// myapi
|
|
200
|
+
// myapi account import-key <key> — non-interactively import a raw API key.
|
|
201
201
|
export async function importKey(apiKey, flags) {
|
|
202
202
|
if (flags.help || !apiKey) {
|
|
203
203
|
info(IMPORT_KEY_HELP);
|
|
@@ -278,7 +278,7 @@ export async function setup(flags = {}) {
|
|
|
278
278
|
}
|
|
279
279
|
else {
|
|
280
280
|
info('› Continuing as anonymous — sites ship to *.makeautonomous.com');
|
|
281
|
-
info(' (Anonymous accounts have $0 credit. Link an email anytime to unlock $5 free credit and paid actions: myapi
|
|
281
|
+
info(' (Anonymous accounts have $0 credit. Link an email anytime to unlock $5 free credit and paid actions: myapi account link <email>)');
|
|
282
282
|
const data = await anonymousFlow();
|
|
283
283
|
apiKey = data.api_key;
|
|
284
284
|
accountId = data.account_id;
|
|
@@ -320,7 +320,7 @@ export async function setup(flags = {}) {
|
|
|
320
320
|
success('› Setup complete. No card, no email, ready to ship.');
|
|
321
321
|
if (subdomainUrl)
|
|
322
322
|
info(`› Your funnel: ${subdomainUrl}`);
|
|
323
|
-
info('› Upgrade anytime — myapi
|
|
323
|
+
info('› Upgrade anytime — myapi account link');
|
|
324
324
|
}
|
|
325
325
|
else {
|
|
326
326
|
success(`› Setup complete. Org ${defaultOrg} ready · $5.00 free credits added.`);
|
|
@@ -3,5 +3,5 @@ import { type Flags } from '../helpers.js';
|
|
|
3
3
|
import type { Exposes } from '../exposes.js';
|
|
4
4
|
export declare const EXPOSES: Exposes;
|
|
5
5
|
export declare const SCHEMA: FlagSchema;
|
|
6
|
-
export declare const STATUS_HELP = "Usage: myapi status [--org <id>] [--json]\n\nSingle-screen view of your account and what's running in the default org:\nidentity, balance, free-tier usage, plus resource counts across domains,\nfunnels,
|
|
6
|
+
export declare const STATUS_HELP = "Usage: myapi status [--org <id>] [--json]\n\nSingle-screen view of your account and what's running in the default org:\nidentity, balance, free-tier usage, plus resource counts across domains,\nfunnels, webhooks, and workflows. Useful before a\nco-build session or when checking \"what's mid-flight\" without running six\nlist commands.\n\nEach section is best-effort \u2014 a failing service is shown as \"\u2014\", not an\nerror, so the rest of the snapshot still prints.\n";
|
|
7
7
|
export declare function run(_subcommand: string | undefined, _args: string[], flags?: Flags): Promise<void>;
|
package/dist/commands/status.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hq, domain, funnel,
|
|
1
|
+
import { hq, domain, funnel, webhook, workflow, MyApiError } from '@myapihq/sdk';
|
|
2
2
|
// listMailboxes is omitted from this view: the backend requires a domain or
|
|
3
3
|
// filter, so there is no global "all mailboxes in this org" call. Use
|
|
4
4
|
// `myapi email mailbox list --domain <d>` for per-domain detail.
|
|
@@ -7,9 +7,8 @@ import { info, error, printJson } from '../output.js';
|
|
|
7
7
|
export const EXPOSES = [
|
|
8
8
|
'GET /hq/billing/balance',
|
|
9
9
|
'GET /hq/account/free-tier',
|
|
10
|
-
'GET /domain/orgs/{org_id}/
|
|
10
|
+
'GET /domain/orgs/{org_id}/list',
|
|
11
11
|
'GET /funnel/orgs/{org_id}/funnels',
|
|
12
|
-
'GET /email/orgs/{org_id}/campaigns',
|
|
13
12
|
'GET /webhook/orgs/{org_id}/endpoints',
|
|
14
13
|
'GET /workflow/orgs/{org_id}/workflows',
|
|
15
14
|
];
|
|
@@ -20,7 +19,7 @@ export const STATUS_HELP = `Usage: myapi status [--org <id>] [--json]
|
|
|
20
19
|
|
|
21
20
|
Single-screen view of your account and what's running in the default org:
|
|
22
21
|
identity, balance, free-tier usage, plus resource counts across domains,
|
|
23
|
-
funnels,
|
|
22
|
+
funnels, webhooks, and workflows. Useful before a
|
|
24
23
|
co-build session or when checking "what's mid-flight" without running six
|
|
25
24
|
list commands.
|
|
26
25
|
|
|
@@ -37,7 +36,7 @@ export async function run(_subcommand, _args, flags = {}) {
|
|
|
37
36
|
}
|
|
38
37
|
const config = loadConfig();
|
|
39
38
|
if (!config?.api_key)
|
|
40
|
-
error('Not configured. Run: myapi
|
|
39
|
+
error('Not configured. Run: myapi account setup');
|
|
41
40
|
const orgId = flags.org ?? config.default_org;
|
|
42
41
|
// Account-level info works without an org; org-scoped resources are skipped if none set.
|
|
43
42
|
const orgKnown = Boolean(orgId);
|
|
@@ -55,20 +54,18 @@ export async function run(_subcommand, _args, flags = {}) {
|
|
|
55
54
|
// the snapshot as untrustworthy rather than silently printing local config.
|
|
56
55
|
const keyRejected = accountResults.some(r => r.status === 'rejected' && r.reason instanceof MyApiError && r.reason.status === 401);
|
|
57
56
|
// Org-scoped (skipped if no default org set).
|
|
58
|
-
let domains = null, funnels = null,
|
|
57
|
+
let domains = null, funnels = null, webhooks = null, workflows = null;
|
|
59
58
|
if (orgKnown) {
|
|
60
59
|
const orgResults = await Promise.allSettled([
|
|
61
60
|
domain.listDomains(config.api_key, orgId),
|
|
62
61
|
funnel.listFunnels(config.api_key, orgId),
|
|
63
|
-
email.listCampaigns(config.api_key, orgId),
|
|
64
62
|
webhook.listEndpoints(config.api_key, orgId),
|
|
65
63
|
workflow.listWorkflows(config.api_key, orgId),
|
|
66
64
|
]);
|
|
67
65
|
domains = unwrap(orgResults[0]);
|
|
68
66
|
funnels = unwrap(orgResults[1]);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
workflows = unwrap(orgResults[4]);
|
|
67
|
+
webhooks = unwrap(orgResults[2]);
|
|
68
|
+
workflows = unwrap(orgResults[3]);
|
|
72
69
|
}
|
|
73
70
|
if (flags.json) {
|
|
74
71
|
printJson({
|
|
@@ -83,13 +80,13 @@ export async function run(_subcommand, _args, flags = {}) {
|
|
|
83
80
|
balance,
|
|
84
81
|
free_tier: freeTier,
|
|
85
82
|
org_resources: orgKnown ? {
|
|
86
|
-
domains, funnels,
|
|
83
|
+
domains, funnels, webhooks, workflows,
|
|
87
84
|
} : null,
|
|
88
85
|
});
|
|
89
86
|
return;
|
|
90
87
|
}
|
|
91
88
|
if (keyRejected) {
|
|
92
|
-
info('⚠ The backend rejected your API key. Values may be stale — run: myapi
|
|
89
|
+
info('⚠ The backend rejected your API key. Values may be stale — run: myapi account setup');
|
|
93
90
|
info('');
|
|
94
91
|
}
|
|
95
92
|
// ── Identity ──────────────────────────────────────────────────────────────
|
|
@@ -101,7 +98,7 @@ export async function run(_subcommand, _args, flags = {}) {
|
|
|
101
98
|
info(`Type: ${config.is_anonymous ? 'anonymous' : 'registered'}`);
|
|
102
99
|
info(`Balance: ${balance ? `${balance.balance_display} | Credits: ${balance.credits_display}` : '—'}`);
|
|
103
100
|
if (config.is_anonymous) {
|
|
104
|
-
info(' → Link an email to unlock $5 free credit + paid actions: myapi
|
|
101
|
+
info(' → Link an email to unlock $5 free credit + paid actions: myapi account link <email>');
|
|
105
102
|
}
|
|
106
103
|
if (Array.isArray(freeTier) && freeTier.length > 0) {
|
|
107
104
|
const parts = freeTier
|
|
@@ -114,7 +111,7 @@ export async function run(_subcommand, _args, flags = {}) {
|
|
|
114
111
|
info('');
|
|
115
112
|
info('Resources:');
|
|
116
113
|
if (!orgKnown) {
|
|
117
|
-
info(' (set a default org to see domains/funnels/
|
|
114
|
+
info(' (set a default org to see domains/funnels/webhooks/workflows)');
|
|
118
115
|
return;
|
|
119
116
|
}
|
|
120
117
|
if (domains) {
|
|
@@ -126,19 +123,6 @@ export async function run(_subcommand, _args, flags = {}) {
|
|
|
126
123
|
else
|
|
127
124
|
info(' Domains: —');
|
|
128
125
|
info(` Funnels: ${funnels ? funnels.length : '—'}`);
|
|
129
|
-
if (campaigns) {
|
|
130
|
-
// Campaigns: backend statuses include 'draft', 'active', 'paused', 'completed'.
|
|
131
|
-
// Surface counts for the two states that matter mid-flight.
|
|
132
|
-
const active = campaigns.filter(c => /active|running/i.test(c.status)).length;
|
|
133
|
-
const paused = campaigns.filter(c => /paused/i.test(c.status)).length;
|
|
134
|
-
const extras = [
|
|
135
|
-
active > 0 ? `${active} active` : null,
|
|
136
|
-
paused > 0 ? `${paused} paused` : null,
|
|
137
|
-
].filter(Boolean).join(', ');
|
|
138
|
-
info(` Campaigns: ${campaigns.length}${extras ? ` (${extras})` : ''}`);
|
|
139
|
-
}
|
|
140
|
-
else
|
|
141
|
-
info(' Campaigns: —');
|
|
142
126
|
info(` Webhooks: ${webhooks ? webhooks.length : '—'}`);
|
|
143
127
|
if (workflows) {
|
|
144
128
|
const enabled = workflows.filter(w => w.enabled).length;
|
package/dist/commands/storage.js
CHANGED
|
@@ -26,6 +26,8 @@ const EXT_TO_CT = {
|
|
|
26
26
|
'.jpeg': 'image/jpeg',
|
|
27
27
|
'.gif': 'image/gif',
|
|
28
28
|
'.webp': 'image/webp',
|
|
29
|
+
'.svg': 'image/svg+xml',
|
|
30
|
+
'.pdf': 'application/pdf',
|
|
29
31
|
'.mp4': 'video/mp4',
|
|
30
32
|
'.webm': 'video/webm',
|
|
31
33
|
};
|
|
@@ -64,7 +66,7 @@ async function upload(filePath, flags) {
|
|
|
64
66
|
const ext = extname(filePath).toLowerCase();
|
|
65
67
|
const contentType = EXT_TO_CT[ext];
|
|
66
68
|
if (!contentType) {
|
|
67
|
-
error(`Unsupported file extension "${ext}". Supported: ${Object.keys(EXT_TO_CT).join(', ')}.\
|
|
69
|
+
error(`Unsupported file extension "${ext}". Supported: ${Object.keys(EXT_TO_CT).join(', ')}.\nFor other types, host the file and use "myapi storage ingest <url>".`);
|
|
68
70
|
}
|
|
69
71
|
let data;
|
|
70
72
|
try {
|
|
@@ -19,6 +19,8 @@ export const SCHEMA = {
|
|
|
19
19
|
'endpoint-id': 'string',
|
|
20
20
|
steps: 'string',
|
|
21
21
|
'no-enable': 'boolean',
|
|
22
|
+
limit: 'number',
|
|
23
|
+
cursor: 'string',
|
|
22
24
|
};
|
|
23
25
|
// Mirrors the backend's SupportedStepTypes list. Both alias and underscore
|
|
24
26
|
// forms are accepted by the workflow runner. Keep this in sync if the
|
|
@@ -279,18 +281,27 @@ export async function del(id, flags) {
|
|
|
279
281
|
}
|
|
280
282
|
export async function runs(id, flags) {
|
|
281
283
|
const config = requireConfig();
|
|
282
|
-
const orgId = requireOrg(flags, config, 'myapi workflow runs <id> [--org <id>]');
|
|
284
|
+
const orgId = requireOrg(flags, config, 'myapi workflow runs <id> [--limit <n>] [--cursor <id>] [--org <id>]');
|
|
283
285
|
if (!id)
|
|
284
|
-
error('Missing required arguments.\nUsage: myapi workflow runs <workflow_id> [--org <id>]');
|
|
285
|
-
const
|
|
286
|
+
error('Missing required arguments.\nUsage: myapi workflow runs <workflow_id> [--limit <n>] [--cursor <id>] [--org <id>]');
|
|
287
|
+
const opts = {};
|
|
288
|
+
if (typeof flags.limit === 'number')
|
|
289
|
+
opts.limit = flags.limit;
|
|
290
|
+
if (typeof flags.cursor === 'string')
|
|
291
|
+
opts.cursor = flags.cursor;
|
|
292
|
+
const page = await sdkWorkflow.listWorkflowRuns(config.api_key, orgId, id, opts);
|
|
286
293
|
if (flags.json) {
|
|
287
|
-
printJson(
|
|
294
|
+
printJson(page);
|
|
288
295
|
return;
|
|
289
296
|
}
|
|
290
|
-
printTable(
|
|
297
|
+
printTable(page.runs.map(summarizeRun), {
|
|
291
298
|
flags,
|
|
292
299
|
empty: 'No runs yet for this workflow.',
|
|
293
300
|
});
|
|
301
|
+
if (page.next_cursor) {
|
|
302
|
+
info('');
|
|
303
|
+
info(`More runs available. Next page: myapi workflow runs ${id} --cursor ${page.next_cursor}`);
|
|
304
|
+
}
|
|
294
305
|
}
|
|
295
306
|
export async function getRun(runId, flags) {
|
|
296
307
|
const config = requireConfig();
|
|
@@ -360,7 +371,11 @@ See the my-workflow-api skill for the full form-to-email recipe.`,
|
|
|
360
371
|
'enable': 'myapi workflow enable <id> [--org <id>]',
|
|
361
372
|
'disable': 'myapi workflow disable <id> [--org <id>]',
|
|
362
373
|
'delete': 'myapi workflow delete <id> [--org <id>]',
|
|
363
|
-
'runs':
|
|
374
|
+
'runs': `myapi workflow runs <workflow_id> [--limit <n>] [--cursor <id>] [--org <id>] [--json]
|
|
375
|
+
|
|
376
|
+
Lists recent runs, newest first (keyset-paginated). --limit is 1-500
|
|
377
|
+
(default 100). When more pages exist, the next cursor is printed; pass it
|
|
378
|
+
back with --cursor to fetch the following page.`,
|
|
364
379
|
'get-run': 'myapi workflow get-run <run_id> [--org <id>]',
|
|
365
380
|
};
|
|
366
381
|
export async function run(subcommand, args, flags) {
|
package/dist/completion.js
CHANGED
|
@@ -35,15 +35,16 @@ export const COMMANDS = [
|
|
|
35
35
|
// command → subcommands, for `myapi <command> <TAB>`. Mirrors each
|
|
36
36
|
// command's dispatcher; commands absent here take no subcommand.
|
|
37
37
|
export const SUBCOMMANDS = {
|
|
38
|
-
account: ['mailing-address'],
|
|
39
|
-
|
|
38
|
+
account: ['setup', 'import-key', 'whoami', 'link', 'switch', 'install-skills', 'config', 'registrant', 'api-keys', 'keys', 'mailing-address'],
|
|
39
|
+
// The end-user auth product. Operator/account commands live under `account`.
|
|
40
|
+
auth: ['tenant', 'client', 'usage', 'domain'],
|
|
40
41
|
org: ['create', 'delete', 'get', 'import', 'list', 'sync-brand', 'update'],
|
|
41
42
|
billing: ['balance', 'history', 'usage', 'setup', 'topup', 'spend-cap'],
|
|
42
43
|
domain: ['assign', 'check', 'email-setup', 'import', 'list', 'mail-server-resync', 'records', 'register', 'renew', 'retry-provisioning', 'settings', 'status'],
|
|
43
44
|
funnel: ['create', 'delete', 'get', 'list', 'pages', 'publish', 'push', 'verify'],
|
|
44
45
|
webhook: ['create', 'delete', 'delivery', 'list', 'update'],
|
|
45
46
|
workflow: ['create', 'delete', 'disable', 'enable', 'get', 'get-run', 'list', 'runs', 'update'],
|
|
46
|
-
email: ['mailbox', 'message', 'warmup', 'template', '
|
|
47
|
+
email: ['mailbox', 'message', 'warmup', 'template', 'verify'],
|
|
47
48
|
image: ['delete', 'generate', 'get', 'get-url', 'list', 'models'],
|
|
48
49
|
storage: ['delete', 'get', 'get-url', 'ingest', 'list', 'upload'],
|
|
49
50
|
pixel: ['audience', 'events', 'identity', 'interactions', 'visits'],
|
|
@@ -60,7 +61,7 @@ export const SUBCOMMANDS = {
|
|
|
60
61
|
payments: ['connect', 'status', 'charge', 'list', 'get', 'refund'],
|
|
61
62
|
container: ['create', 'deploy', 'list', 'get', 'logs', 'domain', 'delete'],
|
|
62
63
|
git: ['create', 'list', 'get', 'delete', 'refs', 'log', 'show', 'tree', 'blob', 'diff', 'commit', 'create-branch', 'delete-branch', 'tag', 'merge', 'repack'],
|
|
63
|
-
queue: ['create', 'list', 'get', 'enqueue', 'jobs', 'job'],
|
|
64
|
+
queue: ['create', 'list', 'get', 'delete', 'enqueue', 'jobs', 'job'],
|
|
64
65
|
task: ['create', 'list', 'get', 'claim', 'extend', 'resolve', 'fail', 'cancel'],
|
|
65
66
|
completion: ['install', 'uninstall'],
|
|
66
67
|
};
|
package/dist/config.js
CHANGED
|
@@ -98,7 +98,7 @@ export function listAccounts() {
|
|
|
98
98
|
export function requireConfig() {
|
|
99
99
|
const config = loadConfig();
|
|
100
100
|
if (!config || !config.api_key) {
|
|
101
|
-
console.error("No API key found. Provide MYAPI_KEY env var or run: myapi
|
|
101
|
+
console.error("No API key found. Provide MYAPI_KEY env var or run: myapi account setup");
|
|
102
102
|
process.exit(1);
|
|
103
103
|
}
|
|
104
104
|
return config;
|
package/dist/exposes.test.js
CHANGED
|
@@ -7,7 +7,7 @@ import * as url from 'url';
|
|
|
7
7
|
// surface.
|
|
8
8
|
const COMMAND_MODULES = [
|
|
9
9
|
'./commands/account.js',
|
|
10
|
-
'./commands/
|
|
10
|
+
'./commands/authproduct.js',
|
|
11
11
|
'./commands/billing.js',
|
|
12
12
|
'./commands/config.js',
|
|
13
13
|
'./commands/crm/index.js',
|
|
@@ -19,7 +19,6 @@ const COMMAND_MODULES = [
|
|
|
19
19
|
'./commands/email/mailbox.js',
|
|
20
20
|
'./commands/email/message.js',
|
|
21
21
|
'./commands/email/template.js',
|
|
22
|
-
'./commands/email/campaign.js',
|
|
23
22
|
'./commands/email/warmup.js',
|
|
24
23
|
'./commands/email/verify.js',
|
|
25
24
|
'./commands/funnel.js',
|