@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 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`);
@@ -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 (isPrm) return brokerGate.metadataResponse(req.method, resource);
1154
- try {
1155
- const result = await brokerGate.check(req.headers, resource, `${resource}${PRM_SUFFIX}`);
1156
- if (!result.ok) return result.response;
1157
- } catch (err) {
1158
- console.warn(`${LOG_PREFIX} broker check failed:`, err);
1159
- return new Response("authorization check failed", { status: 503 });
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 (isPrm) return brokerGate.metadataResponse(req.method, resource);
1162
- try {
1163
- const result = await brokerGate.check(req.headers, resource, `${resource}${PRM_SUFFIX}`);
1164
- if (!result.ok) return result.response;
1165
- } catch (err) {
1166
- console.warn(`${LOG_PREFIX} broker check failed:`, err);
1167
- return new Response("authorization check failed", { status: 503 });
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.1",
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.1",
36
- "@exposify/core": "0.3.13",
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
  },