@myapihq/cli 2.26.1 → 2.27.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/authproduct.js +4 -0
- package/dist/commands/container.js +4 -0
- package/dist/commands/doctor.js +5 -1
- package/dist/commands/feedback.js +4 -0
- package/dist/commands/fn.js +4 -0
- package/dist/commands/funnel-pages-content.test.d.ts +1 -0
- package/dist/commands/funnel-pages-content.test.js +75 -0
- package/dist/commands/funnel.js +28 -3
- package/dist/commands/git.js +4 -0
- package/dist/commands/payments.js +4 -0
- package/dist/commands/queue.js +4 -0
- package/dist/commands/task.js +4 -0
- package/dist/org-flag-declared.test.d.ts +1 -0
- package/dist/org-flag-declared.test.js +66 -0
- package/dist/skills/my-funnel-api/SKILL.md +5 -5
- package/package.json +2 -2
|
@@ -9,6 +9,10 @@ import { requireOrg } from '../helpers.js';
|
|
|
9
9
|
// OIDC endpoints (discovery/jwks/authorize/token/userinfo) are consumed by
|
|
10
10
|
// apps + the JS SDK, not the CLI, so only the management surface is here.
|
|
11
11
|
export const SCHEMA = {
|
|
12
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
13
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
14
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
15
|
+
org: 'string',
|
|
12
16
|
name: 'string',
|
|
13
17
|
type: 'string', // spa | web
|
|
14
18
|
redirect: 'list', // comma-separated OR repeated; occurrences accumulate
|
|
@@ -20,6 +20,10 @@ export const EXPOSES = [
|
|
|
20
20
|
'DELETE /container/orgs/{org_id}/containers/{id}/domain',
|
|
21
21
|
];
|
|
22
22
|
export const SCHEMA = {
|
|
23
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
24
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
25
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
26
|
+
org: 'string',
|
|
23
27
|
name: 'string',
|
|
24
28
|
type: 'string',
|
|
25
29
|
cron: 'string',
|
package/dist/commands/doctor.js
CHANGED
|
@@ -32,7 +32,11 @@ export const EXPOSES = [
|
|
|
32
32
|
// Lifetime delivery counts, to replace the 30-day 'quiet webhook' advice.
|
|
33
33
|
'GET /webhook/orgs/{org_id}/deliveries',
|
|
34
34
|
];
|
|
35
|
-
export const SCHEMA = {
|
|
35
|
+
export const SCHEMA = {
|
|
36
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
37
|
+
// called `--org` a typo on a command that had just honoured it.
|
|
38
|
+
org: 'string',
|
|
39
|
+
};
|
|
36
40
|
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
37
41
|
const C = useColor ? {
|
|
38
42
|
ok: '\x1b[32m', warn: '\x1b[33m', err: '\x1b[31m',
|
|
@@ -22,6 +22,10 @@ export const EXPOSES = [
|
|
|
22
22
|
'DELETE /feedback/orgs/{org_id}/widgets/{id}',
|
|
23
23
|
];
|
|
24
24
|
export const SCHEMA = {
|
|
25
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
26
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
27
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
28
|
+
org: 'string',
|
|
25
29
|
// Declared because `list` reads flags.limit/offset, --help documents both,
|
|
26
30
|
// and a truncated page prints "raise --limit" — while the parser refused
|
|
27
31
|
// them as unknown. Reported by ImmoPilot on 2026-08-19.
|
package/dist/commands/fn.js
CHANGED
|
@@ -15,6 +15,10 @@ export const EXPOSES = [
|
|
|
15
15
|
'PATCH /function/orgs/{org_id}/functions/{id}/scopes',
|
|
16
16
|
];
|
|
17
17
|
export const SCHEMA = {
|
|
18
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
19
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
20
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
21
|
+
org: 'string',
|
|
18
22
|
// `create` takes a positional name; --name stays accepted for
|
|
19
23
|
// back-compat (RELEASING.md's stated convention) and must be declared
|
|
20
24
|
// here so the command-aware flag check in index.ts doesn't flag it.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// `funnel push` overwrites whatever is live at the target, and nothing could
|
|
2
|
+
// tell you what that was.
|
|
3
|
+
//
|
|
4
|
+
// `funnel pages` listed paths only. The API has supported ?include_content=true
|
|
5
|
+
// all along; no client ever sent it. So an agent asked to change one section of
|
|
6
|
+
// a published page had two options: regenerate the whole page from scratch, or
|
|
7
|
+
// scrape the public URL and hope. Every funnel edit was a blind write.
|
|
8
|
+
//
|
|
9
|
+
// Found by asking the reverse-coverage question of QUERY parameters rather than
|
|
10
|
+
// request bodies — the direction the request-field linter documents as out of
|
|
11
|
+
// scope, and the same blind spot that hid `?confirm=` on org delete.
|
|
12
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
13
|
+
const ORG = '11111111-1111-4111-8111-111111111111';
|
|
14
|
+
const FUNNEL = 'f1';
|
|
15
|
+
const sdk = vi.hoisted(() => ({
|
|
16
|
+
funnel: { listFunnelPages: vi.fn() },
|
|
17
|
+
hq: { listOrgs: vi.fn() },
|
|
18
|
+
}));
|
|
19
|
+
vi.mock('@myapihq/sdk', () => sdk);
|
|
20
|
+
vi.mock('../config.js', () => ({
|
|
21
|
+
requireConfig: () => ({ api_key: 'hq_live_test', default_org: ORG, default_funnel: FUNNEL }),
|
|
22
|
+
loadConfig: () => ({ api_key: 'hq_live_test', default_org: ORG, default_funnel: FUNNEL }),
|
|
23
|
+
CONFIG_DIR: '/tmp/nowhere',
|
|
24
|
+
}));
|
|
25
|
+
let printed;
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
printed = [];
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
const output = await import('../output.js');
|
|
30
|
+
const cap = ((m) => { printed.push(typeof m === 'string' ? m : JSON.stringify(m)); });
|
|
31
|
+
vi.spyOn(output, 'info').mockImplementation(cap);
|
|
32
|
+
vi.spyOn(output, 'printJson').mockImplementation(cap);
|
|
33
|
+
vi.spyOn(output, 'printTable').mockImplementation(cap);
|
|
34
|
+
vi.spyOn(output, 'banner').mockImplementation(() => { });
|
|
35
|
+
vi.spyOn(output, 'error').mockImplementation(((m) => {
|
|
36
|
+
printed.push(String(m));
|
|
37
|
+
throw new Error('__EXIT__');
|
|
38
|
+
}));
|
|
39
|
+
});
|
|
40
|
+
afterEach(() => vi.restoreAllMocks());
|
|
41
|
+
async function run(flags) {
|
|
42
|
+
const { pages } = await import('./funnel.js');
|
|
43
|
+
try {
|
|
44
|
+
await pages(FUNNEL, flags);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
if (e?.message !== '__EXIT__')
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
describe('funnel pages --with-content', () => {
|
|
52
|
+
it('asks the API for content, so an edit can read before it writes', async () => {
|
|
53
|
+
sdk.funnel.listFunnelPages.mockResolvedValue([{ slug: '/', content: '<h1>live</h1>' }]);
|
|
54
|
+
await run({ 'with-content': true, json: true });
|
|
55
|
+
expect(sdk.funnel.listFunnelPages).toHaveBeenCalledWith('hq_live_test', ORG, FUNNEL, { includeContent: true });
|
|
56
|
+
});
|
|
57
|
+
it('does not ask for it otherwise — listing paths must stay cheap', async () => {
|
|
58
|
+
sdk.funnel.listFunnelPages.mockResolvedValue([{ slug: '/' }]);
|
|
59
|
+
await run({ json: true });
|
|
60
|
+
expect(sdk.funnel.listFunnelPages).toHaveBeenCalledWith('hq_live_test', ORG, FUNNEL, undefined);
|
|
61
|
+
});
|
|
62
|
+
it('puts the content in --json, which is what an agent reads', async () => {
|
|
63
|
+
sdk.funnel.listFunnelPages.mockResolvedValue([{ slug: '/', content: '<h1>live</h1>' }]);
|
|
64
|
+
await run({ 'with-content': true, json: true });
|
|
65
|
+
expect(printed.join('\n')).toContain('<h1>live</h1>');
|
|
66
|
+
});
|
|
67
|
+
it('keeps HTML out of the human view, showing sizes instead', async () => {
|
|
68
|
+
// Six pages of markup in a terminal buries the thing being looked for.
|
|
69
|
+
sdk.funnel.listFunnelPages.mockResolvedValue([{ slug: '/', content: '<h1>live</h1>' }]);
|
|
70
|
+
await run({ 'with-content': true });
|
|
71
|
+
const out = printed.join('\n');
|
|
72
|
+
expect(out).not.toContain('<h1>live</h1>');
|
|
73
|
+
expect(out).toContain('13');
|
|
74
|
+
});
|
|
75
|
+
});
|
package/dist/commands/funnel.js
CHANGED
|
@@ -24,10 +24,16 @@ export const EXPOSES = [
|
|
|
24
24
|
'GET /hq/orgs/{org_id}',
|
|
25
25
|
];
|
|
26
26
|
export const SCHEMA = {
|
|
27
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
28
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
29
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
30
|
+
org: 'string',
|
|
27
31
|
funnel: 'string',
|
|
28
32
|
slug: 'string',
|
|
29
33
|
env: 'string',
|
|
30
34
|
force: 'boolean',
|
|
35
|
+
// \`funnel pages --with-content\` — read what is live before overwriting it.
|
|
36
|
+
'with-content': 'boolean',
|
|
31
37
|
'api-fn': 'string',
|
|
32
38
|
// form
|
|
33
39
|
fields: 'string',
|
|
@@ -214,7 +220,11 @@ export async function pages(funnelArg, flags) {
|
|
|
214
220
|
const funnelId = funnelArg || flags.funnel || config.default_funnel;
|
|
215
221
|
if (!funnelId)
|
|
216
222
|
error('Missing funnel id. Pass it as a positional arg, --funnel <id>, or set: myapi config set-funnel <id>');
|
|
217
|
-
|
|
223
|
+
// --with-content is what makes an edit a read-then-write instead of a blind
|
|
224
|
+
// overwrite. `funnel push` replaces whatever is live at the target, and until
|
|
225
|
+
// now nothing could tell you what that was: an agent asked to change one
|
|
226
|
+
// section had to regenerate the whole page or scrape the public URL.
|
|
227
|
+
const list = await sdkFunnel.listFunnelPages(config.api_key, orgId, funnelId, flags['with-content'] ? { includeContent: true } : undefined);
|
|
218
228
|
// An empty inventory is not proof the funnel is empty. Verified 2026-07-28:
|
|
219
229
|
// a funnel answering 200 with real content on both its subdomain and a bound
|
|
220
230
|
// custom domain reported `{"pages":[]}`. Someone auditing what is deployed
|
|
@@ -244,10 +254,21 @@ export async function pages(funnelArg, flags) {
|
|
|
244
254
|
printJson(list);
|
|
245
255
|
return;
|
|
246
256
|
}
|
|
247
|
-
|
|
257
|
+
// Human output never dumps the content — six pages of HTML in a terminal
|
|
258
|
+
// buries the thing being looked for. The size is the useful summary; --json
|
|
259
|
+
// carries the content itself, which is the shape an agent reads anyway.
|
|
260
|
+
printTable(flags['with-content']
|
|
261
|
+
? list.map(p => ({
|
|
262
|
+
slug: p.slug,
|
|
263
|
+
bytes: typeof p.content === 'string' ? p.content.length : '—',
|
|
264
|
+
updated_at: p.updated_at ?? '',
|
|
265
|
+
}))
|
|
266
|
+
: list, {
|
|
248
267
|
flags,
|
|
249
268
|
empty: 'No pages published to this funnel yet. Push one with: echo "<h1>Hello</h1>" | myapi funnel push /',
|
|
250
269
|
});
|
|
270
|
+
if (flags['with-content'])
|
|
271
|
+
info(' Content is in --json; this view shows sizes so a terminal is not flooded.');
|
|
251
272
|
}
|
|
252
273
|
export async function push(slug, flags) {
|
|
253
274
|
const config = requireConfig();
|
|
@@ -660,7 +681,11 @@ future platform features (rate-limit, captcha, field validation) for
|
|
|
660
681
|
free.`,
|
|
661
682
|
'get': 'myapi funnel get <id> [--org <id>] [--json]',
|
|
662
683
|
'list': 'myapi funnel list [--org <id>] [--json]',
|
|
663
|
-
'pages':
|
|
684
|
+
'pages': `myapi funnel pages [funnel_id] [--funnel <id>] [--with-content] [--org <id>] [--json]
|
|
685
|
+
|
|
686
|
+
Lists what is published. --with-content also fetches each page's live content, which
|
|
687
|
+
is how you read a page before overwriting it — \`funnel push\` replaces whatever
|
|
688
|
+
is there. Human output shows sizes; --json carries the content.`,
|
|
664
689
|
'publish': `myapi funnel publish <dir> [--funnel <id>] [--env dev|prod] [--api-fn <id>] [--force] [--org <id>]
|
|
665
690
|
|
|
666
691
|
Uploads a whole local directory as the funnel's site. Each file's path
|
package/dist/commands/git.js
CHANGED
|
@@ -24,6 +24,10 @@ export const EXPOSES = [
|
|
|
24
24
|
'POST /git/orgs/{org_id}/repos/{repo}/repack',
|
|
25
25
|
];
|
|
26
26
|
export const SCHEMA = {
|
|
27
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
28
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
29
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
30
|
+
org: 'string',
|
|
27
31
|
name: 'string',
|
|
28
32
|
'default-branch': 'string',
|
|
29
33
|
ref: 'string',
|
|
@@ -13,6 +13,10 @@ export const EXPOSES = [
|
|
|
13
13
|
'POST /payments/webhook/{org_id}',
|
|
14
14
|
];
|
|
15
15
|
export const SCHEMA = {
|
|
16
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
17
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
18
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
19
|
+
org: 'string',
|
|
16
20
|
'stripe-key': 'string',
|
|
17
21
|
amount: 'string',
|
|
18
22
|
description: 'string',
|
package/dist/commands/queue.js
CHANGED
|
@@ -13,6 +13,10 @@ export const EXPOSES = [
|
|
|
13
13
|
'GET /queue/orgs/{org_id}/jobs/{id}',
|
|
14
14
|
];
|
|
15
15
|
export const SCHEMA = {
|
|
16
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
17
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
18
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
19
|
+
org: 'string',
|
|
16
20
|
name: 'string',
|
|
17
21
|
'consumer-url': 'string',
|
|
18
22
|
'max-attempts': 'number',
|
package/dist/commands/task.js
CHANGED
|
@@ -22,6 +22,10 @@ function taskOrigin(flags) {
|
|
|
22
22
|
return typeof v === 'string' ? v : undefined;
|
|
23
23
|
}
|
|
24
24
|
export const SCHEMA = {
|
|
25
|
+
// Declared because requireOrg reads it. Undeclared, the foreign-flag check
|
|
26
|
+
// called `--org` a typo on a command that had just honoured it — telling
|
|
27
|
+
// people the one flag that keeps writes in the right tenant is unrecognized.
|
|
28
|
+
org: 'string',
|
|
25
29
|
body: 'string',
|
|
26
30
|
importance: 'string',
|
|
27
31
|
due: 'string',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// A command that reads `--org` must declare it.
|
|
2
|
+
//
|
|
3
|
+
// Ten command modules called requireOrg() — which reads flags.org — without
|
|
4
|
+
// listing `org` in their SCHEMA. The flag still worked, because requireOrg
|
|
5
|
+
// reads the raw flags. But the foreign-flag check did not know about it, so
|
|
6
|
+
// every one of them answered a correct command with:
|
|
7
|
+
//
|
|
8
|
+
// › Note: unknown flag(s) not recognized by this command: --org
|
|
9
|
+
// (took value "c2c4810d-…") — check for typos.
|
|
10
|
+
//
|
|
11
|
+
// and then used the value anyway. `funnel list --org <other>` returned the
|
|
12
|
+
// other org's funnels while calling the flag a typo.
|
|
13
|
+
//
|
|
14
|
+
// This is not cosmetic. `--org` is the flag that keeps a write in the right
|
|
15
|
+
// tenant, and telling people it is unrecognized is an invitation to drop it and
|
|
16
|
+
// rely on the machine-wide default — which is precisely the habit behind the
|
|
17
|
+
// cross-project collisions customers report. An agent reading stderr is even
|
|
18
|
+
// likelier to "fix" the typo by removing the flag.
|
|
19
|
+
//
|
|
20
|
+
// Found by running a real command and reading what it printed, not from a test.
|
|
21
|
+
import { describe, it, expect } from 'vitest';
|
|
22
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
23
|
+
import * as path from 'node:path';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
const COMMANDS_DIR = fileURLToPath(new URL('./commands/', import.meta.url));
|
|
26
|
+
function moduleFiles() {
|
|
27
|
+
const out = [];
|
|
28
|
+
for (const entry of readdirSync(COMMANDS_DIR).sort()) {
|
|
29
|
+
const p = path.join(COMMANDS_DIR, entry);
|
|
30
|
+
if (statSync(p).isDirectory()) {
|
|
31
|
+
const idx = path.join(p, 'index.ts');
|
|
32
|
+
try {
|
|
33
|
+
statSync(idx);
|
|
34
|
+
out.push(`${entry}/index.ts`);
|
|
35
|
+
}
|
|
36
|
+
catch { /* no dispatcher */ }
|
|
37
|
+
}
|
|
38
|
+
else if (entry.endsWith('.ts') && !entry.includes('.test.')) {
|
|
39
|
+
out.push(entry);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
describe('every command that reads --org declares it', () => {
|
|
45
|
+
const files = moduleFiles();
|
|
46
|
+
it('found command modules (or this proves nothing)', () => {
|
|
47
|
+
expect(files.length).toBeGreaterThan(10);
|
|
48
|
+
});
|
|
49
|
+
it('no module uses requireOrg without declaring org in its SCHEMA', () => {
|
|
50
|
+
const undeclared = [];
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
const src = readFileSync(path.join(COMMANDS_DIR, file), 'utf8');
|
|
53
|
+
const readsOrg = /\brequireOrg\s*\(|\brequireExplicitOrg\s*\(/.test(src);
|
|
54
|
+
if (!readsOrg)
|
|
55
|
+
continue;
|
|
56
|
+
// A module with no SCHEMA of its own inherits nothing — it still needs
|
|
57
|
+
// the declaration, so absence counts as undeclared rather than exempt.
|
|
58
|
+
const declares = /^\s*org:\s*'string',/m.test(src);
|
|
59
|
+
if (!declares)
|
|
60
|
+
undeclared.push(file);
|
|
61
|
+
}
|
|
62
|
+
expect(undeclared, `${undeclared.join(', ')} call requireOrg but do not declare ` +
|
|
63
|
+
"`org: 'string'` in SCHEMA. The flag will still work and the CLI will call it a " +
|
|
64
|
+
'typo — on the one flag that keeps a write in the right tenant.').toEqual([]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: my-funnel-api
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.1
|
|
4
4
|
description: >
|
|
5
5
|
Create and publish websites (funnels) to the edge. Push raw HTML to any slug and it goes live instantly on your org's domain or preview subdomain.
|
|
6
6
|
triggers: [funnel, landing page, website, page, publish, push, slug, html, edge, preview subdomain, makeautonomous]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-7bcaeef9bd17839aa28c62a8e39f67e29a39967397f9e0ee717e19765983e499
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyFunnelAPI
|
|
@@ -19,7 +19,7 @@ Funnels are the publishing surface. You create a funnel under an org (one comman
|
|
|
19
19
|
|
|
20
20
|
By default, your funnel lives on a free preview subdomain (`*.makeautonomous.com`) you get with every org. To serve on a custom domain, register and assign one via **mydomainapi** first.
|
|
21
21
|
|
|
22
|
-
Every funnel auto-provisions a **webhook** at creation (`org_webhook_id`)
|
|
22
|
+
Every funnel auto-provisions a **webhook** at creation (`org_webhook_id`) and exposes two public endpoints your HTML can call without an API key: **form submit** at `POST /funnel/funnels/{id}/submit/{slug}`, which delivers through that webhook (CRM upsert + bound workflows fire automatically), and **event ingest** for pageviews and click tracking. Send a slug elsewhere with `myapi funnel form ... --capture-to webhook:<id>`.
|
|
23
23
|
<!-- llm:end -->
|
|
24
24
|
|
|
25
25
|
## Commands
|
|
@@ -32,7 +32,7 @@ Every funnel auto-provisions a **webhook** at creation (`org_webhook_id`), and e
|
|
|
32
32
|
| `myapi funnel delete <id>` | Delete the funnel and purge its edge pages |
|
|
33
33
|
| `myapi funnel push [slug]` | Push HTML from stdin to a slug (default: `/`). **Overwrites** an existing page — refused without `--force`. `--json` prints `{slug, subdomain_url, overwritten, org_id, funnel_id}` |
|
|
34
34
|
| `myapi funnel publish <dir>` | Upload a whole directory as the funnel's site (`--env dev\|prod`, default prod; `--api-fn <id>`; `--json`). Prod refuses to replace a live site without `--force` |
|
|
35
|
-
| `myapi funnel pages [funnel_id]` |
|
|
35
|
+
| `myapi funnel pages [funnel_id]` | Pages published to a funnel; `--with-content` fetches what is on them |
|
|
36
36
|
| `myapi funnel form [funnel_id]` | Emit canonical form HTML (`--capture-to`, `--cta`, `--success`, `--honeypot`) |
|
|
37
37
|
| `myapi funnel verify [slug]` | Verify a published page is reachable + check links/webhooks |
|
|
38
38
|
<!-- generated:end -->
|
|
@@ -42,7 +42,7 @@ Every funnel auto-provisions a **webhook** at creation (`org_webhook_id`), and e
|
|
|
42
42
|
A write targets a `(org, funnel, slug)` address. Get all three right *before* pushing — the CLI will help, but the thinking is yours:
|
|
43
43
|
|
|
44
44
|
1. **Confirm the org.** `--org` (or `default_org`) decides whose namespace you touch. For a demo or a new project, pass `--org <id>` explicitly every time — don't trust the ambient default. `myapi org list` shows the orgs you can reach.
|
|
45
|
-
2. **Look before you write.** `myapi funnel list --org <id>` shows the org's funnels; `myapi funnel pages --funnel <id>` shows what
|
|
45
|
+
2. **Look before you write.** `myapi funnel list --org <id>` shows the org's funnels; `myapi funnel pages --funnel <id>` shows what is published, and `--with-content` what is on each page (`--json` carries it). `push` replaces a whole page, so edit by reading it first.
|
|
46
46
|
3. **A new demo = a new funnel.** Don't reuse an org's existing funnel for an unrelated demo. `myapi funnel create --name <demo> --org <id>` gives you a clean namespace and its own preview subdomain.
|
|
47
47
|
4. **Pin the funnel.** When an org has exactly one funnel, `push`/`publish` auto-pick it — convenient, but it's how a demo lands on the wrong site. Pass `--funnel <id>` (or set a default) so the target is explicit, not inferred.
|
|
48
48
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myapihq/cli",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.27.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.
|
|
49
|
+
"@myapihq/sdk": "^2.27.1"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^25.6.0",
|