@exposify/next 0.0.1 → 0.0.2
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 +7 -0
- package/dist/config.cjs +4 -2
- package/dist/config.js +5 -3
- package/dist/exposify-next.js +5 -3
- package/dist/index.cjs +14 -10
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +14 -10
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -136,6 +136,13 @@ was found. Name another one with `aiReady(exposify, { login: "signIn" })`
|
|
|
136
136
|
(an action's export name) or `{ login: { path: "/api/login", fields:
|
|
137
137
|
["email", "password"] } }`, or turn it off with `login: false`.
|
|
138
138
|
|
|
139
|
+
**No login found, and no sign-in method in the dashboard?** Then agents use
|
|
140
|
+
your app signed out: `/mcp` doesn't ask them to sign in, and your own checks
|
|
141
|
+
decide what they can do. The startup log says which it is
|
|
142
|
+
(`[agentready] How agents sign in: ...`), and so does the dashboard's "How
|
|
143
|
+
agents sign in" page. Adding a sign-in method there takes effect within a
|
|
144
|
+
minute.
|
|
145
|
+
|
|
139
146
|
Not supported yet: logins in more than one step (SMS codes, email links),
|
|
140
147
|
and logins that need a CSRF token from your own form page.
|
|
141
148
|
|
package/dist/config.cjs
CHANGED
|
@@ -1894,7 +1894,7 @@ function specifier(outFile, file) {
|
|
|
1894
1894
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
1895
1895
|
}
|
|
1896
1896
|
function manifestLogin(l) {
|
|
1897
|
-
return l.kind === "action" ? { kind: "action", key: l.key, fields: l.fields, ...l.host ? { host: l.host } : {} } : { kind: "route", path: l.path, fields: l.fields, body: l.body };
|
|
1897
|
+
return l.kind === "action" ? { kind: "action", key: l.key, fields: l.fields, ...l.host ? { host: l.host } : {}, where: `${l.export} in ${l.file}` } : { kind: "route", path: l.path, fields: l.fields, body: l.body, where: `POST ${l.path} in ${l.file}` };
|
|
1898
1898
|
}
|
|
1899
1899
|
function renderManifest(d, opts) {
|
|
1900
1900
|
const ts = opts.outFile.endsWith(".ts");
|
|
@@ -1946,6 +1946,7 @@ function renderManifest(d, opts) {
|
|
|
1946
1946
|
...actions.length > 0 ? [" actions: [", ...actions, " ],"] : [],
|
|
1947
1947
|
...pages.length > 0 ? [" pages: [", ...pages, " ],"] : [],
|
|
1948
1948
|
...d.login ? [` login: ${j(manifestLogin(d.login))},`] : [],
|
|
1949
|
+
...opts.authStacks?.length ? [` authStacks: ${j(opts.authStacks)},`] : [],
|
|
1949
1950
|
` docs: ${j(opts.docs)},`,
|
|
1950
1951
|
...Object.keys(opts.descriptions).length > 0 ? [` descriptions: ${JSON.stringify(opts.descriptions, null, 2).replace(/\n/g, "\n ")},`] : [],
|
|
1951
1952
|
"};",
|
|
@@ -1964,7 +1965,8 @@ function generate(root, opts = {}, warn = (m) => console.warn(`[exposify] ${m}`)
|
|
|
1964
1965
|
descriptions: readDescriptions(root, warn),
|
|
1965
1966
|
info,
|
|
1966
1967
|
...opts.basePath ? { basePath: opts.basePath } : {},
|
|
1967
|
-
...opts.trailingSlash ? { trailingSlash: true } : {}
|
|
1968
|
+
...opts.trailingSlash ? { trailingSlash: true } : {},
|
|
1969
|
+
authStacks: (0, import_core2.authStacksOf)((0, import_core2.dependencyNames)(pkg)).map((s) => s.pkg)
|
|
1968
1970
|
});
|
|
1969
1971
|
for (const a of discovery.actions.filter((x) => x.proposed?.status === "stale")) {
|
|
1970
1972
|
warn(`the input accepted for the ${a.action.name} server action (${a.file}) is out of date, since the action changed: it's not used until \`exposify-next describe\` reviews it again`);
|
package/dist/config.js
CHANGED
|
@@ -14,7 +14,7 @@ import { DESCRIPTIONS_FILE as DESCRIPTIONS_FILE2 } from "@exposify/core";
|
|
|
14
14
|
import { createHash } from "crypto";
|
|
15
15
|
import { existsSync as existsSync2, readFileSync as readFileSync6, readdirSync, writeFileSync } from "fs";
|
|
16
16
|
import { dirname as dirname2, join as join6, relative as relative2, sep as sep2 } from "path";
|
|
17
|
-
import { DESCRIPTIONS_FILE, parseDescriptions } from "@exposify/core";
|
|
17
|
+
import { DESCRIPTIONS_FILE, authStacksOf, dependencyNames, parseDescriptions } from "@exposify/core";
|
|
18
18
|
import { globSync } from "tinyglobby";
|
|
19
19
|
|
|
20
20
|
// src/ast.ts
|
|
@@ -1827,7 +1827,7 @@ function specifier(outFile, file) {
|
|
|
1827
1827
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
1828
1828
|
}
|
|
1829
1829
|
function manifestLogin(l) {
|
|
1830
|
-
return l.kind === "action" ? { kind: "action", key: l.key, fields: l.fields, ...l.host ? { host: l.host } : {} } : { kind: "route", path: l.path, fields: l.fields, body: l.body };
|
|
1830
|
+
return l.kind === "action" ? { kind: "action", key: l.key, fields: l.fields, ...l.host ? { host: l.host } : {}, where: `${l.export} in ${l.file}` } : { kind: "route", path: l.path, fields: l.fields, body: l.body, where: `POST ${l.path} in ${l.file}` };
|
|
1831
1831
|
}
|
|
1832
1832
|
function renderManifest(d, opts) {
|
|
1833
1833
|
const ts = opts.outFile.endsWith(".ts");
|
|
@@ -1879,6 +1879,7 @@ function renderManifest(d, opts) {
|
|
|
1879
1879
|
...actions.length > 0 ? [" actions: [", ...actions, " ],"] : [],
|
|
1880
1880
|
...pages.length > 0 ? [" pages: [", ...pages, " ],"] : [],
|
|
1881
1881
|
...d.login ? [` login: ${j(manifestLogin(d.login))},`] : [],
|
|
1882
|
+
...opts.authStacks?.length ? [` authStacks: ${j(opts.authStacks)},`] : [],
|
|
1882
1883
|
` docs: ${j(opts.docs)},`,
|
|
1883
1884
|
...Object.keys(opts.descriptions).length > 0 ? [` descriptions: ${JSON.stringify(opts.descriptions, null, 2).replace(/\n/g, "\n ")},`] : [],
|
|
1884
1885
|
"};",
|
|
@@ -1897,7 +1898,8 @@ function generate(root, opts = {}, warn = (m) => console.warn(`[exposify] ${m}`)
|
|
|
1897
1898
|
descriptions: readDescriptions(root, warn),
|
|
1898
1899
|
info,
|
|
1899
1900
|
...opts.basePath ? { basePath: opts.basePath } : {},
|
|
1900
|
-
...opts.trailingSlash ? { trailingSlash: true } : {}
|
|
1901
|
+
...opts.trailingSlash ? { trailingSlash: true } : {},
|
|
1902
|
+
authStacks: authStacksOf(dependencyNames(pkg)).map((s) => s.pkg)
|
|
1901
1903
|
});
|
|
1902
1904
|
for (const a of discovery.actions.filter((x) => x.proposed?.status === "stale")) {
|
|
1903
1905
|
warn(`the input accepted for the ${a.action.name} server action (${a.file}) is out of date, since the action changed: it's not used until \`exposify-next describe\` reviews it again`);
|
package/dist/exposify-next.js
CHANGED
|
@@ -8,7 +8,7 @@ import { runCli } from "@exposify/cli";
|
|
|
8
8
|
import { createHash } from "crypto";
|
|
9
9
|
import { existsSync as existsSync2, readFileSync as readFileSync6, readdirSync, writeFileSync } from "fs";
|
|
10
10
|
import { dirname as dirname2, join as join6, relative as relative2, sep as sep2 } from "path";
|
|
11
|
-
import { DESCRIPTIONS_FILE, parseDescriptions } from "@exposify/core";
|
|
11
|
+
import { DESCRIPTIONS_FILE, authStacksOf, dependencyNames, parseDescriptions } from "@exposify/core";
|
|
12
12
|
import { globSync } from "tinyglobby";
|
|
13
13
|
|
|
14
14
|
// src/ast.ts
|
|
@@ -1925,7 +1925,7 @@ function specifier(outFile, file) {
|
|
|
1925
1925
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
1926
1926
|
}
|
|
1927
1927
|
function manifestLogin(l) {
|
|
1928
|
-
return l.kind === "action" ? { kind: "action", key: l.key, fields: l.fields, ...l.host ? { host: l.host } : {} } : { kind: "route", path: l.path, fields: l.fields, body: l.body };
|
|
1928
|
+
return l.kind === "action" ? { kind: "action", key: l.key, fields: l.fields, ...l.host ? { host: l.host } : {}, where: `${l.export} in ${l.file}` } : { kind: "route", path: l.path, fields: l.fields, body: l.body, where: `POST ${l.path} in ${l.file}` };
|
|
1929
1929
|
}
|
|
1930
1930
|
function renderManifest(d, opts) {
|
|
1931
1931
|
const ts = opts.outFile.endsWith(".ts");
|
|
@@ -1977,6 +1977,7 @@ function renderManifest(d, opts) {
|
|
|
1977
1977
|
...actions.length > 0 ? [" actions: [", ...actions, " ],"] : [],
|
|
1978
1978
|
...pages.length > 0 ? [" pages: [", ...pages, " ],"] : [],
|
|
1979
1979
|
...d.login ? [` login: ${j(manifestLogin(d.login))},`] : [],
|
|
1980
|
+
...opts.authStacks?.length ? [` authStacks: ${j(opts.authStacks)},`] : [],
|
|
1980
1981
|
` docs: ${j(opts.docs)},`,
|
|
1981
1982
|
...Object.keys(opts.descriptions).length > 0 ? [` descriptions: ${JSON.stringify(opts.descriptions, null, 2).replace(/\n/g, "\n ")},`] : [],
|
|
1982
1983
|
"};",
|
|
@@ -1995,7 +1996,8 @@ function generate(root, opts = {}, warn = (m) => console.warn(`[exposify] ${m}`)
|
|
|
1995
1996
|
descriptions: readDescriptions(root, warn),
|
|
1996
1997
|
info,
|
|
1997
1998
|
...opts.basePath ? { basePath: opts.basePath } : {},
|
|
1998
|
-
...opts.trailingSlash ? { trailingSlash: true } : {}
|
|
1999
|
+
...opts.trailingSlash ? { trailingSlash: true } : {},
|
|
2000
|
+
authStacks: authStacksOf(dependencyNames(pkg)).map((s) => s.pkg)
|
|
1999
2001
|
});
|
|
2000
2002
|
for (const a of discovery.actions.filter((x) => x.proposed?.status === "stale")) {
|
|
2001
2003
|
warn(`the input accepted for the ${a.action.name} server action (${a.file}) is out of date, since the action changed: it's not used until \`exposify-next describe\` reviews it again`);
|
package/dist/index.cjs
CHANGED
|
@@ -833,7 +833,7 @@ function loginSpec(manifest, config, warnings) {
|
|
|
833
833
|
if (config === void 0) return manifest.login ?? null;
|
|
834
834
|
if (typeof config === "object") {
|
|
835
835
|
const fields2 = config.fields.map((name) => ({ name, kind: (0, import_core.fieldKind)(name) }));
|
|
836
|
-
return { kind: "route", path: config.path, fields: fields2, body: config.body ?? "json" };
|
|
836
|
+
return { kind: "route", path: config.path, fields: fields2, body: config.body ?? "json", where: `POST ${config.path}` };
|
|
837
837
|
}
|
|
838
838
|
const action = (manifest.actions ?? []).find((a) => a.key === config || a.export === config);
|
|
839
839
|
if (!action) {
|
|
@@ -841,7 +841,7 @@ function loginSpec(manifest, config, warnings) {
|
|
|
841
841
|
return null;
|
|
842
842
|
}
|
|
843
843
|
const fields = action.fields.map((f) => ({ name: f.name, kind: (0, import_core.fieldKind)(f.name) }));
|
|
844
|
-
return { kind: "action", key: action.key, fields, ...action.host ? { host: action.host } : {} };
|
|
844
|
+
return { kind: "action", key: action.key, fields, ...action.host ? { host: action.host } : {}, where: `${action.export} in ${action.file}` };
|
|
845
845
|
}
|
|
846
846
|
async function actionLoginResult(raw, exportName) {
|
|
847
847
|
if (actionNotFound(raw)) return { ok: false, message: "The app's sign-in page didn't run its login. Its developer needs to rebuild the app." };
|
|
@@ -1149,14 +1149,18 @@ function aiReady(manifest, options = {}) {
|
|
|
1149
1149
|
const url = (0, import_core.publicRequestUrl)(req.url, req.headers);
|
|
1150
1150
|
const isPrm = url.endsWith(PRM_SUFFIX);
|
|
1151
1151
|
const resource = brokerGate.resourceFor(isPrm ? url.slice(0, -PRM_SUFFIX.length) : url);
|
|
1152
|
-
await (0, import_core.reportAppLogin)(cfg.auth, resource, login);
|
|
1153
|
-
if (
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1152
|
+
const verdict = await (0, import_core.reportAppLogin)(cfg.auth, resource, login, { where: login?.where, stacks: manifest.authStacks, log: logReady });
|
|
1153
|
+
if (verdict === "open") {
|
|
1154
|
+
if (isPrm) return new Response("not found", { status: 404 });
|
|
1155
|
+
} else {
|
|
1156
|
+
if (isPrm) return brokerGate.metadataResponse(req.method, resource);
|
|
1157
|
+
try {
|
|
1158
|
+
const result = await brokerGate.check(req.headers, resource, `${resource}${PRM_SUFFIX}`);
|
|
1159
|
+
if (!result.ok) return result.response;
|
|
1160
|
+
} catch (err) {
|
|
1161
|
+
console.warn(`${LOG_PREFIX} broker check failed:`, err);
|
|
1162
|
+
return new Response("authorization check failed", { status: 503 });
|
|
1163
|
+
}
|
|
1160
1164
|
}
|
|
1161
1165
|
}
|
|
1162
1166
|
return core(req);
|
package/dist/index.d.cts
CHANGED
|
@@ -85,7 +85,7 @@ interface ManifestPage {
|
|
|
85
85
|
* this request, for Connect with no code. `host` is the page with the
|
|
86
86
|
* action's form, which tool calls redirected to mean "signed out".
|
|
87
87
|
*/
|
|
88
|
-
type ManifestLogin = {
|
|
88
|
+
type ManifestLogin = ({
|
|
89
89
|
kind: "action";
|
|
90
90
|
key: string;
|
|
91
91
|
fields: LoginField[];
|
|
@@ -95,6 +95,9 @@ type ManifestLogin = {
|
|
|
95
95
|
path: string;
|
|
96
96
|
fields: LoginField[];
|
|
97
97
|
body: "json" | "form";
|
|
98
|
+
}) & {
|
|
99
|
+
/** Where it is, for the startup log and the dashboard: "signIn in app/actions/auth.ts". */
|
|
100
|
+
where?: string;
|
|
98
101
|
};
|
|
99
102
|
interface ExposifyManifest {
|
|
100
103
|
info: {
|
|
@@ -111,6 +114,8 @@ interface ExposifyManifest {
|
|
|
111
114
|
actions?: ManifestAction[];
|
|
112
115
|
pages?: ManifestPage[];
|
|
113
116
|
login?: ManifestLogin;
|
|
117
|
+
/** Auth libraries in package.json ("next-auth", "@supabase/ssr", ...), reported with the login. */
|
|
118
|
+
authStacks?: string[];
|
|
114
119
|
/** Docs for search_docs, embedded so they work without a file system. */
|
|
115
120
|
docs: DocSource[];
|
|
116
121
|
/** exposify.descriptions.json's texts, "METHOD /path" -> text. */
|
package/dist/index.d.ts
CHANGED
|
@@ -85,7 +85,7 @@ interface ManifestPage {
|
|
|
85
85
|
* this request, for Connect with no code. `host` is the page with the
|
|
86
86
|
* action's form, which tool calls redirected to mean "signed out".
|
|
87
87
|
*/
|
|
88
|
-
type ManifestLogin = {
|
|
88
|
+
type ManifestLogin = ({
|
|
89
89
|
kind: "action";
|
|
90
90
|
key: string;
|
|
91
91
|
fields: LoginField[];
|
|
@@ -95,6 +95,9 @@ type ManifestLogin = {
|
|
|
95
95
|
path: string;
|
|
96
96
|
fields: LoginField[];
|
|
97
97
|
body: "json" | "form";
|
|
98
|
+
}) & {
|
|
99
|
+
/** Where it is, for the startup log and the dashboard: "signIn in app/actions/auth.ts". */
|
|
100
|
+
where?: string;
|
|
98
101
|
};
|
|
99
102
|
interface ExposifyManifest {
|
|
100
103
|
info: {
|
|
@@ -111,6 +114,8 @@ interface ExposifyManifest {
|
|
|
111
114
|
actions?: ManifestAction[];
|
|
112
115
|
pages?: ManifestPage[];
|
|
113
116
|
login?: ManifestLogin;
|
|
117
|
+
/** Auth libraries in package.json ("next-auth", "@supabase/ssr", ...), reported with the login. */
|
|
118
|
+
authStacks?: string[];
|
|
114
119
|
/** Docs for search_docs, embedded so they work without a file system. */
|
|
115
120
|
docs: DocSource[];
|
|
116
121
|
/** exposify.descriptions.json's texts, "METHOD /path" -> text. */
|
package/dist/index.js
CHANGED
|
@@ -841,7 +841,7 @@ function loginSpec(manifest, config, warnings) {
|
|
|
841
841
|
if (config === void 0) return manifest.login ?? null;
|
|
842
842
|
if (typeof config === "object") {
|
|
843
843
|
const fields2 = config.fields.map((name) => ({ name, kind: fieldKind(name) }));
|
|
844
|
-
return { kind: "route", path: config.path, fields: fields2, body: config.body ?? "json" };
|
|
844
|
+
return { kind: "route", path: config.path, fields: fields2, body: config.body ?? "json", where: `POST ${config.path}` };
|
|
845
845
|
}
|
|
846
846
|
const action = (manifest.actions ?? []).find((a) => a.key === config || a.export === config);
|
|
847
847
|
if (!action) {
|
|
@@ -849,7 +849,7 @@ function loginSpec(manifest, config, warnings) {
|
|
|
849
849
|
return null;
|
|
850
850
|
}
|
|
851
851
|
const fields = action.fields.map((f) => ({ name: f.name, kind: fieldKind(f.name) }));
|
|
852
|
-
return { kind: "action", key: action.key, fields, ...action.host ? { host: action.host } : {} };
|
|
852
|
+
return { kind: "action", key: action.key, fields, ...action.host ? { host: action.host } : {}, where: `${action.export} in ${action.file}` };
|
|
853
853
|
}
|
|
854
854
|
async function actionLoginResult(raw, exportName) {
|
|
855
855
|
if (actionNotFound(raw)) return { ok: false, message: "The app's sign-in page didn't run its login. Its developer needs to rebuild the app." };
|
|
@@ -1157,14 +1157,18 @@ function aiReady(manifest, options = {}) {
|
|
|
1157
1157
|
const url = publicRequestUrl(req.url, req.headers);
|
|
1158
1158
|
const isPrm = url.endsWith(PRM_SUFFIX);
|
|
1159
1159
|
const resource = brokerGate.resourceFor(isPrm ? url.slice(0, -PRM_SUFFIX.length) : url);
|
|
1160
|
-
await reportAppLogin(cfg.auth, resource, login);
|
|
1161
|
-
if (
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
if (
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1160
|
+
const verdict = await reportAppLogin(cfg.auth, resource, login, { where: login?.where, stacks: manifest.authStacks, log: logReady });
|
|
1161
|
+
if (verdict === "open") {
|
|
1162
|
+
if (isPrm) return new Response("not found", { status: 404 });
|
|
1163
|
+
} else {
|
|
1164
|
+
if (isPrm) return brokerGate.metadataResponse(req.method, resource);
|
|
1165
|
+
try {
|
|
1166
|
+
const result = await brokerGate.check(req.headers, resource, `${resource}${PRM_SUFFIX}`);
|
|
1167
|
+
if (!result.ok) return result.response;
|
|
1168
|
+
} catch (err) {
|
|
1169
|
+
console.warn(`${LOG_PREFIX} broker check failed:`, err);
|
|
1170
|
+
return new Response("authorization check failed", { status: 503 });
|
|
1171
|
+
}
|
|
1168
1172
|
}
|
|
1169
1173
|
}
|
|
1170
1174
|
return core(req);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exposify/next",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@babel/parser": "^8.0.0",
|
|
35
|
-
"@exposify/cli": "0.0.
|
|
36
|
-
"@exposify/core": "0.3.
|
|
35
|
+
"@exposify/cli": "0.0.2",
|
|
36
|
+
"@exposify/core": "0.3.14",
|
|
37
37
|
"tinyglobby": "^0.2.10",
|
|
38
38
|
"zod": "^3.24.0"
|
|
39
39
|
},
|