@aotter/mantle-cloudflare 0.0.11-alpha.47 → 0.0.11-alpha.49

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.
@@ -17,6 +17,8 @@ export function createCmsRef(config) {
17
17
  return {
18
18
  manifests: config.manifests,
19
19
  auth: config.auth,
20
+ credentialResolver: config.credentialResolver,
21
+ oauthBearer: config.oauthBearer,
20
22
  get() {
21
23
  if (booted)
22
24
  return booted;
@@ -1 +1 @@
1
- {"version":3,"file":"bootRuntimeOnce.js","sourceRoot":"","sources":["../../src/mount/bootRuntimeOnce.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAEjB,MAAM,wBAAwB,CAAC;AAiBhC,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,MAAM,OAAO,GAAG,gBAAgB,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;QACtB,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;QACtB,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM;QAC9B,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY;QAC1C,sBAAsB,EAAE,MAAM,CAAC,QAAQ,CAAC,sBAAsB;KAC/D,CAAC,CAAC;IAEH,IAAI,MAAM,GAA+B,IAAI,CAAC;IAC9C,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG;YACD,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1B,MAAM,GAAG,OAAO;iBACb,QAAQ,EAAE;iBACV,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;iBACnB,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACb,MAAM,GAAG,IAAI,CAAC;gBACd,MAAM,GAAG,CAAC;YACZ,CAAC,CAAC,CAAC;YACL,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"bootRuntimeOnce.js","sourceRoot":"","sources":["../../src/mount/bootRuntimeOnce.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAEjB,MAAM,wBAAwB,CAAC;AAoBhC,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,MAAM,OAAO,GAAG,gBAAgB,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;QACtB,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;QACtB,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM;QAC9B,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY;QAC1C,sBAAsB,EAAE,MAAM,CAAC,QAAQ,CAAC,sBAAsB;KAC/D,CAAC,CAAC;IAEH,IAAI,MAAM,GAA+B,IAAI,CAAC;IAC9C,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,GAAG;YACD,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1B,MAAM,GAAG,OAAO;iBACb,QAAQ,EAAE;iBACV,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;iBACnB,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACb,MAAM,GAAG,IAAI,CAAC;gBACd,MAAM,GAAG,CAAC;YACZ,CAAC,CAAC,CAAC;YACL,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import type { AnyHandler, CreateCmsRuntimeArgs, PublicPathResolver, TemplateRegistry } from "@aotter/mantle-runtime";
2
2
  import type { Manifest, SiteDefaults } from "@aotter/mantle-spec";
3
3
  import type { Auth } from "../auth/createAuth.js";
4
+ import type { ConsumerCredentialResolver } from "./resolveCaller.js";
4
5
  /**
5
6
  * Consumer-supplied config for the Cloudflare adapter mounts. `auth`
6
7
  * (Better Auth) gates `/admin/api/*` + MCP bearers. `bindings` carries
@@ -27,5 +28,14 @@ export interface CmsConfig {
27
28
  /** Pass-through to runtime: SVG opt-in flag (default false). */
28
29
  readonly mediaAllowSvg?: boolean;
29
30
  readonly auth: Auth;
31
+ /** Site-owned API key / personal-token verifier. Core supplies only
32
+ * normalization and orchestration; storage and issuance stay in
33
+ * consumer code. */
34
+ readonly credentialResolver?: ConsumerCredentialResolver;
35
+ /** Enable OAuth JWT bearer authentication on manifest REST routes. */
36
+ readonly oauthBearer?: {
37
+ readonly audience: string;
38
+ readonly scopes?: readonly string[];
39
+ };
30
40
  }
31
41
  //# sourceMappingURL=cmsConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cmsConfig.d.ts","sourceRoot":"","sources":["../../src/mount/cmsConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,oBAAoB,EAAE,IAAI,GAAG,IAAI,GAAG,QAAQ,CAAC,GAAG;QACtE;;yCAEiC;QACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAC7D;;;;oBAIY;QACZ,QAAQ,CAAC,sBAAsB,CAAC,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,CAAC;KAClF,CAAC;IACF,gEAAgE;IAChE,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB"}
1
+ {"version":3,"file":"cmsConfig.d.ts","sourceRoot":"","sources":["../../src/mount/cmsConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAErE;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,oBAAoB,EAAE,IAAI,GAAG,IAAI,GAAG,QAAQ,CAAC,GAAG;QACtE;;yCAEiC;QACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAC7D;;;;oBAIY;QACZ,QAAQ,CAAC,sBAAsB,CAAC,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,CAAC;KAClF,CAAC;IACF,gEAAgE;IAChE,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;yBAEqB;IACrB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IACzD,sEAAsE;IACtE,QAAQ,CAAC,WAAW,CAAC,EAAE;QACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KACrC,CAAC;CACH"}
@@ -1,4 +1,5 @@
1
1
  export { mountServerEndpoints } from "./mountServerEndpoints.js";
2
+ export { resolveCaller, type CallerResolution, type ConsumerCredentialResolution, type ConsumerCredentialResolver, type ResolveCallerOptions, } from "./resolveCaller.js";
2
3
  export { type CmsRuntimeRef, createCmsRef } from "./bootRuntimeOnce.js";
3
4
  export { createMcpApiHandler, type CreateMcpApiHandlerOptions, } from "./mountMcp.js";
4
5
  export { mountPublicRoutes, type CollectionRouteConfig, type MountPublicRoutesOptions, type PublicRouteContext, type SlugOverride, } from "./mountPublicRoutes.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mount/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,KAAK,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mount/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export { mountServerEndpoints } from "./mountServerEndpoints.js";
2
+ export { resolveCaller, } from "./resolveCaller.js";
2
3
  export { createCmsRef } from "./bootRuntimeOnce.js";
3
4
  export { createMcpApiHandler, } from "./mountMcp.js";
4
5
  export { mountPublicRoutes, } from "./mountPublicRoutes.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mount/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAsB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,mBAAmB,GAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,GAKlB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mount/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,aAAa,GAKd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAsB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,mBAAmB,GAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,GAKlB,MAAM,wBAAwB,CAAC"}
@@ -2,6 +2,10 @@ import type { CmsRuntimeRef } from "./bootRuntimeOnce.js";
2
2
  export interface CreateMcpApiHandlerOptions {
3
3
  readonly ref: CmsRuntimeRef;
4
4
  readonly surface: "staff" | "public";
5
+ /** OAuth scopes required to enter this MCP resource. Defaults to
6
+ * the existing compatibility scope `mcp`. Target-specific scopes
7
+ * remain manifest predicates enforced on tools/call. */
8
+ readonly requiredScopes?: readonly string[];
5
9
  }
6
10
  /**
7
11
  * Build a Cloudflare Worker `ExportedHandler` that serves one MCP
@@ -10,8 +14,8 @@ export interface CreateMcpApiHandlerOptions {
10
14
  *
11
15
  * The OAuthProvider lib verifies the bearer token, decrypts grant
12
16
  * props, and sets `ctx.props` BEFORE calling this handler. We read
13
- * `ctx.props.{userId, role}` (stashed at consent time by
14
- * `mountAuthorize`) and gate staff surfaces on the D1 staff role.
17
+ * immutable grant props and re-read the caller's mutable staff role
18
+ * from D1 on every invocation.
15
19
  *
16
20
  * Note: OAuth scope distinction (`mcp:read` vs `mcp:staff`) used to
17
21
  * differentiate surfaces here. Removed because claude.ai's MCP client
@@ -1 +1 @@
1
- {"version":3,"file":"mountMcp.d.ts","sourceRoot":"","sources":["../../src/mount/mountMcp.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC;CACtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAmF1C"}
1
+ {"version":3,"file":"mountMcp.d.ts","sourceRoot":"","sources":["../../src/mount/mountMcp.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC;;6DAEyD;IACzD,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA2F1C"}
@@ -7,8 +7,8 @@ import { STAFF_ROLE_SET } from "../auth/createAuth.js";
7
7
  *
8
8
  * The OAuthProvider lib verifies the bearer token, decrypts grant
9
9
  * props, and sets `ctx.props` BEFORE calling this handler. We read
10
- * `ctx.props.{userId, role}` (stashed at consent time by
11
- * `mountAuthorize`) and gate staff surfaces on the D1 staff role.
10
+ * immutable grant props and re-read the caller's mutable staff role
11
+ * from D1 on every invocation.
12
12
  *
13
13
  * Note: OAuth scope distinction (`mcp:read` vs `mcp:staff`) used to
14
14
  * differentiate surfaces here. Removed because claude.ai's MCP client
@@ -18,6 +18,7 @@ import { STAFF_ROLE_SET } from "../auth/createAuth.js";
18
18
  */
19
19
  export function createMcpApiHandler(options) {
20
20
  const { ref, surface } = options;
21
+ const requiredScopes = options.requiredScopes ?? ["mcp"];
21
22
  // Key the cached dispatcher to the runtime identity. Without this,
22
23
  // if `ref.get()` rejects + resets and the next call returns a new
23
24
  // runtime instance, the cached dispatcher would silently keep
@@ -28,10 +29,14 @@ export function createMcpApiHandler(options) {
28
29
  async fetch(request, _env, ctx) {
29
30
  const props = ctx.props;
30
31
  if (!props?.userId)
31
- return forbidden();
32
- const role = props.role;
32
+ return forbidden(requiredScopes);
33
+ const grantedScopes = props.scopes?.length ? props.scopes : ["mcp"];
34
+ if (requiredScopes.some((scope) => !grantedScopes.includes(scope))) {
35
+ return forbidden(requiredScopes);
36
+ }
37
+ const role = await ref.auth.getUserRole(props.userId);
33
38
  if (surface === "staff" && (!role || !STAFF_ROLE_SET.has(role))) {
34
- return forbidden();
39
+ return forbidden(requiredScopes);
35
40
  }
36
41
  const runtime = await ref.get();
37
42
  // Media tools require BOTH a storage adapter AND a declared
@@ -86,15 +91,19 @@ export function createMcpApiHandler(options) {
86
91
  staff: role && STAFF_ROLE_SET.has(role)
87
92
  ? { userId: props.userId, role: role }
88
93
  : null,
94
+ clientId: props.clientId ?? null,
95
+ credentialId: null,
96
+ scopes: grantedScopes,
89
97
  });
90
98
  },
91
99
  };
92
100
  }
93
- function forbidden() {
101
+ function forbidden(requiredScopes) {
102
+ const scope = requiredScopes.join(" ");
94
103
  return new Response("forbidden", {
95
104
  status: 403,
96
105
  headers: {
97
- "www-authenticate": `Bearer realm="mcp", error="insufficient_scope"`,
106
+ "www-authenticate": `Bearer realm="mcp", error="insufficient_scope", scope="${scope}"`,
98
107
  "access-control-expose-headers": "WWW-Authenticate",
99
108
  },
100
109
  });
@@ -1 +1 @@
1
- {"version":3,"file":"mountMcp.js","sourceRoot":"","sources":["../../src/mount/mountMcp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mountMcp.js","sourceRoot":"","sources":["../../src/mount/mountMcp.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mountServerEndpoints.d.ts","sourceRoot":"","sources":["../../src/mount/mountServerEndpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AA6B1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAM1D;;;;iBAIiB;AACjB,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,aAAa,GACjB,IAAI,CA6BN;AA0yDD,YAAY,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"mountServerEndpoints.d.ts","sourceRoot":"","sources":["../../src/mount/mountServerEndpoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AA6B1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAO1D;;;;iBAIiB;AACjB,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,aAAa,GACjB,IAAI,CA6BN;AAkwDD,YAAY,EAAE,aAAa,EAAE,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { DiagnosticError, HTTP_STATUS_BY_CODE, MANTLE_REF_KEYWORD, MCP_HINT_KEYWORD, VIEW_PARAMS_RESERVED, isMediaMcpHint, redactForWire, runtimeDiagnostic, } from "@aotter/mantle-spec";
2
2
  import { ViewParamCoercionError, coerceViewParams, evaluateAuthAll, matchPath, } from "@aotter/mantle-runtime";
3
3
  import { indexHtml } from "@aotter/mantle-admin-ui";
4
+ import { resolveCaller } from "./resolveCaller.js";
4
5
  import { STAFF_ROLE_SET } from "../auth/createAuth.js";
5
6
  import { AOTTER_FAVICON_SVG } from "../assets/aotterFavicon.js";
6
7
  const [PAGE_PARAM, SHOW_PARAM] = VIEW_PARAMS_RESERVED;
@@ -22,7 +23,7 @@ export function mountServerEndpoints(app, ref) {
22
23
  app.on(method, honoPath, async (c) => {
23
24
  const runtime = await ref.get();
24
25
  const waitUntil = readWaitUntil(c);
25
- return handleHttpTrigger(c.req.raw, runtime, ref.auth, triggerName, path, waitUntil);
26
+ return handleHttpTrigger(c.req.raw, runtime, ref, triggerName, path, waitUntil);
26
27
  });
27
28
  }
28
29
  for (const v of ref.manifests) {
@@ -38,7 +39,7 @@ export function mountServerEndpoints(app, ref) {
38
39
  app.get(`/api/views/${viewName}`, async (c) => {
39
40
  const runtime = await ref.get();
40
41
  const waitUntil = readWaitUntil(c);
41
- return handleViewRequest(c.req.raw, runtime, viewName, ref.auth, waitUntil, "/api/views");
42
+ return handleViewRequest(c.req.raw, runtime, viewName, ref, waitUntil, "/api/views");
42
43
  });
43
44
  }
44
45
  mountAdminBetterAuth(app, ref, ref.auth);
@@ -261,7 +262,7 @@ function mountAdminBetterAuth(app, ref, auth) {
261
262
  guarded("get", `/admin/api/views/${viewName}`, async (c) => {
262
263
  const runtime = await ref.get();
263
264
  const waitUntil = readWaitUntil(c);
264
- return handleViewRequest(c.req.raw, runtime, viewName, ref.auth, waitUntil, "/admin/api/views");
265
+ return handleViewRequest(c.req.raw, runtime, viewName, ref, waitUntil, "/admin/api/views");
265
266
  });
266
267
  }
267
268
  guarded("get", "/admin/api/operations", () => Response.json({
@@ -1202,6 +1203,12 @@ function adminHandlerContext(c, gate) {
1202
1203
  return {
1203
1204
  user: { id: gate.userId },
1204
1205
  staff: { id: gate.userId, role: gate.role },
1206
+ auth: {
1207
+ credential: "session",
1208
+ credentialId: gate.sessionId,
1209
+ clientId: null,
1210
+ scopes: [],
1211
+ },
1205
1212
  env: {},
1206
1213
  ...(waitUntil ? { waitUntil } : {}),
1207
1214
  };
@@ -1210,7 +1217,7 @@ async function readStaffGate(c, auth) {
1210
1217
  const session = await auth.getSession(c.req.raw);
1211
1218
  if (!session)
1212
1219
  return { kind: "unauth" };
1213
- const role = session.user.role ?? null;
1220
+ const role = await auth.getUserRole(session.user.id);
1214
1221
  const login = session.user.githubLogin ?? null;
1215
1222
  if (!role || !STAFF_ROLE_SET.has(role)) {
1216
1223
  return { kind: "forbidden", login };
@@ -1220,9 +1227,10 @@ async function readStaffGate(c, auth) {
1220
1227
  userId: session.user.id,
1221
1228
  login,
1222
1229
  role: role,
1230
+ sessionId: session.session.id,
1223
1231
  };
1224
1232
  }
1225
- async function handleHttpTrigger(req, runtime, auth, triggerName, triggerPath, waitUntil) {
1233
+ async function handleHttpTrigger(req, runtime, ref, triggerName, triggerPath, waitUntil) {
1226
1234
  const trigger = runtime.triggersByName.get(triggerName);
1227
1235
  if (!trigger) {
1228
1236
  return jsonError({ status: 500, code: "INTERNAL_ERROR", message: `Trigger '${triggerName}' missing post-boot.` });
@@ -1232,6 +1240,16 @@ async function handleHttpTrigger(req, runtime, auth, triggerName, triggerPath, w
1232
1240
  if (!procedure) {
1233
1241
  return jsonError({ status: 500, code: "INTERNAL_ERROR", message: `Procedure '${procName}' missing post-boot.` });
1234
1242
  }
1243
+ const triggerPathPrefix = `${req.method} ${triggerPath}`;
1244
+ const caller = await resolveCaller(req, {
1245
+ auth: ref.auth,
1246
+ credentialResolver: ref.credentialResolver,
1247
+ oauthBearer: ref.oauthBearer,
1248
+ waitUntil,
1249
+ });
1250
+ if (caller.kind === "invalid") {
1251
+ return Response.json({ ok: false, diagnostic: caller.diagnostic }, { status: caller.status });
1252
+ }
1235
1253
  const url = new URL(req.url);
1236
1254
  const params = matchPath(triggerPath, url.pathname) ?? {};
1237
1255
  const body = await readBody(req);
@@ -1239,32 +1257,10 @@ async function handleHttpTrigger(req, runtime, auth, triggerName, triggerPath, w
1239
1257
  // resource identifier (a `DELETE /entries/{id}` body MUST NOT spoof
1240
1258
  // `id`). Body fields fill in non-path inputs only.
1241
1259
  const input = { ...body, ...params };
1242
- const triggerPathPrefix = `${req.method} ${triggerPath}`;
1243
- const ctx = await buildCallerContext(req, auth, waitUntil);
1244
- // Mirror the View handler's 401-vs-403 discipline (see
1245
- // `handleViewRequest`). An auth-gated Procedure called with no
1246
- // session is UNAUTHENTICATED (401); a session whose role fails the
1247
- // predicate is AUTH_DENIED (403). InvokeProcedureUseCase collapses
1248
- // both into AUTH_DENIED if we pass `{ user: null, staff: null }`
1249
- // as ctx, so we pre-check here.
1250
- if (procedure.spec.requires?.auth && !ctx) {
1251
- return Response.json({
1252
- ok: false,
1253
- diagnostic: runtimeDiagnostic({
1254
- code: "UNAUTHENTICATED",
1255
- severity: "error",
1256
- path: triggerPathPrefix,
1257
- expected: "authenticated session",
1258
- message: `Procedure '${procName}' requires authentication.`,
1259
- }),
1260
- }, { status: 401 });
1261
- }
1262
- const wu = waitUntil ? { waitUntil } : {};
1263
- const invokeCtx = ctx ?? { user: null, staff: null, env: {}, ...wu };
1264
1260
  const result = await runtime.invokeProcedure.execute({
1265
1261
  procedure,
1266
1262
  input,
1267
- ctx: invokeCtx,
1263
+ ctx: caller.context,
1268
1264
  pathPrefix: triggerPathPrefix,
1269
1265
  });
1270
1266
  if (result.ok) {
@@ -1273,7 +1269,7 @@ async function handleHttpTrigger(req, runtime, auth, triggerName, triggerPath, w
1273
1269
  const status = HTTP_STATUS_BY_CODE[result.diagnostic.code] ?? 500;
1274
1270
  return Response.json({ ok: false, diagnostic: result.diagnostic }, { status });
1275
1271
  }
1276
- async function handleViewRequest(req, runtime, viewName, auth, waitUntil,
1272
+ async function handleViewRequest(req, runtime, viewName, ref, waitUntil,
1277
1273
  // Mount prefix for this View's route. Passed by the caller because
1278
1274
  // the same handler serves BOTH the public mount (`/api/views`) and
1279
1275
  // the staff mount (`/admin/api/views`); hardcoding the public prefix
@@ -1284,29 +1280,22 @@ mountPath) {
1284
1280
  return jsonError({ status: 500, code: "INTERNAL_ERROR", message: `View '${viewName}' missing post-boot.` });
1285
1281
  }
1286
1282
  const viewPath = `GET ${mountPath}/${viewName}`;
1287
- // Resolve caller identity FIRST and evaluate `requires.auth.all`
1288
- // BEFORE param coercion. Two reasons:
1289
- // (1) a param-coercion 400 against an auth-gated View would leak
1290
- // the View's parameter contract to an unauthorized caller —
1291
- // this matters for both anonymous probes AND authenticated
1292
- // users without the required role.
1293
- // (2) the UNAUTHENTICATED branch in ExecuteViewUseCase only fires
1294
- // when ctx is undefined, so passing a guest ctx for no-session
1295
- // would collapse 401 and 403 into the same AUTH_DENIED.
1296
- const ctx = await buildCallerContext(req, auth, waitUntil);
1283
+ // Resolve caller and evaluate static auth BEFORE query coercion so a
1284
+ // protected View does not leak its parameter contract. The runtime
1285
+ // evaluates the same predicates again before guard/query execution;
1286
+ // this adapter preflight exists only to preserve the no-leak order at
1287
+ // the HTTP parsing boundary.
1288
+ const caller = await resolveCaller(req, {
1289
+ auth: ref.auth,
1290
+ credentialResolver: ref.credentialResolver,
1291
+ oauthBearer: ref.oauthBearer,
1292
+ waitUntil,
1293
+ });
1294
+ if (caller.kind === "invalid") {
1295
+ return Response.json({ ok: false, diagnostic: caller.diagnostic }, { status: caller.status });
1296
+ }
1297
+ const ctx = caller.context;
1297
1298
  if (view.spec.requires?.auth) {
1298
- if (!ctx) {
1299
- return Response.json({
1300
- ok: false,
1301
- diagnostic: runtimeDiagnostic({
1302
- code: "UNAUTHENTICATED",
1303
- severity: "error",
1304
- path: viewPath,
1305
- expected: "authenticated session",
1306
- message: `View '${viewName}' requires authentication.`,
1307
- }),
1308
- }, { status: 401 });
1309
- }
1310
1299
  const denial = evaluateAuthAll(view.spec.requires, ctx, viewPath, "runtime");
1311
1300
  if (denial) {
1312
1301
  return Response.json({
@@ -1349,35 +1338,6 @@ mountPath) {
1349
1338
  const status = HTTP_STATUS_BY_CODE[result.diagnostic.code] ?? 500;
1350
1339
  return Response.json({ ok: false, diagnostic: result.diagnostic }, { status });
1351
1340
  }
1352
- /**
1353
- * Resolve caller identity for a View or HTTP-Trigger request from the
1354
- * Better Auth cookie session. Returns `undefined` when there is no
1355
- * session so callers can distinguish 401 (no session) from 403
1356
- * (session but wrong role) — `ExecuteViewUseCase` and the
1357
- * `handleHttpTrigger` pre-check both rely on this signal.
1358
- *
1359
- * Used by both `handleViewRequest` and `handleHttpTrigger` so the
1360
- * two HTTP surfaces resolve identity identically.
1361
- *
1362
- * Note: this resolves cookie sessions only. OAuth bearer tokens
1363
- * (issued by `createOAuthProvider` for MCP callers) are NOT verified
1364
- * here — bearer-authenticated identity belongs on the MCP surface,
1365
- * not the HTTP Trigger surface, so a bearer-only caller hitting an
1366
- * auth-gated Trigger will land at the 401 branch in
1367
- * `handleHttpTrigger`. Procedures that need to be agent-callable
1368
- * should be reached via `/mcp` or `/mcp/staff` (see #281).
1369
- */
1370
- async function buildCallerContext(req, auth, waitUntil) {
1371
- const session = await auth.getSession(req);
1372
- if (!session)
1373
- return undefined;
1374
- const wu = waitUntil ? { waitUntil } : {};
1375
- const role = await auth.getUserRole(session.user.id);
1376
- const staff = role && STAFF_ROLE_SET.has(role)
1377
- ? { id: session.user.id, role: role }
1378
- : null;
1379
- return { user: { id: session.user.id }, staff, env: {}, ...wu };
1380
- }
1381
1341
  function parsePositiveInt(raw) {
1382
1342
  if (raw == null || raw === "")
1383
1343
  return undefined;