@kya-os/create-mcpi-app 1.10.2 → 1.10.4

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.
@@ -45834,6 +45834,18 @@ var require_oauth_config_service = __commonJS({
45834
45834
  Object.defineProperty(exports, "__esModule", { value: true });
45835
45835
  exports.OAuthConfigService = void 0;
45836
45836
  var oauth_config_cache_js_1 = require_oauth_config_cache();
45837
+ function mapProviderSecretMetadata(raw2) {
45838
+ if (!raw2 || typeof raw2 !== "object")
45839
+ return void 0;
45840
+ const m3 = raw2;
45841
+ const metadata = {
45842
+ clientSecretName: m3.clientSecretName ?? m3.client_secret_name,
45843
+ clientIdSecretName: m3.clientIdSecretName ?? m3.client_id_secret_name,
45844
+ apiKeySecretName: m3.apiKeySecretName ?? m3.api_key_secret_name,
45845
+ clientSecretVersion: m3.clientSecretVersion ?? m3.client_secret_version
45846
+ };
45847
+ return metadata;
45848
+ }
45837
45849
  var OAuthConfigService2 = class {
45838
45850
  config;
45839
45851
  constructor(config4) {
@@ -45907,7 +45919,16 @@ var require_oauth_config_service = __commonJS({
45907
45919
  customParams: p3.customParams ?? p3.custom_params,
45908
45920
  tokenEndpointAuthMethod: p3.tokenEndpointAuthMethod ?? p3.token_endpoint_auth_method,
45909
45921
  responseType: p3.responseType ?? p3.response_type,
45910
- grantType: p3.grantType ?? p3.grant_type
45922
+ grantType: p3.grantType ?? p3.grant_type,
45923
+ // Provider-registry secret metadata (clientSecretName etc.). REQUIRED:
45924
+ // OAuthService.resolveClientSecret resolves a confidential provider's
45925
+ // client secret from secure storage via `metadata.clientSecretName`
45926
+ // (the AgentShield /providers response intentionally omits the plaintext
45927
+ // `clientSecret`). Without mapping this field here, `metadata` is
45928
+ // undefined, resolveClientSecret falls back to the (absent) inline
45929
+ // clientSecret, and the worker sends an empty secret — token exchange
45930
+ // then fails with "client_id and/or client_secret incorrect".
45931
+ metadata: mapProviderSecretMetadata(p3.metadata)
45911
45932
  };
45912
45933
  }
45913
45934
  const configuredProvider = result.data.configuredProvider ?? result.data.configured_provider ?? null;
@@ -141492,6 +141513,21 @@ var INTERNAL_PICKUP_INFO = "/_internal/pickup/info";
141492
141513
 
141493
141514
  // ../mcp-i-cloudflare/dist/delegation-http/anchor-do.js
141494
141515
  init_storage_keys();
141516
+ function anchorSnapshot(rec) {
141517
+ return {
141518
+ sid: rec.sid,
141519
+ status: rec.status,
141520
+ requiredScopes: rec.requiredScopes,
141521
+ minAssurance: rec.minAssurance,
141522
+ expiresAt: rec.expiresAt,
141523
+ createdAt: rec.createdAt,
141524
+ registeredAtMs: rec.registeredAtMs,
141525
+ issuedAtMs: rec.issuedAtMs,
141526
+ agentDid: rec.agentDid,
141527
+ audience: rec.audience,
141528
+ serverDid: rec.serverDid
141529
+ };
141530
+ }
141495
141531
  var pendingBody = () => ({ status: "pending" });
141496
141532
  var pinnedErr = () => ({ error: KYAOS_ERRORS.pickupPinned });
141497
141533
  var invalidSessionErr = () => ({ error: KYAOS_ERRORS.invalidSession });
@@ -141499,7 +141535,12 @@ var pickupExpiredErr = () => ({ error: KYAOS_ERRORS.pickupExpired });
141499
141535
  function reduceCreate(rec, input, now2) {
141500
141536
  const i2 = input;
141501
141537
  if (rec && now2 <= rec.expiresAt) {
141502
- return { response: { status: 201, body: { success: true, reused: true } } };
141538
+ return {
141539
+ response: {
141540
+ status: 201,
141541
+ body: { success: true, reused: true, anchor: anchorSnapshot(rec) }
141542
+ }
141543
+ };
141503
141544
  }
141504
141545
  const record4 = {
141505
141546
  sid: i2.sid,
@@ -141512,6 +141553,8 @@ function reduceCreate(rec, input, now2) {
141512
141553
  agentDid: typeof i2.agentDid === "string" ? i2.agentDid : void 0,
141513
141554
  audience: typeof i2.audience === "string" ? i2.audience : void 0,
141514
141555
  serverDid: typeof i2.serverDid === "string" ? i2.serverDid : void 0,
141556
+ registeredAtMs: typeof i2.registeredAtMs === "number" ? i2.registeredAtMs : void 0,
141557
+ issuedAtMs: now2,
141515
141558
  pin: i2.pin ? {
141516
141559
  type: i2.pin.type,
141517
141560
  valueSha256: i2.pin.valueSha256,
@@ -141519,7 +141562,13 @@ function reduceCreate(rec, input, now2) {
141519
141562
  source: "challenge"
141520
141563
  } : void 0
141521
141564
  };
141522
- return { record: record4, response: { status: 201, body: { success: true } } };
141565
+ return {
141566
+ record: record4,
141567
+ response: {
141568
+ status: 201,
141569
+ body: { success: true, anchor: anchorSnapshot(record4) }
141570
+ }
141571
+ };
141523
141572
  }
141524
141573
  function reducePoll(rec, holder, now2) {
141525
141574
  if (!rec) {
@@ -141663,7 +141712,7 @@ async function handlePickupInternal(ctx, request, now2) {
141663
141712
  // ../mcp-i-cloudflare/package.json
141664
141713
  var package_default = {
141665
141714
  name: "@kya-os/mcp-i-cloudflare",
141666
- version: "1.12.0",
141715
+ version: "1.12.2",
141667
141716
  description: "Cloudflare Workers adapter for MCP-I framework",
141668
141717
  main: "dist/index.js",
141669
141718
  types: "dist/index.d.ts",
@@ -141692,9 +141741,9 @@ var package_default = {
141692
141741
  },
141693
141742
  dependencies: {
141694
141743
  "@kya-os/consent": "^0.1.41",
141695
- "@kya-os/contracts": "^1.9.0",
141744
+ "@kya-os/contracts": "^1.9.1",
141696
141745
  "@kya-os/mcp": "^1.10.1",
141697
- "@kya-os/mcp-i-core": "^1.8.1",
141746
+ "@kya-os/mcp-i-core": "^1.8.2",
141698
141747
  "@kya-os/mcp-i-runtime": "^1.0.0",
141699
141748
  "@kya-os/provider-registry": "^0.1.7",
141700
141749
  "@modelcontextprotocol/sdk": "^1.25.2",
@@ -141881,6 +141930,16 @@ function registrationRateLimited(now2) {
141881
141930
 
141882
141931
  // ../mcp-i-cloudflare/dist/delegation-http/anchor-registration-validate.js
141883
141932
  var DID_RE = /^did:(key|web):.+$/;
141933
+ var SYNTHETIC_DETECTED_DID_PREFIX = "did:web:detected:";
141934
+ function didIssueMessage(value) {
141935
+ if (typeof value !== "string" || !DID_RE.test(value)) {
141936
+ return "Invalid DID format. Must be did:key: or did:web:";
141937
+ }
141938
+ if (value.startsWith(SYNTHETIC_DETECTED_DID_PREFIX)) {
141939
+ return "Synthetic detected DIDs are not valid KYA-OS identities";
141940
+ }
141941
+ return null;
141942
+ }
141884
141943
  function isRecord2(value) {
141885
141944
  return typeof value === "object" && value !== null && !Array.isArray(value);
141886
141945
  }
@@ -141914,17 +141973,17 @@ function validateChallenge(issues, raw2) {
141914
141973
  checkOptionalString(issues, "challenge.pep_surface", raw2.pep_surface, 64);
141915
141974
  checkOptionalString(issues, "challenge.verdict", raw2.verdict, 64);
141916
141975
  checkOptionalString(issues, "challenge.challenge_pin", raw2.challenge_pin, 512);
141917
- if (raw2.detected_agent_did !== void 0 && (typeof raw2.detected_agent_did !== "string" || !DID_RE.test(raw2.detected_agent_did))) {
141918
- issues.push({
141919
- path: "challenge.detected_agent_did",
141920
- message: "Invalid DID format. Must be did:key: or did:web:"
141921
- });
141976
+ if (raw2.detected_agent_did !== void 0) {
141977
+ const issue4 = didIssueMessage(raw2.detected_agent_did);
141978
+ if (issue4) {
141979
+ issues.push({ path: "challenge.detected_agent_did", message: issue4 });
141980
+ }
141922
141981
  }
141923
- if (raw2.audience !== void 0 && (typeof raw2.audience !== "string" || !DID_RE.test(raw2.audience))) {
141924
- issues.push({
141925
- path: "challenge.audience",
141926
- message: "Invalid DID format. Must be did:key: or did:web:"
141927
- });
141982
+ if (raw2.audience !== void 0) {
141983
+ const issue4 = didIssueMessage(raw2.audience);
141984
+ if (issue4) {
141985
+ issues.push({ path: "challenge.audience", message: issue4 });
141986
+ }
141928
141987
  }
141929
141988
  if (issues.length > issuesBefore)
141930
141989
  return void 0;
@@ -141946,17 +142005,21 @@ function validateRegistrationBody(raw2) {
141946
142005
  }
141947
142006
  const issues = [];
141948
142007
  checkString(issues, "session_id", raw2.session_id, 255);
141949
- if (typeof raw2.agent_did !== "string" || !DID_RE.test(raw2.agent_did)) {
142008
+ {
142009
+ const issue4 = didIssueMessage(raw2.agent_did);
142010
+ if (issue4)
142011
+ issues.push({ path: "agent_did", message: issue4 });
142012
+ }
142013
+ if (typeof raw2.project_id !== "string" || raw2.project_id.length < 1) {
141950
142014
  issues.push({
141951
- path: "agent_did",
141952
- message: "Invalid DID format. Must be did:key: or did:web:"
142015
+ path: "project_id",
142016
+ message: "project_id must be a non-empty string"
141953
142017
  });
141954
142018
  }
141955
- checkString(issues, "project_id", raw2.project_id, 255);
141956
- if (typeof raw2.created_at !== "number" || !Number.isInteger(raw2.created_at) || raw2.created_at <= 0) {
142019
+ if (typeof raw2.created_at !== "number" || !Number.isInteger(raw2.created_at) || raw2.created_at <= 0 || raw2.created_at > 864e13) {
141957
142020
  issues.push({
141958
142021
  path: "created_at",
141959
- message: "created_at must be a positive unix-ms integer"
142022
+ message: "created_at must be a valid positive unix-ms integer"
141960
142023
  });
141961
142024
  }
141962
142025
  const clientInfo = raw2.client_info;
@@ -141969,11 +142032,10 @@ function validateRegistrationBody(raw2) {
141969
142032
  checkString(issues, "client_info.name", clientInfo.name, 255);
141970
142033
  checkOptionalString(issues, "client_info.version", clientInfo.version, 50);
141971
142034
  }
141972
- if (raw2.server_did !== void 0 && (typeof raw2.server_did !== "string" || !DID_RE.test(raw2.server_did))) {
141973
- issues.push({
141974
- path: "server_did",
141975
- message: "Invalid DID format. Must be did:key: or did:web:"
141976
- });
142035
+ if (raw2.server_did !== void 0) {
142036
+ const issue4 = didIssueMessage(raw2.server_did);
142037
+ if (issue4)
142038
+ issues.push({ path: "server_did", message: issue4 });
141977
142039
  }
141978
142040
  const challenge = validateChallenge(issues, raw2.challenge);
141979
142041
  if (raw2.challenge !== void 0 && typeof raw2.session_id === "string" && raw2.session_id.length < 22) {
@@ -142002,7 +142064,10 @@ function validateRegistrationBody(raw2) {
142002
142064
  // ../mcp-i-cloudflare/dist/delegation-http/anchor-registration.js
142003
142065
  var DO_INTERNAL_ORIGIN = "https://do.internal";
142004
142066
  function isAnchorRegistrationEnabled(cfg, env2) {
142005
- return cfg !== null && cfg.remoteAnchorRegistration && typeof env2.AGENTSHIELD_API_KEY === "string" && env2.AGENTSHIELD_API_KEY.length > 0;
142067
+ return cfg !== null && cfg.remoteAnchorRegistration && typeof env2.AGENTSHIELD_API_KEY === "string" && env2.AGENTSHIELD_API_KEY.length > 0 && // No anchor store, no registration surface: getAnchorStub throws on an
142068
+ // unbound MCP_OBJECT, so an unbound deployment must 404 like every other
142069
+ // unprovisioned state instead of 500ing per request.
142070
+ env2.MCP_OBJECT !== void 0;
142006
142071
  }
142007
142072
  function deriveRegistrationSid(sessionId) {
142008
142073
  if (isAnchorSid(sessionId))
@@ -142032,41 +142097,37 @@ async function callAnchor(env2, deps, sid, internalPath, body) {
142032
142097
  }
142033
142098
  async function ensureAnchor(env2, cfg, deps, sid, challenge, session) {
142034
142099
  const pin = challenge.challengePin && cfg.allowUnverifiedKeyidHolders ? { type: "keyid", valueSha256: sha256Hex(challenge.challengePin) } : void 0;
142035
- const created = await callAnchor(env2, deps, sid, INTERNAL_PICKUP_CREATE, {
142036
- sid,
142037
- requiredScopes: challenge.requiredScopes,
142038
- pollIntervalS: cfg.pollIntervalS,
142039
- anchorTtlS: cfg.anchorTtlS,
142040
- delegationExpiresInS: cfg.delegationExpiresInS,
142041
- agentDid: challenge.detectedAgentDid ?? session.agentDid,
142042
- // Cross-resource claim inputs (drive the minted VC's aud / server_did —
142043
- // see consent-anchor-bridge's withCrossResourceClaims).
142044
- ...challenge.audience ? { audience: challenge.audience } : {},
142045
- ...session.serverDid ? { serverDid: session.serverDid } : {},
142046
- ...pin ? { pin } : {}
142047
- });
142048
- if (created.status !== 201) {
142049
- return {
142050
- error: errorResponse(502, "anchor_unavailable", "The anchor store did not accept the registration")
142051
- };
142052
- }
142053
- let reused = false;
142100
+ const anchorUnavailable = {
142101
+ error: errorResponse(502, "anchor_unavailable", "The anchor store did not accept the registration")
142102
+ };
142103
+ let created;
142104
+ let body;
142054
142105
  try {
142055
- reused = (await created.json()).reused === true;
142056
- } catch {
142106
+ created = await callAnchor(env2, deps, sid, INTERNAL_PICKUP_CREATE, {
142107
+ sid,
142108
+ requiredScopes: challenge.requiredScopes,
142109
+ pollIntervalS: cfg.pollIntervalS,
142110
+ anchorTtlS: cfg.anchorTtlS,
142111
+ delegationExpiresInS: cfg.delegationExpiresInS,
142112
+ agentDid: challenge.detectedAgentDid ?? session.agentDid,
142113
+ registeredAtMs: session.registeredAtMs,
142114
+ // Cross-resource claim inputs (drive the minted VC's aud / server_did —
142115
+ // see consent-anchor-bridge's withCrossResourceClaims).
142116
+ ...challenge.audience ? { audience: challenge.audience } : {},
142117
+ ...session.serverDid ? { serverDid: session.serverDid } : {},
142118
+ ...pin ? { pin } : {}
142119
+ });
142120
+ if (created.status !== 201)
142121
+ return anchorUnavailable;
142122
+ body = await created.json();
142123
+ } catch (error87) {
142124
+ console.warn(`[kya-http] anchor create failed (sid=${sid}):`, error87 instanceof Error ? error87.message : String(error87));
142125
+ return anchorUnavailable;
142057
142126
  }
142058
- const readBack = await callAnchor(env2, deps, sid, INTERNAL_PICKUP_INFO, {
142059
- sid
142060
- });
142061
- if (readBack.status !== 200) {
142062
- return {
142063
- error: errorResponse(502, "anchor_unavailable", "The registered anchor could not be read back")
142064
- };
142127
+ if (!body.anchor || !Array.isArray(body.anchor.requiredScopes)) {
142128
+ return anchorUnavailable;
142065
142129
  }
142066
- return {
142067
- isNew: !reused,
142068
- snapshot: await readBack.json()
142069
- };
142130
+ return { isNew: body.reused !== true, snapshot: body.anchor };
142070
142131
  }
142071
142132
  async function handleAnchorRegistration(c, env2, cfg, deps) {
142072
142133
  if (!registrarAuthorized(env2, c.req.header("Authorization"))) {
@@ -142092,9 +142153,13 @@ async function handleAnchorRegistration(c, env2, cfg, deps) {
142092
142153
  return errorResponse(401, "unauthorized", "This endpoint only accepts challenge registration");
142093
142154
  }
142094
142155
  const sid = deriveRegistrationSid(validated.input.sessionId);
142156
+ if (!challenge.audience) {
142157
+ console.warn(`[kya-http] external registration without challenge.audience (sid=${sid}): the minted credential will FAIL an org-pinned \xA74.3 audience gate; cross-resource use requires the registrar to send challenge.audience`);
142158
+ }
142095
142159
  const anchor = await ensureAnchor(env2, cfg, deps, sid, challenge, {
142096
142160
  agentDid: validated.input.agentDid,
142097
- serverDid: validated.input.serverDid
142161
+ serverDid: validated.input.serverDid,
142162
+ registeredAtMs: validated.input.createdAt
142098
142163
  });
142099
142164
  if ("error" in anchor)
142100
142165
  return anchor.error;
@@ -142118,17 +142183,24 @@ async function handleAnchorRegistration(c, env2, cfg, deps) {
142118
142183
  console.warn(`[kya-http] registration challenge_proof signing failed (sid=${sid}):`, error87 instanceof Error ? error87.message : String(error87));
142119
142184
  return errorResponse(502, "proof_unavailable", "The challenge proof could not be signed");
142120
142185
  }
142186
+ const createdAtMs = anchor.snapshot.registeredAtMs ?? validated.input.createdAt;
142187
+ const issuedAtMs = anchor.snapshot.issuedAtMs ?? Date.now();
142121
142188
  return new Response(JSON.stringify({
142122
142189
  success: true,
142123
142190
  data: {
142124
142191
  session_id: sid,
142125
142192
  registered: true,
142126
- created_at: new Date(validated.input.createdAt).toISOString(),
142193
+ created_at: new Date(createdAtMs).toISOString(),
142127
142194
  challenge: {
142128
142195
  consent_uri: consentUri,
142129
142196
  challenge_proof: challengeProof,
142130
142197
  required_scopes: anchor.snapshot.requiredScopes,
142131
- issued_at: Date.now()
142198
+ issued_at: issuedAtMs,
142199
+ // ADDITIVE diagnostic (not in the frozen conformance key set, ignored
142200
+ // by both existing parsers): whether the minted credential will carry
142201
+ // the §4.3 cross-resource claims. False means no audience was
142202
+ // registered — the credential only self-verifies at this worker.
142203
+ cross_resource: typeof anchor.snapshot.audience === "string"
142132
142204
  }
142133
142205
  }
142134
142206
  }), {
@@ -147376,6 +147448,190 @@ async function handlePickupGet(c, env2, cfg) {
147376
147448
  init_dist2();
147377
147449
  init_crypto();
147378
147450
  init_storage();
147451
+
147452
+ // ../mcp-i-cloudflare/dist/delegation-http/credential-consent.js
147453
+ function readString(entry, camel, snake) {
147454
+ const value = entry[camel] ?? entry[snake];
147455
+ return typeof value === "string" ? value : void 0;
147456
+ }
147457
+ function readRecord(entry, camel, snake) {
147458
+ const value = entry[camel] ?? entry[snake];
147459
+ return value && typeof value === "object" ? value : void 0;
147460
+ }
147461
+ function isCredentialTyped(entry) {
147462
+ return !!entry && (entry.type === "password" || entry.type === "credential") && entry.configured !== false;
147463
+ }
147464
+ function buildSuccessCheck(raw2) {
147465
+ if (!raw2)
147466
+ return void 0;
147467
+ const path = typeof raw2.path === "string" ? raw2.path : void 0;
147468
+ const expectedValue = raw2.expectedValue ?? raw2.expected_value;
147469
+ if (!path || expectedValue === void 0)
147470
+ return void 0;
147471
+ if (typeof expectedValue !== "string" && typeof expectedValue !== "boolean" && typeof expectedValue !== "number") {
147472
+ return void 0;
147473
+ }
147474
+ return { path, expectedValue };
147475
+ }
147476
+ function buildCredentialConfig(entry) {
147477
+ const authEndpoint = readString(entry, "authEndpoint", "auth_endpoint");
147478
+ const requestBodyTemplate = readRecord(entry, "requestBodyTemplate", "request_body_template");
147479
+ const rawResponseFields = readRecord(entry, "responseFields", "response_fields");
147480
+ if (!authEndpoint || !requestBodyTemplate || !rawResponseFields)
147481
+ return null;
147482
+ const sessionToken = readString(rawResponseFields, "sessionToken", "session_token");
147483
+ if (!sessionToken)
147484
+ return null;
147485
+ const responseFields = {
147486
+ sessionToken,
147487
+ userId: readString(rawResponseFields, "userId", "user_id"),
147488
+ userEmail: readString(rawResponseFields, "userEmail", "user_email"),
147489
+ userDisplayName: readString(rawResponseFields, "userDisplayName", "user_display_name"),
147490
+ expiresIn: readString(rawResponseFields, "expiresIn", "expires_in")
147491
+ };
147492
+ const successCheck = buildSuccessCheck(readRecord(entry, "successCheck", "success_check"));
147493
+ const headers = readRecord(entry, "headers", "headers");
147494
+ const tokenUsage = readString(entry, "tokenUsage", "token_usage");
147495
+ const tokenHeader = readString(entry, "tokenHeader", "token_header");
147496
+ const cookieFormat = readString(entry, "cookieFormat", "cookie_format");
147497
+ return {
147498
+ // The handler ignores `type`, but the contract's discriminant is "credential".
147499
+ type: "credential",
147500
+ displayName: readString(entry, "displayName", "display_name"),
147501
+ authEndpoint,
147502
+ requestBodyTemplate,
147503
+ responseFields,
147504
+ ...successCheck ? { successCheck } : {},
147505
+ ...headers ? { headers } : {},
147506
+ ...tokenUsage ? { tokenUsage } : {},
147507
+ ...tokenHeader ? { tokenHeader } : {},
147508
+ ...cookieFormat ? { cookieFormat } : {}
147509
+ };
147510
+ }
147511
+ async function resolveAnchorCredentialProvider(env2, _scopes) {
147512
+ const apiKey = env2.AGENTSHIELD_API_KEY;
147513
+ const projectId = env2.AGENTSHIELD_PROJECT_ID;
147514
+ if (!apiKey || !projectId)
147515
+ return { status: "none" };
147516
+ const agentShieldUrl = env2.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
147517
+ let providersMap;
147518
+ let configuredProvider;
147519
+ try {
147520
+ const response = await fetch(`${agentShieldUrl}/api/v1/bouncer/projects/${encodeURIComponent(projectId)}/providers`, {
147521
+ method: "GET",
147522
+ headers: {
147523
+ Authorization: `Bearer ${apiKey}`,
147524
+ "Content-Type": "application/json"
147525
+ }
147526
+ });
147527
+ if (!response.ok)
147528
+ return { status: "unavailable" };
147529
+ const body = await response.json();
147530
+ if (body.success !== true || !body.data || typeof body.data.providers !== "object" || body.data.providers === null) {
147531
+ return { status: "unavailable" };
147532
+ }
147533
+ providersMap = body.data.providers;
147534
+ configuredProvider = body.data.configuredProvider ?? body.data.configured_provider ?? null;
147535
+ } catch {
147536
+ return { status: "unavailable" };
147537
+ }
147538
+ const credentialIds = Object.keys(providersMap).filter((id) => isCredentialTyped(providersMap[id]));
147539
+ if (credentialIds.length === 0)
147540
+ return { status: "none" };
147541
+ const chosenId = configuredProvider && isCredentialTyped(providersMap[configuredProvider]) ? configuredProvider : credentialIds.length === 1 ? credentialIds[0] : null;
147542
+ if (!chosenId)
147543
+ return { status: "unavailable" };
147544
+ const config4 = buildCredentialConfig(providersMap[chosenId]);
147545
+ if (!config4)
147546
+ return { status: "unavailable" };
147547
+ return {
147548
+ status: "credential",
147549
+ provider: {
147550
+ providerId: chosenId,
147551
+ displayName: config4.displayName || chosenId,
147552
+ config: config4
147553
+ }
147554
+ };
147555
+ }
147556
+ async function resolveCredentialIdentity(env2, params) {
147557
+ const agentShieldUrl = env2.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
147558
+ const apiKey = env2.AGENTSHIELD_API_KEY;
147559
+ if (!apiKey)
147560
+ return { success: false };
147561
+ try {
147562
+ const response = await fetch(`${agentShieldUrl}/api/v1/bouncer/identity/resolve`, {
147563
+ method: "POST",
147564
+ headers: {
147565
+ "X-API-Key": apiKey,
147566
+ "Content-Type": "application/json"
147567
+ },
147568
+ body: JSON.stringify({
147569
+ project_id: params.projectId,
147570
+ credential_result: {
147571
+ provider: params.provider,
147572
+ user_id: params.userId,
147573
+ email: params.userEmail,
147574
+ name: params.userDisplayName
147575
+ }
147576
+ })
147577
+ });
147578
+ if (!response.ok)
147579
+ return { success: false };
147580
+ const data = await response.json();
147581
+ const userDid = data?.data?.user_did;
147582
+ return userDid ? { success: true, userDid } : { success: false };
147583
+ } catch {
147584
+ return { success: false };
147585
+ }
147586
+ }
147587
+ function sidToDelegationUuid(sid) {
147588
+ const h5 = sha256Hex(sid).slice(0, 32).split("");
147589
+ h5[12] = "4";
147590
+ h5[16] = (parseInt(h5[16], 16) & 3 | 8).toString(16);
147591
+ const s5 = h5.join("");
147592
+ return `${s5.slice(0, 8)}-${s5.slice(8, 12)}-${s5.slice(12, 16)}-${s5.slice(16, 20)}-${s5.slice(20, 32)}`;
147593
+ }
147594
+ async function notifyDelegation(env2, params) {
147595
+ const apiKey = env2.AGENTSHIELD_API_KEY;
147596
+ const projectId = env2.AGENTSHIELD_PROJECT_ID;
147597
+ if (!apiKey || !projectId)
147598
+ return;
147599
+ const agentShieldUrl = env2.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
147600
+ try {
147601
+ const response = await fetch(`${agentShieldUrl}/api/v1/bouncer/delegations/notify`, {
147602
+ method: "POST",
147603
+ headers: {
147604
+ "X-API-Key": apiKey,
147605
+ "Content-Type": "application/json"
147606
+ },
147607
+ body: JSON.stringify({
147608
+ delegation_id: sidToDelegationUuid(params.sid),
147609
+ agent_did: params.agentDid,
147610
+ agent_name: params.agentName || void 0,
147611
+ user_did: params.userDid,
147612
+ user_id: params.userId || void 0,
147613
+ user_identifier: params.userIdentifier || void 0,
147614
+ scopes: params.scopes,
147615
+ provider: params.provider,
147616
+ project_id: projectId,
147617
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
147618
+ expires_at: params.expiresAt || void 0,
147619
+ metadata: {
147620
+ source: "mcp-i-anchor-consent",
147621
+ sid: params.sid,
147622
+ ...params.metadata
147623
+ }
147624
+ })
147625
+ });
147626
+ if (!response.ok) {
147627
+ console.warn(`[kya-http] delegation notify failed (non-blocking): ${response.status} sid=${params.sid}`);
147628
+ }
147629
+ } catch (error87) {
147630
+ console.warn(`[kya-http] delegation notify failed (non-blocking): ${error87 instanceof Error ? error87.message : String(error87)} sid=${params.sid}`);
147631
+ }
147632
+ }
147633
+
147634
+ // ../mcp-i-cloudflare/dist/delegation-http/consent-anchor-bridge.js
147379
147635
  var DO_INTERNAL_ORIGIN2 = "https://do.internal";
147380
147636
  async function callAnchor2(env2, sid, internalPath, body) {
147381
147637
  const stub = getAnchorStub(env2, sid);
@@ -147445,6 +147701,36 @@ function approveFormPage(sid, info, csrfToken) {
147445
147701
  </form>
147446
147702
  </main>`);
147447
147703
  }
147704
+ function credentialFieldNames(provider) {
147705
+ const names = [];
147706
+ for (const template of Object.values(provider.config.requestBodyTemplate)) {
147707
+ const match2 = /\{\{(\w+)\}\}/.exec(template);
147708
+ if (match2 && !names.includes(match2[1]))
147709
+ names.push(match2[1]);
147710
+ }
147711
+ return names.length > 0 ? names : ["email", "password"];
147712
+ }
147713
+ function credentialFormPage(sid, info, provider, csrfToken) {
147714
+ const scopeItems = info.requiredScopes.length > 0 ? info.requiredScopes.map((s5) => `<li class="kya-scope-item">${escapeHtml2(s5)}</li>`).join("") : `<li class="kya-scope-item">No specific permissions required.</li>`;
147715
+ const fieldInputs = credentialFieldNames(provider).map((name16) => {
147716
+ const isSecret = /pass|secret|token|pin/i.test(name16);
147717
+ const label = name16.charAt(0).toUpperCase() + name16.slice(1);
147718
+ return `<label class="kya-field-label" for="kya-field-${escapeHtml2(name16)}">${escapeHtml2(label)}</label>
147719
+ <input class="kya-field-input" id="kya-field-${escapeHtml2(name16)}" name="${escapeHtml2(name16)}" type="${isSecret ? "password" : "text"}" autocomplete="${isSecret ? "current-password" : "username"}" required>`;
147720
+ }).join("");
147721
+ return page("Permission Request", `<main class="kya-consent">
147722
+ <h1>Sign in to authorize</h1>
147723
+ <p class="kya-provider-name">${escapeHtml2(provider.displayName)}</p>
147724
+ <p class="kya-permissions-header">This request needs the following permissions:</p>
147725
+ <ul class="kya-permissions-list">${scopeItems}</ul>
147726
+ <form method="POST" action="/consent/approve?sid=${encodeURIComponent(sid)}">
147727
+ <input type="hidden" name="sid" value="${escapeHtml2(sid)}">
147728
+ <input type="hidden" name="csrf_token" value="${escapeHtml2(csrfToken)}">
147729
+ ${fieldInputs}
147730
+ <button type="submit" class="kya-consent-allow">Sign in &amp; allow</button>
147731
+ </form>
147732
+ </main>`);
147733
+ }
147448
147734
  function base64UrlEncodeBytes(bytes) {
147449
147735
  return btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
147450
147736
  }
@@ -147549,7 +147835,11 @@ async function mintDelegationVcJwt(env2, sid, info, expiresInS) {
147549
147835
  constraints: {
147550
147836
  scopes: info.requiredScopes,
147551
147837
  notBefore: nowS,
147552
- notAfter: nowS + expiresInS
147838
+ notAfter: nowS + expiresInS,
147839
+ // §11.7 outer===inner audience invariant (checkpoint's own mints bind the
147840
+ // audience in BOTH the JWT aud and constraints.audience): set the inner
147841
+ // half for cross-resource anchors so verifiers reading either slot agree.
147842
+ ...info.audience ? { audience: info.audience } : {}
147553
147843
  },
147554
147844
  signature: "",
147555
147845
  status: "active",
@@ -147564,7 +147854,10 @@ async function mintDelegationVcJwt(env2, sid, info, expiresInS) {
147564
147854
  const signingInput = withCrossResourceClaims(unsigned, info, sid);
147565
147855
  const signatureBytes = await cryptoProvider.sign(new TextEncoder().encode(signingInput), signingPrivateKey);
147566
147856
  const signature = base64urlEncodeFromBytes2(signatureBytes);
147567
- return completeVCJWT2(signingInput, signature);
147857
+ return {
147858
+ vcJwt: completeVCJWT2(signingInput, signature),
147859
+ subjectDid: agentDid
147860
+ };
147568
147861
  }
147569
147862
  async function handleAnchorConsentGet(c, sid, env2, _cfg) {
147570
147863
  const infoResponse = await callAnchor2(env2, sid, INTERNAL_PICKUP_INFO, {
@@ -147579,12 +147872,16 @@ async function handleAnchorConsentGet(c, sid, env2, _cfg) {
147579
147872
  }
147580
147873
  const info = await infoResponse.json();
147581
147874
  const csrfToken = await mintCsrfToken(env2, sid);
147875
+ const resolution = await resolveAnchorCredentialProvider(env2, info.requiredScopes);
147876
+ if (resolution.status === "credential") {
147877
+ return htmlResponse(credentialFormPage(sid, info, resolution.provider, csrfToken), 200);
147878
+ }
147582
147879
  return htmlResponse(approveFormPage(sid, info, csrfToken), 200);
147583
147880
  }
147584
147881
  async function handleAnchorConsentApprove(c, sid, env2, cfg) {
147882
+ const bodyFields = await readBodyFields(c);
147585
147883
  if (!isTestConsentMode(env2)) {
147586
- const csrfToken = await readCsrfTokenFromBody(c);
147587
- const valid = await validateCsrfToken(env2, sid, csrfToken);
147884
+ const valid = await validateCsrfToken(env2, sid, bodyFields.csrf_token);
147588
147885
  if (!valid) {
147589
147886
  return htmlResponse(page("Authorization failed", `<main class="kya-consent-failed"><h1>Authorization failed</h1><p>Invalid or missing security token. Please reload and try again.</p></main>`), 403);
147590
147887
  }
@@ -147601,9 +147898,46 @@ async function handleAnchorConsentApprove(c, sid, env2, cfg) {
147601
147898
  return approvalFailedPage("This authorization request could not be loaded. Please start over.", 502);
147602
147899
  }
147603
147900
  const info = await infoResponse.json();
147901
+ const resolution = await resolveAnchorCredentialProvider(env2, info.requiredScopes);
147902
+ if (resolution.status === "unavailable") {
147903
+ return approvalFailedPage("We could not verify the sign-in requirement for this request. Please try again.", 503);
147904
+ }
147905
+ const provider = resolution.status === "credential" ? resolution.provider : null;
147906
+ let authorizedUser = null;
147907
+ if (provider) {
147908
+ const credentials = {};
147909
+ for (const name16 of credentialFieldNames(provider)) {
147910
+ if (bodyFields[name16] !== void 0)
147911
+ credentials[name16] = bodyFields[name16];
147912
+ }
147913
+ const handler = createCredentialAuthHandler({
147914
+ fetch: (...args) => globalThis.fetch(...args),
147915
+ logger: (msg, data) => console.debug(`[kya-http] ${msg}`, data)
147916
+ });
147917
+ const authResult = await handler.authenticate(provider.config, credentials);
147918
+ if (!authResult.success) {
147919
+ return htmlResponse(page("Sign-in failed", `<main class="kya-consent-failed"><h1>Sign-in failed</h1><p>${escapeHtml2(authResult.error || "Those credentials were not accepted. Please try again.")}</p></main>`), 401);
147920
+ }
147921
+ const identity = await resolveCredentialIdentity(env2, {
147922
+ projectId: env2.AGENTSHIELD_PROJECT_ID || "",
147923
+ provider: provider.providerId,
147924
+ userId: authResult.userId || "unknown",
147925
+ userEmail: authResult.userEmail,
147926
+ userDisplayName: authResult.userDisplayName
147927
+ });
147928
+ if (!identity.success || !identity.userDid) {
147929
+ return approvalFailedPage("We signed you in but could not resolve your identity. Please start over.", 500);
147930
+ }
147931
+ authorizedUser = {
147932
+ userDid: identity.userDid,
147933
+ userId: authResult.userId,
147934
+ userEmail: authResult.userEmail
147935
+ };
147936
+ }
147604
147937
  let vcJwt;
147938
+ let subjectDid;
147605
147939
  try {
147606
- vcJwt = await mintDelegationVcJwt(env2, sid, info, cfg.delegationExpiresInS);
147940
+ ({ vcJwt, subjectDid } = await mintDelegationVcJwt(env2, sid, info, cfg.delegationExpiresInS));
147607
147941
  } catch (error87) {
147608
147942
  console.warn(`[kya-http] delegation mint failed (sid=${sid}):`, error87 instanceof Error ? error87.message : String(error87));
147609
147943
  return approvalFailedPage("We could not complete the authorization. Please start over.", 500);
@@ -147621,24 +147955,46 @@ async function handleAnchorConsentApprove(c, sid, env2, cfg) {
147621
147955
  if (!approveResponse.ok) {
147622
147956
  return approvalFailedPage("We could not complete the authorization. Please start over.", 502);
147623
147957
  }
147958
+ if (authorizedUser && provider) {
147959
+ const report = notifyDelegation(env2, {
147960
+ sid,
147961
+ agentDid: subjectDid,
147962
+ userDid: authorizedUser.userDid,
147963
+ userId: authorizedUser.userId,
147964
+ userIdentifier: authorizedUser.userEmail,
147965
+ scopes: info.requiredScopes,
147966
+ provider: provider.providerId,
147967
+ // Record the same expiry the VC was minted with, matching the OAuth path.
147968
+ expiresAt: new Date(Date.now() + cfg.delegationExpiresInS * 1e3).toISOString()
147969
+ });
147970
+ const execCtx = c.executionCtx;
147971
+ execCtx?.waitUntil?.(report);
147972
+ }
147624
147973
  return successPage();
147625
147974
  }
147626
- async function readCsrfTokenFromBody(c) {
147975
+ async function readBodyFields(c) {
147976
+ const out = {};
147627
147977
  const raw2 = c.req?.raw;
147628
147978
  if (!raw2)
147629
- return void 0;
147979
+ return out;
147630
147980
  try {
147631
147981
  const contentType2 = raw2.headers.get("Content-Type") || "";
147632
147982
  if (contentType2.includes("application/json")) {
147633
- const body = await raw2.clone().json();
147634
- const token2 = body?.csrf_token;
147635
- return typeof token2 === "string" ? token2 : void 0;
147983
+ const body = await raw2.json();
147984
+ for (const [key, value] of Object.entries(body)) {
147985
+ if (typeof value === "string")
147986
+ out[key] = value;
147987
+ }
147988
+ return out;
147636
147989
  }
147637
- const form = await raw2.clone().formData();
147638
- const token = form.get("csrf_token");
147639
- return typeof token === "string" ? token : void 0;
147990
+ const form = await raw2.formData();
147991
+ form.forEach((value, key) => {
147992
+ if (typeof value === "string")
147993
+ out[key] = value;
147994
+ });
147995
+ return out;
147640
147996
  } catch {
147641
- return void 0;
147997
+ return out;
147642
147998
  }
147643
147999
  }
147644
148000