@kya-os/create-mcpi-app 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
 
2
- > @kya-os/create-mcpi-app@1.13.0 build /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app
2
+ > @kya-os/create-mcpi-app@1.14.0 build /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app
3
3
  > tsc && chmod +x dist/index.js && node --import tsx scripts/build-bundles.ts
4
4
 
5
5
  🔨 Building template bundles...
@@ -7,23 +7,23 @@
7
7
 
8
8
  📦 Building template: blank
9
9
  ✅ Source files written to /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app/dist/.tmp-bundles/blank
10
- ✅ Bundle built: 8564273 bytes, hash: sha256:e6abd9412c1e1b82a73b9feab75e49ff4af04f8dc8d912f34cef43a2743627a2
10
+ ✅ Bundle built: 8565369 bytes, hash: sha256:82c9c7ad725657596d170b798edf349e185bba42f6795b48efe253da6a320304
11
11
 
12
12
  📦 Building template: hardware-world
13
13
  ✅ Source files written to /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app/dist/.tmp-bundles/hardware-world
14
- ✅ Bundle built: 8576706 bytes, hash: sha256:b0efa3467d3353697f11bb8a953e1ed8cd4bfa393046afd36bb7d2152e7c32ba
14
+ ✅ Bundle built: 8577802 bytes, hash: sha256:86f8393c5f1c5872656c838b56245200e59ec56e4931b0dbac3387101702599c
15
15
 
16
16
  📦 Building template: ecommerce
17
17
  ✅ Source files written to /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app/dist/.tmp-bundles/ecommerce
18
- ✅ Bundle built: 8565967 bytes, hash: sha256:0d0c64955b1ccc2ffe0de63d0fb5396aacefd41a4f60e0e34eb1c32eaeca18d5
18
+ ✅ Bundle built: 8567063 bytes, hash: sha256:b79f9cb456fe4cea8041d71e873b05b64f8e0184c9fe98408d8237c0762cf465
19
19
 
20
20
  📦 Building template: mix-station
21
21
  ✅ Source files written to /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app/dist/.tmp-bundles/mix-station
22
- ✅ Bundle built: 8579352 bytes, hash: sha256:638947f74b153bc3e5fc316c50a5e5be0892f6a4e512b1cac24edf591311db20
22
+ ✅ Bundle built: 8580448 bytes, hash: sha256:8cc29447b3641c36e3393c4aef6004b3c306803c3eec167562c9f71c90ebf24a
23
23
 
24
24
  ✅ All bundles built successfully!
25
25
  Output: /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app/dist/bundles
26
- Version: 1.13.0
27
- Framework: 1.16.0
26
+ Version: 1.14.0
27
+ Framework: 1.17.0
28
28
  Templates: blank, hardware-world, ecommerce, mix-station
29
29
  Manifest: /home/runner/work/xmcp-i/xmcp-i/packages/create-mcpi-app/dist/bundles/manifest.json
@@ -152582,6 +152582,50 @@ function createRemoteIssuer(binding, apiKey) {
152582
152582
 
152583
152583
  // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152584
152584
  init_crypto3();
152585
+
152586
+ // ../mcp-i-cloudflare/dist/services/resource-audience.js
152587
+ var RESOURCE_REFUSALS = Object.freeze({
152588
+ resources_unconfigured: "KYA_OS_RESOURCE_DIDS is unset, empty or malformed: this worker has no resource DID, so no delegation can name it",
152589
+ no_routed_host: "No routed host for this verification: the expected audience is did:web:<request Host>",
152590
+ host_not_a_resource: "The routed host is not one of this worker's resources (KYA_OS_RESOURCE_DIDS)"
152591
+ });
152592
+ var DID_WEB_PATTERN = /^did:web:[a-z0-9.-]+(?:%3A[0-9]{1,5})?(?::[^\s:#?/]+)*$/;
152593
+ function parseResourceDids(raw2) {
152594
+ if (typeof raw2 !== "string" || !raw2.trim())
152595
+ return null;
152596
+ let parsed;
152597
+ try {
152598
+ parsed = JSON.parse(raw2);
152599
+ } catch {
152600
+ return null;
152601
+ }
152602
+ return Array.isArray(parsed) && parsed.length > 0 && parsed.every((did) => typeof did === "string" && DID_WEB_PATTERN.test(did)) ? parsed : null;
152603
+ }
152604
+ function didWebForHost(host) {
152605
+ const value = host.trim().toLowerCase();
152606
+ if (!/^[a-z0-9.-]+(?::[0-9]{1,5})?$/.test(value))
152607
+ return void 0;
152608
+ return "did:web:" + value.replace(":", "%3A");
152609
+ }
152610
+ function routedResource(resourceDids, routedHost) {
152611
+ const resources = parseResourceDids(resourceDids);
152612
+ if (!resources)
152613
+ return { refusal: "resources_unconfigured" };
152614
+ const routed = routedHost === void 0 ? void 0 : didWebForHost(routedHost);
152615
+ if (!routed)
152616
+ return { refusal: "no_routed_host" };
152617
+ if (!resources.includes(routed))
152618
+ return { refusal: "host_not_a_resource" };
152619
+ return { resourceDid: routed };
152620
+ }
152621
+ function audienceNamesResource(aud, resourceDid) {
152622
+ if (aud === void 0)
152623
+ return "missing";
152624
+ const value = Array.isArray(aud) && aud.length === 1 ? aud[0] : aud;
152625
+ return resourceDid !== void 0 && value === resourceDid ? "accepted" : "unmatched";
152626
+ }
152627
+
152628
+ // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152585
152629
  var DID_PATTERN = /^did:[a-z0-9]+:[^\s#?]+$/;
152586
152630
  var UPSTREAM_TIMEOUT_MS = 3e3;
152587
152631
  var DID_DOCUMENT_TTL_MS = 5 * 6e4;
@@ -152599,35 +152643,24 @@ function checkpointOriginFor(url3) {
152599
152643
  }
152600
152644
  function resolveDelegationTrust(env2, options = {}) {
152601
152645
  const issuers = /* @__PURE__ */ new Set();
152602
- const audiences = /* @__PURE__ */ new Set();
152646
+ const { resourceDid, refusal: resourceRefusal } = routedResource(env2.KYA_OS_RESOURCE_DIDS, options.routedHost);
152603
152647
  const ownDid = typeof env2.MCP_IDENTITY_AGENT_DID === "string" && DID_PATTERN.test(env2.MCP_IDENTITY_AGENT_DID) ? env2.MCP_IDENTITY_AGENT_DID : void 0;
152604
- if (ownDid) {
152648
+ if (ownDid)
152605
152649
  issuers.add(ownDid);
152606
- audiences.add(ownDid);
152607
- }
152608
152650
  const binding = parseNativeIssuerBinding(env2.MCPI_NATIVE_HTTP_ISSUER_CONFIG);
152609
- if (binding) {
152651
+ if (binding)
152610
152652
  issuers.add(binding.issuerDid);
152611
- audiences.add(binding.issuerDid);
152612
- audiences.add(binding.projectId);
152613
- }
152614
152653
  for (const did of [
152615
152654
  ...listFrom(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
152616
152655
  ...options.trustedIssuers ?? []
152617
152656
  ])
152618
152657
  if (did && DID_PATTERN.test(did))
152619
152658
  issuers.add(did);
152620
- for (const aud of [
152621
- ...listFrom(env2.CHECKPOINT_PROJECT_ID),
152622
- ...listFrom(env2.KYA_OS_DELEGATION_AUDIENCES),
152623
- ...options.audiences ?? []
152624
- ])
152625
- if (aud)
152626
- audiences.add(aud);
152627
152659
  const checkpointUrl = env2.CHECKPOINT_API_URL || DEFAULT_CHECKPOINT_URL;
152628
152660
  return {
152629
152661
  issuers,
152630
- audiences,
152662
+ resourceDid,
152663
+ resourceRefusal,
152631
152664
  ownDid,
152632
152665
  checkpointOrigin: typeof checkpointUrl === "string" ? checkpointOriginFor(checkpointUrl) : void 0
152633
152666
  };
@@ -152641,10 +152674,7 @@ function credentialHandle(payload) {
152641
152674
  return typeof jti === "string" && jti.length > 0 ? jti : void 0;
152642
152675
  }
152643
152676
  function audienceVerdict(aud, trust) {
152644
- if (aud === void 0)
152645
- return "missing";
152646
- const values = Array.isArray(aud) ? aud : [aud];
152647
- return values.some((v) => typeof v === "string" && trust.audiences.has(v)) ? "accepted" : "unmatched";
152677
+ return audienceNamesResource(aud, trust.resourceDid);
152648
152678
  }
152649
152679
  async function readBounded(stream, maxBytes) {
152650
152680
  if (!stream)
@@ -152982,16 +153012,14 @@ var DelegationService = class {
152982
153012
  /**
152983
153013
  * Whether a cached development verdict still holds under THIS deployment's
152984
153014
  * trust: the token's issuer is the one the verdict was granted to, it is
152985
- * still pinned, and the token's `aud` is still accepted (a KV namespace may
152986
- * be shared by deployments with different audiences). Development only, so
152987
- * no audience is deferred to Checkpoint here.
153015
+ * still pinned, and the token's `aud` is still this worker's resource DID
153016
+ * (a KV namespace may be shared by deployments with different resources).
152988
153017
  */
152989
153018
  async servesCachedVerdict(token, grantedIssuer) {
152990
153019
  const payload = parseVCJWT2(token)?.payload;
152991
153020
  if (!payload || payload.iss !== grantedIssuer)
152992
153021
  return false;
152993
- const audience = audienceVerdict(payload.aud, this.trust);
152994
- if (audience !== "accepted" && !(audience === "missing" && grantedIssuer === this.trust.ownDid))
153022
+ if (audienceVerdict(payload.aud, this.trust) !== "accepted")
152995
153023
  return false;
152996
153024
  return this.isPinnedIssuer(grantedIssuer);
152997
153025
  }
@@ -153005,15 +153033,13 @@ var DelegationService = class {
153005
153033
  * only fetch an unpinned issuer can cause is the configured Checkpoint's own
153006
153034
  * DID document (cached).
153007
153035
  *
153008
- * Audience: `aud` must name this worker (see ./delegation-trust). Only a
153009
- * self-issued credential (issuer = this worker's own DID) may omit it: the
153010
- * anchor flow mints self-issued delegations without `aud`, while the
153011
- * Checkpoint platform mint, the hosted-consent org mint and the native
153012
- * issuer always set it. One exception: with a Checkpoint API key, a
153013
- * platform-signed credential may carry an `aud` this worker cannot name
153014
- * (its project UUID, while CHECKPOINT_PROJECT_ID is often the friendly id).
153015
- * Checkpoint's confirm pins that `aud` to the API key's project, so the
153016
- * check is left to it.
153036
+ * Audience: `aud` must be `did:web:<the host this request was routed for>`,
153037
+ * and that DID must be in `KYA_OS_RESOURCE_DIDS` (see ./delegation-trust),
153038
+ * whoever the issuer and whether or not a Checkpoint API key is set. A
153039
+ * credential without `aud`, or naming anything else (another of this
153040
+ * worker's hosts, the org DID, the worker's own DID, a project id), is
153041
+ * refused. Without a valid resource list, or without a routed host (a
153042
+ * verification with no request behind it), every credential is refused.
153017
153043
  *
153018
153044
  * Issuer: only pinned issuers are resolved and verified. An untrusted or
153019
153045
  * unresolvable issuer fails closed.
@@ -153033,15 +153059,14 @@ var DelegationService = class {
153033
153059
  const issuerDid2 = parsed.payload.iss;
153034
153060
  if (!issuerDid2 || typeof issuerDid2 !== "string")
153035
153061
  return reject("Missing issuer (iss)");
153062
+ if (!this.trust.resourceDid)
153063
+ return reject(RESOURCE_REFUSALS[this.trust.resourceRefusal]);
153036
153064
  const audience = audienceVerdict(parsed.payload.aud, this.trust);
153037
- if (audience === "missing" && issuerDid2 !== this.trust.ownDid)
153065
+ if (audience === "missing")
153038
153066
  return reject("Missing audience (aud)");
153039
- if (audience === "unmatched" && !this.env.CHECKPOINT_API_KEY)
153067
+ if (audience !== "accepted")
153040
153068
  return reject("Audience not accepted");
153041
- if (this.trust.issuers.has(issuerDid2)) {
153042
- if (audience === "unmatched")
153043
- return reject("Audience not accepted");
153044
- } else if (!await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153069
+ if (!this.trust.issuers.has(issuerDid2) && !await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153045
153070
  return reject(`Untrusted issuer: ${logSafe(issuerDid2)}`);
153046
153071
  }
153047
153072
  const kid = parsed.header.kid;
@@ -166382,7 +166407,7 @@ function mapPrefixedEnv(source, prefix) {
166382
166407
  // Delegation trust policy (DelegationService); set unprefixed like the
166383
166408
  // native issuer binding above.
166384
166409
  KYA_OS_TRUSTED_DELEGATION_ISSUERS: stringValue(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
166385
- KYA_OS_DELEGATION_AUDIENCES: stringValue(env2.KYA_OS_DELEGATION_AUDIENCES),
166410
+ KYA_OS_RESOURCE_DIDS: stringValue(env2.KYA_OS_RESOURCE_DIDS),
166386
166411
  KYA_OS_INSECURE_DEV_TOKENS: stringValue(env2.KYA_OS_INSECURE_DEV_TOKENS),
166387
166412
  CHECKPOINT_API_URL: typeof env2.CHECKPOINT_API_URL === "string" ? env2.CHECKPOINT_API_URL : void 0,
166388
166413
  CHECKPOINT_API_KEY: typeof env2.CHECKPOINT_API_KEY === "string" ? env2.CHECKPOINT_API_KEY : void 0,
@@ -166725,7 +166750,7 @@ init_native_oauth_state_do();
166725
166750
  // ../mcp-i-cloudflare/package.json
166726
166751
  var package_default = {
166727
166752
  name: "@kya-os/mcp-i-cloudflare",
166728
- version: "1.16.0",
166753
+ version: "1.17.0",
166729
166754
  description: "Cloudflare Workers adapter for MCP-I framework",
166730
166755
  main: "dist/index.js",
166731
166756
  types: "dist/index.d.ts",
@@ -174214,7 +174239,7 @@ async function applyBearerDelegation(request, env2, cfg, getProofSupport = getCa
174214
174239
  const native = cfg.native ?? void 0;
174215
174240
  const isValid2 = await new DelegationService(env2, void 0, {
174216
174241
  trustedIssuers: [native?.issuerDid],
174217
- audiences: [native?.issuerDid, native?.projectId]
174242
+ routedHost: new URL(request.url).host
174218
174243
  }).verifyDelegation(vcJwt);
174219
174244
  if (!isValid2) {
174220
174245
  if (isVcJwtExpired(vcJwt)) {
@@ -152582,6 +152582,50 @@ function createRemoteIssuer(binding, apiKey) {
152582
152582
 
152583
152583
  // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152584
152584
  init_crypto3();
152585
+
152586
+ // ../mcp-i-cloudflare/dist/services/resource-audience.js
152587
+ var RESOURCE_REFUSALS = Object.freeze({
152588
+ resources_unconfigured: "KYA_OS_RESOURCE_DIDS is unset, empty or malformed: this worker has no resource DID, so no delegation can name it",
152589
+ no_routed_host: "No routed host for this verification: the expected audience is did:web:<request Host>",
152590
+ host_not_a_resource: "The routed host is not one of this worker's resources (KYA_OS_RESOURCE_DIDS)"
152591
+ });
152592
+ var DID_WEB_PATTERN = /^did:web:[a-z0-9.-]+(?:%3A[0-9]{1,5})?(?::[^\s:#?/]+)*$/;
152593
+ function parseResourceDids(raw2) {
152594
+ if (typeof raw2 !== "string" || !raw2.trim())
152595
+ return null;
152596
+ let parsed;
152597
+ try {
152598
+ parsed = JSON.parse(raw2);
152599
+ } catch {
152600
+ return null;
152601
+ }
152602
+ return Array.isArray(parsed) && parsed.length > 0 && parsed.every((did) => typeof did === "string" && DID_WEB_PATTERN.test(did)) ? parsed : null;
152603
+ }
152604
+ function didWebForHost(host) {
152605
+ const value = host.trim().toLowerCase();
152606
+ if (!/^[a-z0-9.-]+(?::[0-9]{1,5})?$/.test(value))
152607
+ return void 0;
152608
+ return "did:web:" + value.replace(":", "%3A");
152609
+ }
152610
+ function routedResource(resourceDids, routedHost) {
152611
+ const resources = parseResourceDids(resourceDids);
152612
+ if (!resources)
152613
+ return { refusal: "resources_unconfigured" };
152614
+ const routed = routedHost === void 0 ? void 0 : didWebForHost(routedHost);
152615
+ if (!routed)
152616
+ return { refusal: "no_routed_host" };
152617
+ if (!resources.includes(routed))
152618
+ return { refusal: "host_not_a_resource" };
152619
+ return { resourceDid: routed };
152620
+ }
152621
+ function audienceNamesResource(aud, resourceDid) {
152622
+ if (aud === void 0)
152623
+ return "missing";
152624
+ const value = Array.isArray(aud) && aud.length === 1 ? aud[0] : aud;
152625
+ return resourceDid !== void 0 && value === resourceDid ? "accepted" : "unmatched";
152626
+ }
152627
+
152628
+ // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152585
152629
  var DID_PATTERN = /^did:[a-z0-9]+:[^\s#?]+$/;
152586
152630
  var UPSTREAM_TIMEOUT_MS = 3e3;
152587
152631
  var DID_DOCUMENT_TTL_MS = 5 * 6e4;
@@ -152599,35 +152643,24 @@ function checkpointOriginFor(url3) {
152599
152643
  }
152600
152644
  function resolveDelegationTrust(env2, options = {}) {
152601
152645
  const issuers = /* @__PURE__ */ new Set();
152602
- const audiences = /* @__PURE__ */ new Set();
152646
+ const { resourceDid, refusal: resourceRefusal } = routedResource(env2.KYA_OS_RESOURCE_DIDS, options.routedHost);
152603
152647
  const ownDid = typeof env2.MCP_IDENTITY_AGENT_DID === "string" && DID_PATTERN.test(env2.MCP_IDENTITY_AGENT_DID) ? env2.MCP_IDENTITY_AGENT_DID : void 0;
152604
- if (ownDid) {
152648
+ if (ownDid)
152605
152649
  issuers.add(ownDid);
152606
- audiences.add(ownDid);
152607
- }
152608
152650
  const binding = parseNativeIssuerBinding(env2.MCPI_NATIVE_HTTP_ISSUER_CONFIG);
152609
- if (binding) {
152651
+ if (binding)
152610
152652
  issuers.add(binding.issuerDid);
152611
- audiences.add(binding.issuerDid);
152612
- audiences.add(binding.projectId);
152613
- }
152614
152653
  for (const did of [
152615
152654
  ...listFrom(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
152616
152655
  ...options.trustedIssuers ?? []
152617
152656
  ])
152618
152657
  if (did && DID_PATTERN.test(did))
152619
152658
  issuers.add(did);
152620
- for (const aud of [
152621
- ...listFrom(env2.CHECKPOINT_PROJECT_ID),
152622
- ...listFrom(env2.KYA_OS_DELEGATION_AUDIENCES),
152623
- ...options.audiences ?? []
152624
- ])
152625
- if (aud)
152626
- audiences.add(aud);
152627
152659
  const checkpointUrl = env2.CHECKPOINT_API_URL || DEFAULT_CHECKPOINT_URL;
152628
152660
  return {
152629
152661
  issuers,
152630
- audiences,
152662
+ resourceDid,
152663
+ resourceRefusal,
152631
152664
  ownDid,
152632
152665
  checkpointOrigin: typeof checkpointUrl === "string" ? checkpointOriginFor(checkpointUrl) : void 0
152633
152666
  };
@@ -152641,10 +152674,7 @@ function credentialHandle(payload) {
152641
152674
  return typeof jti === "string" && jti.length > 0 ? jti : void 0;
152642
152675
  }
152643
152676
  function audienceVerdict(aud, trust) {
152644
- if (aud === void 0)
152645
- return "missing";
152646
- const values = Array.isArray(aud) ? aud : [aud];
152647
- return values.some((v) => typeof v === "string" && trust.audiences.has(v)) ? "accepted" : "unmatched";
152677
+ return audienceNamesResource(aud, trust.resourceDid);
152648
152678
  }
152649
152679
  async function readBounded(stream, maxBytes) {
152650
152680
  if (!stream)
@@ -152982,16 +153012,14 @@ var DelegationService = class {
152982
153012
  /**
152983
153013
  * Whether a cached development verdict still holds under THIS deployment's
152984
153014
  * trust: the token's issuer is the one the verdict was granted to, it is
152985
- * still pinned, and the token's `aud` is still accepted (a KV namespace may
152986
- * be shared by deployments with different audiences). Development only, so
152987
- * no audience is deferred to Checkpoint here.
153015
+ * still pinned, and the token's `aud` is still this worker's resource DID
153016
+ * (a KV namespace may be shared by deployments with different resources).
152988
153017
  */
152989
153018
  async servesCachedVerdict(token, grantedIssuer) {
152990
153019
  const payload = parseVCJWT2(token)?.payload;
152991
153020
  if (!payload || payload.iss !== grantedIssuer)
152992
153021
  return false;
152993
- const audience = audienceVerdict(payload.aud, this.trust);
152994
- if (audience !== "accepted" && !(audience === "missing" && grantedIssuer === this.trust.ownDid))
153022
+ if (audienceVerdict(payload.aud, this.trust) !== "accepted")
152995
153023
  return false;
152996
153024
  return this.isPinnedIssuer(grantedIssuer);
152997
153025
  }
@@ -153005,15 +153033,13 @@ var DelegationService = class {
153005
153033
  * only fetch an unpinned issuer can cause is the configured Checkpoint's own
153006
153034
  * DID document (cached).
153007
153035
  *
153008
- * Audience: `aud` must name this worker (see ./delegation-trust). Only a
153009
- * self-issued credential (issuer = this worker's own DID) may omit it: the
153010
- * anchor flow mints self-issued delegations without `aud`, while the
153011
- * Checkpoint platform mint, the hosted-consent org mint and the native
153012
- * issuer always set it. One exception: with a Checkpoint API key, a
153013
- * platform-signed credential may carry an `aud` this worker cannot name
153014
- * (its project UUID, while CHECKPOINT_PROJECT_ID is often the friendly id).
153015
- * Checkpoint's confirm pins that `aud` to the API key's project, so the
153016
- * check is left to it.
153036
+ * Audience: `aud` must be `did:web:<the host this request was routed for>`,
153037
+ * and that DID must be in `KYA_OS_RESOURCE_DIDS` (see ./delegation-trust),
153038
+ * whoever the issuer and whether or not a Checkpoint API key is set. A
153039
+ * credential without `aud`, or naming anything else (another of this
153040
+ * worker's hosts, the org DID, the worker's own DID, a project id), is
153041
+ * refused. Without a valid resource list, or without a routed host (a
153042
+ * verification with no request behind it), every credential is refused.
153017
153043
  *
153018
153044
  * Issuer: only pinned issuers are resolved and verified. An untrusted or
153019
153045
  * unresolvable issuer fails closed.
@@ -153033,15 +153059,14 @@ var DelegationService = class {
153033
153059
  const issuerDid2 = parsed.payload.iss;
153034
153060
  if (!issuerDid2 || typeof issuerDid2 !== "string")
153035
153061
  return reject("Missing issuer (iss)");
153062
+ if (!this.trust.resourceDid)
153063
+ return reject(RESOURCE_REFUSALS[this.trust.resourceRefusal]);
153036
153064
  const audience = audienceVerdict(parsed.payload.aud, this.trust);
153037
- if (audience === "missing" && issuerDid2 !== this.trust.ownDid)
153065
+ if (audience === "missing")
153038
153066
  return reject("Missing audience (aud)");
153039
- if (audience === "unmatched" && !this.env.CHECKPOINT_API_KEY)
153067
+ if (audience !== "accepted")
153040
153068
  return reject("Audience not accepted");
153041
- if (this.trust.issuers.has(issuerDid2)) {
153042
- if (audience === "unmatched")
153043
- return reject("Audience not accepted");
153044
- } else if (!await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153069
+ if (!this.trust.issuers.has(issuerDid2) && !await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153045
153070
  return reject(`Untrusted issuer: ${logSafe(issuerDid2)}`);
153046
153071
  }
153047
153072
  const kid = parsed.header.kid;
@@ -166382,7 +166407,7 @@ function mapPrefixedEnv(source, prefix) {
166382
166407
  // Delegation trust policy (DelegationService); set unprefixed like the
166383
166408
  // native issuer binding above.
166384
166409
  KYA_OS_TRUSTED_DELEGATION_ISSUERS: stringValue(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
166385
- KYA_OS_DELEGATION_AUDIENCES: stringValue(env2.KYA_OS_DELEGATION_AUDIENCES),
166410
+ KYA_OS_RESOURCE_DIDS: stringValue(env2.KYA_OS_RESOURCE_DIDS),
166386
166411
  KYA_OS_INSECURE_DEV_TOKENS: stringValue(env2.KYA_OS_INSECURE_DEV_TOKENS),
166387
166412
  CHECKPOINT_API_URL: typeof env2.CHECKPOINT_API_URL === "string" ? env2.CHECKPOINT_API_URL : void 0,
166388
166413
  CHECKPOINT_API_KEY: typeof env2.CHECKPOINT_API_KEY === "string" ? env2.CHECKPOINT_API_KEY : void 0,
@@ -166725,7 +166750,7 @@ init_native_oauth_state_do();
166725
166750
  // ../mcp-i-cloudflare/package.json
166726
166751
  var package_default = {
166727
166752
  name: "@kya-os/mcp-i-cloudflare",
166728
- version: "1.16.0",
166753
+ version: "1.17.0",
166729
166754
  description: "Cloudflare Workers adapter for MCP-I framework",
166730
166755
  main: "dist/index.js",
166731
166756
  types: "dist/index.d.ts",
@@ -174214,7 +174239,7 @@ async function applyBearerDelegation(request, env2, cfg, getProofSupport = getCa
174214
174239
  const native = cfg.native ?? void 0;
174215
174240
  const isValid2 = await new DelegationService(env2, void 0, {
174216
174241
  trustedIssuers: [native?.issuerDid],
174217
- audiences: [native?.issuerDid, native?.projectId]
174242
+ routedHost: new URL(request.url).host
174218
174243
  }).verifyDelegation(vcJwt);
174219
174244
  if (!isValid2) {
174220
174245
  if (isVcJwtExpired(vcJwt)) {
@@ -152582,6 +152582,50 @@ function createRemoteIssuer(binding, apiKey) {
152582
152582
 
152583
152583
  // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152584
152584
  init_crypto3();
152585
+
152586
+ // ../mcp-i-cloudflare/dist/services/resource-audience.js
152587
+ var RESOURCE_REFUSALS = Object.freeze({
152588
+ resources_unconfigured: "KYA_OS_RESOURCE_DIDS is unset, empty or malformed: this worker has no resource DID, so no delegation can name it",
152589
+ no_routed_host: "No routed host for this verification: the expected audience is did:web:<request Host>",
152590
+ host_not_a_resource: "The routed host is not one of this worker's resources (KYA_OS_RESOURCE_DIDS)"
152591
+ });
152592
+ var DID_WEB_PATTERN = /^did:web:[a-z0-9.-]+(?:%3A[0-9]{1,5})?(?::[^\s:#?/]+)*$/;
152593
+ function parseResourceDids(raw2) {
152594
+ if (typeof raw2 !== "string" || !raw2.trim())
152595
+ return null;
152596
+ let parsed;
152597
+ try {
152598
+ parsed = JSON.parse(raw2);
152599
+ } catch {
152600
+ return null;
152601
+ }
152602
+ return Array.isArray(parsed) && parsed.length > 0 && parsed.every((did) => typeof did === "string" && DID_WEB_PATTERN.test(did)) ? parsed : null;
152603
+ }
152604
+ function didWebForHost(host) {
152605
+ const value = host.trim().toLowerCase();
152606
+ if (!/^[a-z0-9.-]+(?::[0-9]{1,5})?$/.test(value))
152607
+ return void 0;
152608
+ return "did:web:" + value.replace(":", "%3A");
152609
+ }
152610
+ function routedResource(resourceDids, routedHost) {
152611
+ const resources = parseResourceDids(resourceDids);
152612
+ if (!resources)
152613
+ return { refusal: "resources_unconfigured" };
152614
+ const routed = routedHost === void 0 ? void 0 : didWebForHost(routedHost);
152615
+ if (!routed)
152616
+ return { refusal: "no_routed_host" };
152617
+ if (!resources.includes(routed))
152618
+ return { refusal: "host_not_a_resource" };
152619
+ return { resourceDid: routed };
152620
+ }
152621
+ function audienceNamesResource(aud, resourceDid) {
152622
+ if (aud === void 0)
152623
+ return "missing";
152624
+ const value = Array.isArray(aud) && aud.length === 1 ? aud[0] : aud;
152625
+ return resourceDid !== void 0 && value === resourceDid ? "accepted" : "unmatched";
152626
+ }
152627
+
152628
+ // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152585
152629
  var DID_PATTERN = /^did:[a-z0-9]+:[^\s#?]+$/;
152586
152630
  var UPSTREAM_TIMEOUT_MS = 3e3;
152587
152631
  var DID_DOCUMENT_TTL_MS = 5 * 6e4;
@@ -152599,35 +152643,24 @@ function checkpointOriginFor(url3) {
152599
152643
  }
152600
152644
  function resolveDelegationTrust(env2, options = {}) {
152601
152645
  const issuers = /* @__PURE__ */ new Set();
152602
- const audiences = /* @__PURE__ */ new Set();
152646
+ const { resourceDid, refusal: resourceRefusal } = routedResource(env2.KYA_OS_RESOURCE_DIDS, options.routedHost);
152603
152647
  const ownDid = typeof env2.MCP_IDENTITY_AGENT_DID === "string" && DID_PATTERN.test(env2.MCP_IDENTITY_AGENT_DID) ? env2.MCP_IDENTITY_AGENT_DID : void 0;
152604
- if (ownDid) {
152648
+ if (ownDid)
152605
152649
  issuers.add(ownDid);
152606
- audiences.add(ownDid);
152607
- }
152608
152650
  const binding = parseNativeIssuerBinding(env2.MCPI_NATIVE_HTTP_ISSUER_CONFIG);
152609
- if (binding) {
152651
+ if (binding)
152610
152652
  issuers.add(binding.issuerDid);
152611
- audiences.add(binding.issuerDid);
152612
- audiences.add(binding.projectId);
152613
- }
152614
152653
  for (const did of [
152615
152654
  ...listFrom(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
152616
152655
  ...options.trustedIssuers ?? []
152617
152656
  ])
152618
152657
  if (did && DID_PATTERN.test(did))
152619
152658
  issuers.add(did);
152620
- for (const aud of [
152621
- ...listFrom(env2.CHECKPOINT_PROJECT_ID),
152622
- ...listFrom(env2.KYA_OS_DELEGATION_AUDIENCES),
152623
- ...options.audiences ?? []
152624
- ])
152625
- if (aud)
152626
- audiences.add(aud);
152627
152659
  const checkpointUrl = env2.CHECKPOINT_API_URL || DEFAULT_CHECKPOINT_URL;
152628
152660
  return {
152629
152661
  issuers,
152630
- audiences,
152662
+ resourceDid,
152663
+ resourceRefusal,
152631
152664
  ownDid,
152632
152665
  checkpointOrigin: typeof checkpointUrl === "string" ? checkpointOriginFor(checkpointUrl) : void 0
152633
152666
  };
@@ -152641,10 +152674,7 @@ function credentialHandle(payload) {
152641
152674
  return typeof jti === "string" && jti.length > 0 ? jti : void 0;
152642
152675
  }
152643
152676
  function audienceVerdict(aud, trust) {
152644
- if (aud === void 0)
152645
- return "missing";
152646
- const values = Array.isArray(aud) ? aud : [aud];
152647
- return values.some((v) => typeof v === "string" && trust.audiences.has(v)) ? "accepted" : "unmatched";
152677
+ return audienceNamesResource(aud, trust.resourceDid);
152648
152678
  }
152649
152679
  async function readBounded(stream, maxBytes) {
152650
152680
  if (!stream)
@@ -152982,16 +153012,14 @@ var DelegationService = class {
152982
153012
  /**
152983
153013
  * Whether a cached development verdict still holds under THIS deployment's
152984
153014
  * trust: the token's issuer is the one the verdict was granted to, it is
152985
- * still pinned, and the token's `aud` is still accepted (a KV namespace may
152986
- * be shared by deployments with different audiences). Development only, so
152987
- * no audience is deferred to Checkpoint here.
153015
+ * still pinned, and the token's `aud` is still this worker's resource DID
153016
+ * (a KV namespace may be shared by deployments with different resources).
152988
153017
  */
152989
153018
  async servesCachedVerdict(token, grantedIssuer) {
152990
153019
  const payload = parseVCJWT2(token)?.payload;
152991
153020
  if (!payload || payload.iss !== grantedIssuer)
152992
153021
  return false;
152993
- const audience = audienceVerdict(payload.aud, this.trust);
152994
- if (audience !== "accepted" && !(audience === "missing" && grantedIssuer === this.trust.ownDid))
153022
+ if (audienceVerdict(payload.aud, this.trust) !== "accepted")
152995
153023
  return false;
152996
153024
  return this.isPinnedIssuer(grantedIssuer);
152997
153025
  }
@@ -153005,15 +153033,13 @@ var DelegationService = class {
153005
153033
  * only fetch an unpinned issuer can cause is the configured Checkpoint's own
153006
153034
  * DID document (cached).
153007
153035
  *
153008
- * Audience: `aud` must name this worker (see ./delegation-trust). Only a
153009
- * self-issued credential (issuer = this worker's own DID) may omit it: the
153010
- * anchor flow mints self-issued delegations without `aud`, while the
153011
- * Checkpoint platform mint, the hosted-consent org mint and the native
153012
- * issuer always set it. One exception: with a Checkpoint API key, a
153013
- * platform-signed credential may carry an `aud` this worker cannot name
153014
- * (its project UUID, while CHECKPOINT_PROJECT_ID is often the friendly id).
153015
- * Checkpoint's confirm pins that `aud` to the API key's project, so the
153016
- * check is left to it.
153036
+ * Audience: `aud` must be `did:web:<the host this request was routed for>`,
153037
+ * and that DID must be in `KYA_OS_RESOURCE_DIDS` (see ./delegation-trust),
153038
+ * whoever the issuer and whether or not a Checkpoint API key is set. A
153039
+ * credential without `aud`, or naming anything else (another of this
153040
+ * worker's hosts, the org DID, the worker's own DID, a project id), is
153041
+ * refused. Without a valid resource list, or without a routed host (a
153042
+ * verification with no request behind it), every credential is refused.
153017
153043
  *
153018
153044
  * Issuer: only pinned issuers are resolved and verified. An untrusted or
153019
153045
  * unresolvable issuer fails closed.
@@ -153033,15 +153059,14 @@ var DelegationService = class {
153033
153059
  const issuerDid2 = parsed.payload.iss;
153034
153060
  if (!issuerDid2 || typeof issuerDid2 !== "string")
153035
153061
  return reject("Missing issuer (iss)");
153062
+ if (!this.trust.resourceDid)
153063
+ return reject(RESOURCE_REFUSALS[this.trust.resourceRefusal]);
153036
153064
  const audience = audienceVerdict(parsed.payload.aud, this.trust);
153037
- if (audience === "missing" && issuerDid2 !== this.trust.ownDid)
153065
+ if (audience === "missing")
153038
153066
  return reject("Missing audience (aud)");
153039
- if (audience === "unmatched" && !this.env.CHECKPOINT_API_KEY)
153067
+ if (audience !== "accepted")
153040
153068
  return reject("Audience not accepted");
153041
- if (this.trust.issuers.has(issuerDid2)) {
153042
- if (audience === "unmatched")
153043
- return reject("Audience not accepted");
153044
- } else if (!await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153069
+ if (!this.trust.issuers.has(issuerDid2) && !await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153045
153070
  return reject(`Untrusted issuer: ${logSafe(issuerDid2)}`);
153046
153071
  }
153047
153072
  const kid = parsed.header.kid;
@@ -166382,7 +166407,7 @@ function mapPrefixedEnv(source, prefix) {
166382
166407
  // Delegation trust policy (DelegationService); set unprefixed like the
166383
166408
  // native issuer binding above.
166384
166409
  KYA_OS_TRUSTED_DELEGATION_ISSUERS: stringValue(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
166385
- KYA_OS_DELEGATION_AUDIENCES: stringValue(env2.KYA_OS_DELEGATION_AUDIENCES),
166410
+ KYA_OS_RESOURCE_DIDS: stringValue(env2.KYA_OS_RESOURCE_DIDS),
166386
166411
  KYA_OS_INSECURE_DEV_TOKENS: stringValue(env2.KYA_OS_INSECURE_DEV_TOKENS),
166387
166412
  CHECKPOINT_API_URL: typeof env2.CHECKPOINT_API_URL === "string" ? env2.CHECKPOINT_API_URL : void 0,
166388
166413
  CHECKPOINT_API_KEY: typeof env2.CHECKPOINT_API_KEY === "string" ? env2.CHECKPOINT_API_KEY : void 0,
@@ -166725,7 +166750,7 @@ init_native_oauth_state_do();
166725
166750
  // ../mcp-i-cloudflare/package.json
166726
166751
  var package_default = {
166727
166752
  name: "@kya-os/mcp-i-cloudflare",
166728
- version: "1.16.0",
166753
+ version: "1.17.0",
166729
166754
  description: "Cloudflare Workers adapter for MCP-I framework",
166730
166755
  main: "dist/index.js",
166731
166756
  types: "dist/index.d.ts",
@@ -174214,7 +174239,7 @@ async function applyBearerDelegation(request, env2, cfg, getProofSupport = getCa
174214
174239
  const native = cfg.native ?? void 0;
174215
174240
  const isValid2 = await new DelegationService(env2, void 0, {
174216
174241
  trustedIssuers: [native?.issuerDid],
174217
- audiences: [native?.issuerDid, native?.projectId]
174242
+ routedHost: new URL(request.url).host
174218
174243
  }).verifyDelegation(vcJwt);
174219
174244
  if (!isValid2) {
174220
174245
  if (isVcJwtExpired(vcJwt)) {
@@ -1,30 +1,30 @@
1
1
  {
2
- "version": "1.13.0",
3
- "frameworkVersion": "1.16.0",
2
+ "version": "1.14.0",
3
+ "frameworkVersion": "1.17.0",
4
4
  "doClassName": "MCPIAgent",
5
5
  "auditDoClassName": "AuditProducer",
6
6
  "nativeOAuthStateDoClassName": "NativeOAuthState",
7
- "buildDate": "2026-10-12T23:20:11.343Z",
7
+ "buildDate": "2026-10-13T00:48:58.917Z",
8
8
  "templates": {
9
9
  "blank": {
10
- "file": "blank.e6abd9412c1e1b82a73b9feab75e49ff4af04f8dc8d912f34cef43a2743627a2.js",
11
- "size": 8564273,
12
- "hash": "sha256:e6abd9412c1e1b82a73b9feab75e49ff4af04f8dc8d912f34cef43a2743627a2"
10
+ "file": "blank.82c9c7ad725657596d170b798edf349e185bba42f6795b48efe253da6a320304.js",
11
+ "size": 8565369,
12
+ "hash": "sha256:82c9c7ad725657596d170b798edf349e185bba42f6795b48efe253da6a320304"
13
13
  },
14
14
  "hardware-world": {
15
- "file": "hardware-world.b0efa3467d3353697f11bb8a953e1ed8cd4bfa393046afd36bb7d2152e7c32ba.js",
16
- "size": 8576706,
17
- "hash": "sha256:b0efa3467d3353697f11bb8a953e1ed8cd4bfa393046afd36bb7d2152e7c32ba"
15
+ "file": "hardware-world.86f8393c5f1c5872656c838b56245200e59ec56e4931b0dbac3387101702599c.js",
16
+ "size": 8577802,
17
+ "hash": "sha256:86f8393c5f1c5872656c838b56245200e59ec56e4931b0dbac3387101702599c"
18
18
  },
19
19
  "ecommerce": {
20
- "file": "ecommerce.0d0c64955b1ccc2ffe0de63d0fb5396aacefd41a4f60e0e34eb1c32eaeca18d5.js",
21
- "size": 8565967,
22
- "hash": "sha256:0d0c64955b1ccc2ffe0de63d0fb5396aacefd41a4f60e0e34eb1c32eaeca18d5"
20
+ "file": "ecommerce.b79f9cb456fe4cea8041d71e873b05b64f8e0184c9fe98408d8237c0762cf465.js",
21
+ "size": 8567063,
22
+ "hash": "sha256:b79f9cb456fe4cea8041d71e873b05b64f8e0184c9fe98408d8237c0762cf465"
23
23
  },
24
24
  "mix-station": {
25
- "file": "mix-station.638947f74b153bc3e5fc316c50a5e5be0892f6a4e512b1cac24edf591311db20.js",
26
- "size": 8579352,
27
- "hash": "sha256:638947f74b153bc3e5fc316c50a5e5be0892f6a4e512b1cac24edf591311db20"
25
+ "file": "mix-station.8cc29447b3641c36e3393c4aef6004b3c306803c3eec167562c9f71c90ebf24a.js",
26
+ "size": 8580448,
27
+ "hash": "sha256:8cc29447b3641c36e3393c4aef6004b3c306803c3eec167562c9f71c90ebf24a"
28
28
  }
29
29
  }
30
30
  }
@@ -152582,6 +152582,50 @@ function createRemoteIssuer(binding, apiKey) {
152582
152582
 
152583
152583
  // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152584
152584
  init_crypto3();
152585
+
152586
+ // ../mcp-i-cloudflare/dist/services/resource-audience.js
152587
+ var RESOURCE_REFUSALS = Object.freeze({
152588
+ resources_unconfigured: "KYA_OS_RESOURCE_DIDS is unset, empty or malformed: this worker has no resource DID, so no delegation can name it",
152589
+ no_routed_host: "No routed host for this verification: the expected audience is did:web:<request Host>",
152590
+ host_not_a_resource: "The routed host is not one of this worker's resources (KYA_OS_RESOURCE_DIDS)"
152591
+ });
152592
+ var DID_WEB_PATTERN = /^did:web:[a-z0-9.-]+(?:%3A[0-9]{1,5})?(?::[^\s:#?/]+)*$/;
152593
+ function parseResourceDids(raw2) {
152594
+ if (typeof raw2 !== "string" || !raw2.trim())
152595
+ return null;
152596
+ let parsed;
152597
+ try {
152598
+ parsed = JSON.parse(raw2);
152599
+ } catch {
152600
+ return null;
152601
+ }
152602
+ return Array.isArray(parsed) && parsed.length > 0 && parsed.every((did) => typeof did === "string" && DID_WEB_PATTERN.test(did)) ? parsed : null;
152603
+ }
152604
+ function didWebForHost(host) {
152605
+ const value = host.trim().toLowerCase();
152606
+ if (!/^[a-z0-9.-]+(?::[0-9]{1,5})?$/.test(value))
152607
+ return void 0;
152608
+ return "did:web:" + value.replace(":", "%3A");
152609
+ }
152610
+ function routedResource(resourceDids, routedHost) {
152611
+ const resources = parseResourceDids(resourceDids);
152612
+ if (!resources)
152613
+ return { refusal: "resources_unconfigured" };
152614
+ const routed = routedHost === void 0 ? void 0 : didWebForHost(routedHost);
152615
+ if (!routed)
152616
+ return { refusal: "no_routed_host" };
152617
+ if (!resources.includes(routed))
152618
+ return { refusal: "host_not_a_resource" };
152619
+ return { resourceDid: routed };
152620
+ }
152621
+ function audienceNamesResource(aud, resourceDid) {
152622
+ if (aud === void 0)
152623
+ return "missing";
152624
+ const value = Array.isArray(aud) && aud.length === 1 ? aud[0] : aud;
152625
+ return resourceDid !== void 0 && value === resourceDid ? "accepted" : "unmatched";
152626
+ }
152627
+
152628
+ // ../mcp-i-cloudflare/dist/services/delegation-trust.js
152585
152629
  var DID_PATTERN = /^did:[a-z0-9]+:[^\s#?]+$/;
152586
152630
  var UPSTREAM_TIMEOUT_MS = 3e3;
152587
152631
  var DID_DOCUMENT_TTL_MS = 5 * 6e4;
@@ -152599,35 +152643,24 @@ function checkpointOriginFor(url3) {
152599
152643
  }
152600
152644
  function resolveDelegationTrust(env2, options = {}) {
152601
152645
  const issuers = /* @__PURE__ */ new Set();
152602
- const audiences = /* @__PURE__ */ new Set();
152646
+ const { resourceDid, refusal: resourceRefusal } = routedResource(env2.KYA_OS_RESOURCE_DIDS, options.routedHost);
152603
152647
  const ownDid = typeof env2.MCP_IDENTITY_AGENT_DID === "string" && DID_PATTERN.test(env2.MCP_IDENTITY_AGENT_DID) ? env2.MCP_IDENTITY_AGENT_DID : void 0;
152604
- if (ownDid) {
152648
+ if (ownDid)
152605
152649
  issuers.add(ownDid);
152606
- audiences.add(ownDid);
152607
- }
152608
152650
  const binding = parseNativeIssuerBinding(env2.MCPI_NATIVE_HTTP_ISSUER_CONFIG);
152609
- if (binding) {
152651
+ if (binding)
152610
152652
  issuers.add(binding.issuerDid);
152611
- audiences.add(binding.issuerDid);
152612
- audiences.add(binding.projectId);
152613
- }
152614
152653
  for (const did of [
152615
152654
  ...listFrom(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
152616
152655
  ...options.trustedIssuers ?? []
152617
152656
  ])
152618
152657
  if (did && DID_PATTERN.test(did))
152619
152658
  issuers.add(did);
152620
- for (const aud of [
152621
- ...listFrom(env2.CHECKPOINT_PROJECT_ID),
152622
- ...listFrom(env2.KYA_OS_DELEGATION_AUDIENCES),
152623
- ...options.audiences ?? []
152624
- ])
152625
- if (aud)
152626
- audiences.add(aud);
152627
152659
  const checkpointUrl = env2.CHECKPOINT_API_URL || DEFAULT_CHECKPOINT_URL;
152628
152660
  return {
152629
152661
  issuers,
152630
- audiences,
152662
+ resourceDid,
152663
+ resourceRefusal,
152631
152664
  ownDid,
152632
152665
  checkpointOrigin: typeof checkpointUrl === "string" ? checkpointOriginFor(checkpointUrl) : void 0
152633
152666
  };
@@ -152641,10 +152674,7 @@ function credentialHandle(payload) {
152641
152674
  return typeof jti === "string" && jti.length > 0 ? jti : void 0;
152642
152675
  }
152643
152676
  function audienceVerdict(aud, trust) {
152644
- if (aud === void 0)
152645
- return "missing";
152646
- const values = Array.isArray(aud) ? aud : [aud];
152647
- return values.some((v) => typeof v === "string" && trust.audiences.has(v)) ? "accepted" : "unmatched";
152677
+ return audienceNamesResource(aud, trust.resourceDid);
152648
152678
  }
152649
152679
  async function readBounded(stream, maxBytes) {
152650
152680
  if (!stream)
@@ -152982,16 +153012,14 @@ var DelegationService = class {
152982
153012
  /**
152983
153013
  * Whether a cached development verdict still holds under THIS deployment's
152984
153014
  * trust: the token's issuer is the one the verdict was granted to, it is
152985
- * still pinned, and the token's `aud` is still accepted (a KV namespace may
152986
- * be shared by deployments with different audiences). Development only, so
152987
- * no audience is deferred to Checkpoint here.
153015
+ * still pinned, and the token's `aud` is still this worker's resource DID
153016
+ * (a KV namespace may be shared by deployments with different resources).
152988
153017
  */
152989
153018
  async servesCachedVerdict(token, grantedIssuer) {
152990
153019
  const payload = parseVCJWT2(token)?.payload;
152991
153020
  if (!payload || payload.iss !== grantedIssuer)
152992
153021
  return false;
152993
- const audience = audienceVerdict(payload.aud, this.trust);
152994
- if (audience !== "accepted" && !(audience === "missing" && grantedIssuer === this.trust.ownDid))
153022
+ if (audienceVerdict(payload.aud, this.trust) !== "accepted")
152995
153023
  return false;
152996
153024
  return this.isPinnedIssuer(grantedIssuer);
152997
153025
  }
@@ -153005,15 +153033,13 @@ var DelegationService = class {
153005
153033
  * only fetch an unpinned issuer can cause is the configured Checkpoint's own
153006
153034
  * DID document (cached).
153007
153035
  *
153008
- * Audience: `aud` must name this worker (see ./delegation-trust). Only a
153009
- * self-issued credential (issuer = this worker's own DID) may omit it: the
153010
- * anchor flow mints self-issued delegations without `aud`, while the
153011
- * Checkpoint platform mint, the hosted-consent org mint and the native
153012
- * issuer always set it. One exception: with a Checkpoint API key, a
153013
- * platform-signed credential may carry an `aud` this worker cannot name
153014
- * (its project UUID, while CHECKPOINT_PROJECT_ID is often the friendly id).
153015
- * Checkpoint's confirm pins that `aud` to the API key's project, so the
153016
- * check is left to it.
153036
+ * Audience: `aud` must be `did:web:<the host this request was routed for>`,
153037
+ * and that DID must be in `KYA_OS_RESOURCE_DIDS` (see ./delegation-trust),
153038
+ * whoever the issuer and whether or not a Checkpoint API key is set. A
153039
+ * credential without `aud`, or naming anything else (another of this
153040
+ * worker's hosts, the org DID, the worker's own DID, a project id), is
153041
+ * refused. Without a valid resource list, or without a routed host (a
153042
+ * verification with no request behind it), every credential is refused.
153017
153043
  *
153018
153044
  * Issuer: only pinned issuers are resolved and verified. An untrusted or
153019
153045
  * unresolvable issuer fails closed.
@@ -153033,15 +153059,14 @@ var DelegationService = class {
153033
153059
  const issuerDid2 = parsed.payload.iss;
153034
153060
  if (!issuerDid2 || typeof issuerDid2 !== "string")
153035
153061
  return reject("Missing issuer (iss)");
153062
+ if (!this.trust.resourceDid)
153063
+ return reject(RESOURCE_REFUSALS[this.trust.resourceRefusal]);
153036
153064
  const audience = audienceVerdict(parsed.payload.aud, this.trust);
153037
- if (audience === "missing" && issuerDid2 !== this.trust.ownDid)
153065
+ if (audience === "missing")
153038
153066
  return reject("Missing audience (aud)");
153039
- if (audience === "unmatched" && !this.env.CHECKPOINT_API_KEY)
153067
+ if (audience !== "accepted")
153040
153068
  return reject("Audience not accepted");
153041
- if (this.trust.issuers.has(issuerDid2)) {
153042
- if (audience === "unmatched")
153043
- return reject("Audience not accepted");
153044
- } else if (!await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153069
+ if (!this.trust.issuers.has(issuerDid2) && !await isCheckpointPlatformIssuer(issuerDid2, this.trust, this.didResolver)) {
153045
153070
  return reject(`Untrusted issuer: ${logSafe(issuerDid2)}`);
153046
153071
  }
153047
153072
  const kid = parsed.header.kid;
@@ -166382,7 +166407,7 @@ function mapPrefixedEnv(source, prefix) {
166382
166407
  // Delegation trust policy (DelegationService); set unprefixed like the
166383
166408
  // native issuer binding above.
166384
166409
  KYA_OS_TRUSTED_DELEGATION_ISSUERS: stringValue(env2.KYA_OS_TRUSTED_DELEGATION_ISSUERS),
166385
- KYA_OS_DELEGATION_AUDIENCES: stringValue(env2.KYA_OS_DELEGATION_AUDIENCES),
166410
+ KYA_OS_RESOURCE_DIDS: stringValue(env2.KYA_OS_RESOURCE_DIDS),
166386
166411
  KYA_OS_INSECURE_DEV_TOKENS: stringValue(env2.KYA_OS_INSECURE_DEV_TOKENS),
166387
166412
  CHECKPOINT_API_URL: typeof env2.CHECKPOINT_API_URL === "string" ? env2.CHECKPOINT_API_URL : void 0,
166388
166413
  CHECKPOINT_API_KEY: typeof env2.CHECKPOINT_API_KEY === "string" ? env2.CHECKPOINT_API_KEY : void 0,
@@ -166725,7 +166750,7 @@ init_native_oauth_state_do();
166725
166750
  // ../mcp-i-cloudflare/package.json
166726
166751
  var package_default = {
166727
166752
  name: "@kya-os/mcp-i-cloudflare",
166728
- version: "1.16.0",
166753
+ version: "1.17.0",
166729
166754
  description: "Cloudflare Workers adapter for MCP-I framework",
166730
166755
  main: "dist/index.js",
166731
166756
  types: "dist/index.d.ts",
@@ -174214,7 +174239,7 @@ async function applyBearerDelegation(request, env2, cfg, getProofSupport = getCa
174214
174239
  const native = cfg.native ?? void 0;
174215
174240
  const isValid2 = await new DelegationService(env2, void 0, {
174216
174241
  trustedIssuers: [native?.issuerDid],
174217
- audiences: [native?.issuerDid, native?.projectId]
174242
+ routedHost: new URL(request.url).host
174218
174243
  }).verifyDelegation(vcJwt);
174219
174244
  if (!isValid2) {
174220
174245
  if (isVcJwtExpired(vcJwt)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kya-os/create-mcpi-app",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "Scaffold a new MCP-I application",
5
5
  "type": "module",
6
6
  "main": "./dist/helpers/index.js",
@@ -51,7 +51,7 @@
51
51
  "@kya-os/cli-effects": "^1.0.19",
52
52
  "@kya-os/contracts": "^1.13.1",
53
53
  "@kya-os/mcp-i": "^1.13.1",
54
- "@kya-os/mcp-i-cloudflare": "^1.16.0",
54
+ "@kya-os/mcp-i-cloudflare": "^1.17.0",
55
55
  "base-x": "^5.0.0",
56
56
  "chalk": "^4.1.2",
57
57
  "commander": "^12.1.0",