@exposify/cli 0.0.2 → 0.1.0
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/README.md +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +42 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @exposify/cli
|
|
2
2
|
|
|
3
|
-
The framework-neutral engine behind
|
|
3
|
+
The framework-neutral engine behind `@exposify/express` and `@exposify/next`:
|
|
4
4
|
the endpoint checklist, the startup-log question, config + clipboard + verify,
|
|
5
5
|
tool descriptions (`describe`), and `inspect` snapshots. You don't use it
|
|
6
6
|
directly: install an adapter (`@exposify/express`, `@exposify/nestjs`,
|
package/dist/index.d.ts
CHANGED
|
@@ -132,6 +132,22 @@ interface ScanResult {
|
|
|
132
132
|
fields: string[];
|
|
133
133
|
others?: string[];
|
|
134
134
|
};
|
|
135
|
+
/**
|
|
136
|
+
* Supabase Auth with `@supabase/ssr` (Next.js): which sign-ins Connect
|
|
137
|
+
* makes on Supabase directly, and where the app signs in (plan
|
|
138
|
+
* `2026-10-24-supabase-connect.md` Part 2).
|
|
139
|
+
*/
|
|
140
|
+
supabase?: {
|
|
141
|
+
direct: Array<"password" | "email-code" | "social">;
|
|
142
|
+
/** The sign-in calls found, one line each; empty: none found. */
|
|
143
|
+
found: string[];
|
|
144
|
+
/** Server sign-ins the form can't run. */
|
|
145
|
+
unusable?: string[];
|
|
146
|
+
/** Routes that finish a sign-in; Connect's sign-ins skip them. */
|
|
147
|
+
callbacks?: string[];
|
|
148
|
+
/** `@supabase/auth-helpers-nextjs`: an older cookie format, not supported. */
|
|
149
|
+
authHelpers?: boolean;
|
|
150
|
+
};
|
|
135
151
|
}
|
|
136
152
|
interface ScanFailure {
|
|
137
153
|
ok: false;
|
|
@@ -278,7 +294,7 @@ interface ConfigStepInput<R extends ScanResult = ScanResult> {
|
|
|
278
294
|
readLine: (site: CallSite) => string | undefined;
|
|
279
295
|
}
|
|
280
296
|
interface CliAdapter<R extends ScanResult = ScanResult> {
|
|
281
|
-
/** The command
|
|
297
|
+
/** The command as users type it in hints, e.g. "npx @exposify/next". */
|
|
282
298
|
bin: string;
|
|
283
299
|
/** An example for "pass it explicitly", e.g. "src/server.ts". */
|
|
284
300
|
entryExample: string;
|
package/dist/index.js
CHANGED
|
@@ -1561,7 +1561,38 @@ function inspect(result, cwd) {
|
|
|
1561
1561
|
if (result.actions && result.actions.length > 0) inspectActions(result, cwd);
|
|
1562
1562
|
inspectLogin(result);
|
|
1563
1563
|
}
|
|
1564
|
+
function supabaseSignIn(s, login) {
|
|
1565
|
+
if (s.authHelpers) return { row: "none: @supabase/auth-helpers-nextjs isn't supported", why: ["It keeps the session in an older cookie format. Move to @supabase/ssr, Supabase's replacement for it."] };
|
|
1566
|
+
const passwordDirect = s.direct.includes("password");
|
|
1567
|
+
const why = [];
|
|
1568
|
+
let row;
|
|
1569
|
+
if (s.found.length === 0) {
|
|
1570
|
+
row = "your Supabase Auth, directly";
|
|
1571
|
+
why.push("Couldn't find where your users sign in, so AI assistants sign in to Supabase directly: a password on /mcp/login, social and email codes on Exposify's page.");
|
|
1572
|
+
} else if (!passwordDirect && login) {
|
|
1573
|
+
row = `your app's own login for passwords (${login.what}); your Supabase Auth, directly, for social and email codes`;
|
|
1574
|
+
why.push('Your password sign-in runs on your server, which may hold your own checks, so the form runs it. Switch to "Sign in with Supabase" on the dashboard to skip it.');
|
|
1575
|
+
} else if (!passwordDirect) {
|
|
1576
|
+
row = "your Supabase Auth, directly, for social and email codes; no password sign-in";
|
|
1577
|
+
why.push(`Your app signs in on the server where the form can't run it: ${(s.unusable ?? []).join("; ")}.`);
|
|
1578
|
+
why.push('Switch on "Sign in with Supabase" on the dashboard to have passwords go to Supabase directly (it skips what that code checks).');
|
|
1579
|
+
} else {
|
|
1580
|
+
row = "your Supabase Auth, directly";
|
|
1581
|
+
why.push(`Your sign-in runs in the browser (${s.found[0]}), so there's no server check to skip.`);
|
|
1582
|
+
}
|
|
1583
|
+
if (s.callbacks?.length) why.push(`Connect's sign-ins don't go through ${s.callbacks.join(", ")}; anything those check is skipped.`);
|
|
1584
|
+
return { row, why };
|
|
1585
|
+
}
|
|
1564
1586
|
function inspectLogin(result) {
|
|
1587
|
+
if (result.supabase) {
|
|
1588
|
+
const { row, why } = supabaseSignIn(result.supabase, result.login);
|
|
1589
|
+
console.log(`
|
|
1590
|
+
Sign-in for AI assistants: ${row}.`);
|
|
1591
|
+
for (const line of why) console.log(dim(` ${line}`));
|
|
1592
|
+
if (result.supabase.found.length > 1) for (const f of result.supabase.found) console.log(dim(` found ${f}`));
|
|
1593
|
+
if (result.supabase.direct.length && !result.supabase.authHelpers) console.log(dim(" Check it on a running app: npx @exposify/next test-sign-in"));
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1565
1596
|
if (!result.login) return;
|
|
1566
1597
|
console.log(`
|
|
1567
1598
|
Sign-in for AI assistants: your app's own login, ${result.login.what} (${result.login.fields.join(", ")}).`);
|
|
@@ -1748,7 +1779,7 @@ ${bold("Step 2/5")} \xB7 Print "[agentready] MCP ready \u2026" when your server
|
|
|
1748
1779
|
console.log(`
|
|
1749
1780
|
${green("\u2713 Already set up")}: your aiReady() config already matches. Nothing to change.`);
|
|
1750
1781
|
if (tty && !args.quick) {
|
|
1751
|
-
await signInStep(args, root, cwd, "Step 4/5", result.login);
|
|
1782
|
+
await signInStep(args, root, cwd, "Step 4/5", result.login, result.supabase);
|
|
1752
1783
|
const code2 = await describeStep(args, toolRows(result.routes, result.actions), root, cwd, "Step 5/5");
|
|
1753
1784
|
if (code2 !== 0) return code2;
|
|
1754
1785
|
}
|
|
@@ -1834,7 +1865,7 @@ ${bold("Step 3/5")} \xB7 Your aiReady() config${copyNote}
|
|
|
1834
1865
|
}
|
|
1835
1866
|
const finalRoutes = verified ?? toolRows(routesAsSelected(registered, selected), actionRows.map((a) => ({ ...a, exposed: a.marker ? a.exposed : pickedActions.has(a.configKey) })));
|
|
1836
1867
|
if (tty && !args.quick) {
|
|
1837
|
-
await signInStep(args, root, cwd, "Step 4/5", result.login);
|
|
1868
|
+
await signInStep(args, root, cwd, "Step 4/5", result.login, result.supabase);
|
|
1838
1869
|
const code2 = await describeStep(args, finalRoutes, root, cwd, "Step 5/5");
|
|
1839
1870
|
if (code2 !== 0) return code2;
|
|
1840
1871
|
const proposed = await proposeStep(args, verifiedActions, root, cwd);
|
|
@@ -1879,7 +1910,7 @@ ${bold("Optional")} \xB7 Save the tools agents get to ${shown}?`);
|
|
|
1879
1910
|
}
|
|
1880
1911
|
if (save) writeSnapshot(routes, file, cwd);
|
|
1881
1912
|
}
|
|
1882
|
-
async function signInStep(args, root, cwd, title, login) {
|
|
1913
|
+
async function signInStep(args, root, cwd, title, login, supabase) {
|
|
1883
1914
|
if (!args.signIn) return;
|
|
1884
1915
|
const stacks = detectAuthStacks(root);
|
|
1885
1916
|
const oauth = stacks.find((s) => s.path === "oauth");
|
|
@@ -1892,13 +1923,17 @@ ${bold(title)} \xB7 How your users sign in`);
|
|
|
1892
1923
|
console.log(dim(" The README's OAuth section lists the settings to turn on in the provider's dashboard."));
|
|
1893
1924
|
return;
|
|
1894
1925
|
}
|
|
1895
|
-
const
|
|
1896
|
-
|
|
1926
|
+
const sb = supabase && !supabase.authHelpers ? supabaseSignIn(supabase, login) : null;
|
|
1927
|
+
const own = sb ? sb.row : login ? `your app's own login, ${login.what} (${login.fields.join(", ")})` : null;
|
|
1928
|
+
if (sb) {
|
|
1929
|
+
console.log(` AI assistants sign in with ${sb.row}. Nothing to set up for it.`);
|
|
1930
|
+
for (const line of sb.why) console.log(dim(` ${line}`));
|
|
1931
|
+
} else if (own) console.log(` Found ${own}. AI assistants sign in with it on a form your app serves at /mcp/login, so there's nothing to set up for it.`);
|
|
1897
1932
|
const signedOut = "agents use your app signed out, and your own checks decide what they can do";
|
|
1898
1933
|
const have = existingKey(root, process.env);
|
|
1899
1934
|
if (have) {
|
|
1900
1935
|
console.log(
|
|
1901
|
-
green(` \u2713 ${KEY_ENV} is set (${have.from}):`) + (own ? " agents sign in with your app's login, through Exposify's broker." : ` until you add a sign-in method in the dashboard, ${signedOut}.`)
|
|
1936
|
+
green(` \u2713 ${KEY_ENV} is set (${have.from}):`) + (sb ? ` agents sign in with ${sb.row}, through Exposify's broker.` : own ? " agents sign in with your app's login, through Exposify's broker." : ` until you add a sign-in method in the dashboard, ${signedOut}.`)
|
|
1902
1937
|
);
|
|
1903
1938
|
return;
|
|
1904
1939
|
}
|
|
@@ -1931,7 +1966,7 @@ ${bold(title)} \xB7 How your users sign in`);
|
|
|
1931
1966
|
process.env[KEY_ENV] = outcome.key;
|
|
1932
1967
|
console.log(green(` \u2713 ${written.created ? "Created" : "Updated"} ${relative(cwd, written.path) || written.path} with ${KEY_ENV}`) + ` (project "${outcome.projectName}").`);
|
|
1933
1968
|
if (!written.ignored) console.log(yellow(` ! Add .env to .gitignore: it now holds a secret.`));
|
|
1934
|
-
if (own) console.log(` Your app tells Exposify about its login when it starts with ${KEY_ENV}: nothing to add in the dashboard.`);
|
|
1969
|
+
if (own) console.log(` Your app tells Exposify about its ${sb ? "Supabase Auth" : "login"} when it starts with ${KEY_ENV}: nothing to add in the dashboard.`);
|
|
1935
1970
|
else {
|
|
1936
1971
|
console.log(` No login form was found, so ${signedOut}.`);
|
|
1937
1972
|
console.log(` To have agents act as a signed-in user, add a sign-in method in the dashboard (presets for GitHub, Google, Supabase, \u2026).`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exposify/cli",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@babel/parser": "^8.0.0",
|
|
25
|
-
"@exposify/core": "0.
|
|
25
|
+
"@exposify/core": "0.4.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.0.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
|
-
"description": "The framework-neutral engine behind exposify
|
|
36
|
+
"description": "The framework-neutral engine behind @exposify/express and @exposify/next: guided setup, inspect and describe for Exposify adapters.",
|
|
37
37
|
"author": "Exposify",
|
|
38
38
|
"keywords": [
|
|
39
39
|
"mcp",
|