@kya-os/checkpoint-express 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import nodeCrypto from 'crypto';
2
- import { gunzipSync } from 'zlib';
2
+ import { verifyRequest, renderDecisionAsResponse } from '@kya-os/checkpoint-wasm-runtime/orchestrator';
3
+ import { makeSystemClock, makePolicyEvaluator, makeReputationOracle, makeStatusListCache, makeDidResolver } from '@kya-os/checkpoint-wasm-runtime/adapters';
3
4
  import { shouldEnforce, acceptsHtml, encodeVerdictCookie, classifyResponseShape, BLOCKED_PATH, VERDICT_COOKIE_NAME } from '@kya-os/checkpoint-shared';
4
5
  export { DEFAULT_POLICY, ENFORCEMENT_ACTIONS, createEvaluationContext, evaluatePolicy } from '@kya-os/checkpoint-shared';
5
6
 
@@ -4921,10 +4922,10 @@ var init_nodejs = __esm({
4921
4922
  _noTokenize;
4922
4923
  _noStem;
4923
4924
  _from;
4924
- constructor(noTokenize = { noTokenize: false }, noStem = { noStem: false }, from2 = { from: null }) {
4925
+ constructor(noTokenize = { noTokenize: false }, noStem = { noStem: false }, from = { from: null }) {
4925
4926
  this._noTokenize = noTokenize;
4926
4927
  this._noStem = noStem;
4927
- this._from = from2;
4928
+ this._from = from;
4928
4929
  }
4929
4930
  noTokenize() {
4930
4931
  return new _TextFieldBuilder({ noTokenize: true }, this._noStem, this._from);
@@ -4947,9 +4948,9 @@ var init_nodejs = __esm({
4947
4948
  NumericFieldBuilder = class _NumericFieldBuilder {
4948
4949
  type;
4949
4950
  _from;
4950
- constructor(type, from2 = { from: null }) {
4951
+ constructor(type, from = { from: null }) {
4951
4952
  this.type = type;
4952
- this._from = from2;
4953
+ this._from = from;
4953
4954
  }
4954
4955
  from(field) {
4955
4956
  return new _NumericFieldBuilder(this.type, { from: field });
@@ -4968,9 +4969,9 @@ var init_nodejs = __esm({
4968
4969
  BoolFieldBuilder = class _BoolFieldBuilder {
4969
4970
  _fast;
4970
4971
  _from;
4971
- constructor(fast = { fast: false }, from2 = { from: null }) {
4972
+ constructor(fast = { fast: false }, from = { from: null }) {
4972
4973
  this._fast = fast;
4973
- this._from = from2;
4974
+ this._from = from;
4974
4975
  }
4975
4976
  fast() {
4976
4977
  return new _BoolFieldBuilder({ fast: true }, this._from);
@@ -5006,9 +5007,9 @@ var init_nodejs = __esm({
5006
5007
  DateFieldBuilder = class _DateFieldBuilder {
5007
5008
  _fast;
5008
5009
  _from;
5009
- constructor(fast = { fast: false }, from2 = { from: null }) {
5010
+ constructor(fast = { fast: false }, from = { from: null }) {
5010
5011
  this._fast = fast;
5011
- this._from = from2;
5012
+ this._from = from;
5012
5013
  }
5013
5014
  fast() {
5014
5015
  return new _DateFieldBuilder({ fast: true }, this._from);
@@ -5191,1346 +5192,6 @@ var init_nodejs = __esm({
5191
5192
  };
5192
5193
  }
5193
5194
  });
5194
-
5195
- // ../checkpoint-wasm-runtime/dist/orchestrator-node.mjs
5196
- var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "metadata", "metadata.google.internal"]);
5197
- var UnsafeOutboundUrl = class extends Error {
5198
- kind = "UnsafeOutboundUrl";
5199
- };
5200
- function assertSafeHttpsUrl(rawUrl, label = "outbound URL") {
5201
- let parsed;
5202
- try {
5203
- parsed = new URL(rawUrl);
5204
- } catch {
5205
- throw new UnsafeOutboundUrl(`${label} must be a valid URL: ${rawUrl}`);
5206
- }
5207
- if (parsed.protocol !== "https:") {
5208
- throw new UnsafeOutboundUrl(`${label} must use https: ${rawUrl}`);
5209
- }
5210
- if (parsed.username || parsed.password) {
5211
- throw new UnsafeOutboundUrl(`${label} must not contain credentials: ${rawUrl}`);
5212
- }
5213
- const hostname = normalizeHostname(parsed.hostname);
5214
- if (!hostname || isBlockedHostname(hostname)) {
5215
- throw new UnsafeOutboundUrl(`${label} targets a local or private host: ${rawUrl}`);
5216
- }
5217
- return rawUrl;
5218
- }
5219
- function normalizeHostname(hostname) {
5220
- let normalized = hostname.trim().toLowerCase();
5221
- if (normalized.startsWith("[") && normalized.endsWith("]")) {
5222
- normalized = normalized.slice(1, -1);
5223
- }
5224
- while (normalized.endsWith(".")) {
5225
- normalized = normalized.slice(0, -1);
5226
- }
5227
- return normalized;
5228
- }
5229
- function isBlockedHostname(hostname) {
5230
- if (BLOCKED_HOSTNAMES.has(hostname) || hostname.endsWith(".localhost")) {
5231
- return true;
5232
- }
5233
- const ipv4 = parseIpv4(hostname);
5234
- if (ipv4) {
5235
- return isBlockedIpv4(ipv4);
5236
- }
5237
- return isBlockedIpv6(hostname);
5238
- }
5239
- function parseIpv4(hostname) {
5240
- const parts = hostname.split(".");
5241
- if (parts.length !== 4) return null;
5242
- const octets = parts.map((part) => {
5243
- if (!/^\d{1,3}$/.test(part)) return Number.NaN;
5244
- const value = Number(part);
5245
- return value >= 0 && value <= 255 ? value : Number.NaN;
5246
- });
5247
- if (octets.some(Number.isNaN)) return null;
5248
- return octets;
5249
- }
5250
- function isBlockedIpv4([a, b]) {
5251
- return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 198 && (b === 18 || b === 19) || a >= 224;
5252
- }
5253
- function isBlockedIpv6(hostname) {
5254
- if (!hostname.includes(":")) return false;
5255
- const ipv4Mapped = hostname.match(/(?:^|:)ffff:(\d{1,3}(?:\.\d{1,3}){3})$/);
5256
- if (ipv4Mapped) {
5257
- const ipv4 = parseIpv4(ipv4Mapped[1]);
5258
- return ipv4 ? isBlockedIpv4(ipv4) : true;
5259
- }
5260
- if (hostname === "::" || hostname === "::1" || hostname === "0:0:0:0:0:0:0:1") {
5261
- return true;
5262
- }
5263
- const firstSegment = Number.parseInt(hostname.split(":")[0] || "0", 16);
5264
- if (Number.isNaN(firstSegment)) return true;
5265
- return (firstSegment & 65024) === 64512 || // unique local fc00::/7
5266
- (firstSegment & 65472) === 65152 || // link-local fe80::/10
5267
- (firstSegment & 65280) === 65280;
5268
- }
5269
- function engineVerify(input, ctx) {
5270
- const result = (void 0)(input, ctx);
5271
- return result;
5272
- }
5273
- function base64UrlDecode(input) {
5274
- const padded = input.replace(/-/g, "+").replace(/_/g, "/");
5275
- const padding = padded.length % 4 === 0 ? "" : "=".repeat(4 - padded.length % 4);
5276
- return new Uint8Array(Buffer.from(padded + padding, "base64"));
5277
- }
5278
- function buildAgentRequest(req, opts = {}) {
5279
- const mcpI = tryBuildMcpIFromBody(req);
5280
- if (mcpI) {
5281
- return { protocol: "McpI", request: mcpI };
5282
- }
5283
- if (opts.legacyEnvelopeFallback) {
5284
- const legacyMcpI = tryBuildMcpIFromLegacyHeader(req);
5285
- if (legacyMcpI) {
5286
- return { protocol: "McpI", request: legacyMcpI };
5287
- }
5288
- }
5289
- if (getHeader(req, "signature-input")) {
5290
- return { protocol: "HttpSigned", request: buildHttpSigned(req) };
5291
- }
5292
- return { protocol: "PlainHttp", request: buildPlainHttp(req) };
5293
- }
5294
- function hasMalformedJwsBody(req) {
5295
- const parsed = parseBodyAsObject(req.body);
5296
- if (!parsed || typeof parsed !== "object") return false;
5297
- const meta = parsed._meta;
5298
- if (!meta || typeof meta !== "object") return false;
5299
- const proof = meta.proof;
5300
- if (!proof || typeof proof !== "object") return false;
5301
- const jws = proof.jws;
5302
- if (typeof jws !== "string" || jws.length === 0) return false;
5303
- const raw = Array.from(Buffer.from(jws, "utf8"));
5304
- return parseJwsPayloadStruct(raw) === null;
5305
- }
5306
- function extractIssuer(request) {
5307
- if (request.protocol === "McpI") return request.request.payload.iss || null;
5308
- return null;
5309
- }
5310
- function extractAgentDid(request) {
5311
- if (request.protocol === "McpI") return request.request.payload.sub || null;
5312
- return null;
5313
- }
5314
- function extractCredentialStatusUrl(request) {
5315
- if (request.protocol !== "McpI") return null;
5316
- const raw = decodeJwsPayloadJson(request.request.raw);
5317
- if (!raw) return null;
5318
- const vc = raw.vc;
5319
- if (!vc || typeof vc !== "object") return null;
5320
- const credentialStatus = vc.credentialStatus;
5321
- if (!credentialStatus || typeof credentialStatus !== "object") return null;
5322
- const id = credentialStatus.id;
5323
- return typeof id === "string" ? id : null;
5324
- }
5325
- function tryBuildMcpIFromBody(req) {
5326
- const parsed = parseBodyAsObject(req.body);
5327
- if (!parsed) return null;
5328
- const meta = parsed._meta;
5329
- if (!meta || typeof meta !== "object") return null;
5330
- const proof = meta.proof;
5331
- if (!proof || typeof proof !== "object") return null;
5332
- const jws = proof.jws;
5333
- if (typeof jws !== "string" || jws.length === 0) return null;
5334
- const raw = Array.from(Buffer.from(jws, "utf8"));
5335
- const payload = parseJwsPayloadStruct(raw);
5336
- if (!payload) return null;
5337
- return { raw, payload };
5338
- }
5339
- function parseBodyAsObject(body) {
5340
- if (!body) return null;
5341
- if (Buffer.isBuffer(body)) {
5342
- try {
5343
- return JSON.parse(body.toString("utf8"));
5344
- } catch {
5345
- return null;
5346
- }
5347
- }
5348
- if (typeof body === "string") {
5349
- try {
5350
- return JSON.parse(body);
5351
- } catch {
5352
- return null;
5353
- }
5354
- }
5355
- if (typeof body === "object") return body;
5356
- return null;
5357
- }
5358
- function tryBuildMcpIFromLegacyHeader(req) {
5359
- const header = getHeader(req, "kya-delegation");
5360
- if (!header) return null;
5361
- let parsed;
5362
- try {
5363
- parsed = JSON.parse(header);
5364
- } catch {
5365
- return null;
5366
- }
5367
- if (!parsed || typeof parsed !== "object") return null;
5368
- const obj = parsed;
5369
- const protectedSeg = obj.protected;
5370
- const payloadSeg = obj.payload;
5371
- const signatureSeg = obj.signature;
5372
- if (typeof protectedSeg !== "string" || typeof payloadSeg !== "string" || typeof signatureSeg !== "string") {
5373
- return null;
5374
- }
5375
- const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
5376
- const raw = Array.from(Buffer.from(compact, "utf8"));
5377
- const payload = parseJwsPayloadStruct(raw);
5378
- if (!payload) return null;
5379
- return { raw, payload };
5380
- }
5381
- function parseJwsPayloadStruct(rawBytes) {
5382
- const json = decodeJwsPayloadJson(rawBytes);
5383
- if (!json || typeof json !== "object") return null;
5384
- return projectMcpIPayload(json);
5385
- }
5386
- function decodeJwsPayloadJson(rawBytes) {
5387
- const text = Buffer.from(rawBytes).toString("utf8");
5388
- const segments = text.split(".");
5389
- if (segments.length !== 3) return null;
5390
- let decoded;
5391
- try {
5392
- decoded = base64UrlDecode(segments[1]);
5393
- } catch {
5394
- return null;
5395
- }
5396
- try {
5397
- return JSON.parse(Buffer.from(decoded).toString("utf8"));
5398
- } catch {
5399
- return null;
5400
- }
5401
- }
5402
- function projectMcpIPayload(raw) {
5403
- const aud = raw.aud;
5404
- const iss = raw.iss;
5405
- const sub = raw.sub;
5406
- const nonce = raw.nonce;
5407
- const sessionId = raw.sessionId;
5408
- const ts = raw.ts;
5409
- const requestHash = raw.requestHash;
5410
- const responseHash = raw.responseHash;
5411
- if (typeof aud !== "string" || typeof iss !== "string" || typeof sub !== "string" || typeof nonce !== "string" || typeof sessionId !== "string" || typeof ts !== "number" || typeof requestHash !== "string" || typeof responseHash !== "string") {
5412
- return null;
5413
- }
5414
- return { aud, iss, sub, nonce, sessionId, ts, requestHash, responseHash };
5415
- }
5416
- function buildHttpSigned(req) {
5417
- return {
5418
- raw: bodyAsBytes(req.body),
5419
- method: req.method,
5420
- path: req.url,
5421
- headers: flattenHeaders(req.headers)
5422
- };
5423
- }
5424
- function buildPlainHttp(req) {
5425
- return {
5426
- raw: bodyAsBytes(req.body),
5427
- method: req.method,
5428
- path: req.url,
5429
- headers: flattenHeaders(req.headers),
5430
- userAgent: getHeader(req, "user-agent") ?? null,
5431
- remoteIp: req.remoteAddress ?? null
5432
- };
5433
- }
5434
- function getHeader(req, name) {
5435
- const lowered = name.toLowerCase();
5436
- for (const [key, value] of Object.entries(req.headers)) {
5437
- if (key.toLowerCase() !== lowered) continue;
5438
- if (Array.isArray(value)) return value[0] ?? null;
5439
- if (typeof value === "string") return value;
5440
- }
5441
- return null;
5442
- }
5443
- function flattenHeaders(headers) {
5444
- const out = [];
5445
- for (const [key, value] of Object.entries(headers)) {
5446
- if (value === void 0) continue;
5447
- if (Array.isArray(value)) {
5448
- for (const v of value) out.push([key, v]);
5449
- } else {
5450
- out.push([key, value]);
5451
- }
5452
- }
5453
- return out;
5454
- }
5455
- function bodyAsBytes(body) {
5456
- if (!body) return [];
5457
- if (Buffer.isBuffer(body)) return Array.from(body);
5458
- if (typeof body === "string") return Array.from(Buffer.from(body, "utf8"));
5459
- if (typeof body === "object") return Array.from(Buffer.from(JSON.stringify(body), "utf8"));
5460
- return [];
5461
- }
5462
- var DEFAULT_REPUTATION_BASELINE = 1;
5463
- async function verifyRequest(req, opts) {
5464
- return verifyRequest_internal(req, opts);
5465
- }
5466
- async function verifyRequest_internal(req, opts) {
5467
- if (hasMalformedJwsBody(req)) {
5468
- return blockWithParseError("malformed JWS body", opts.enforcementMode);
5469
- }
5470
- const agentRequest = buildAgentRequest(req, {
5471
- legacyEnvelopeFallback: opts.legacyEnvelopeFallback
5472
- });
5473
- const issuer = extractIssuer(agentRequest);
5474
- const agentDid = extractAgentDid(agentRequest);
5475
- const credentialStatusUrl = extractCredentialStatusUrl(agentRequest);
5476
- const baseline = opts.reputationBaseline ?? DEFAULT_REPUTATION_BASELINE;
5477
- const [didResult, statusResult, repResult] = await Promise.allSettled([
5478
- issuer ? opts.didResolver.resolve(issuer) : Promise.resolve(null),
5479
- credentialStatusUrl ? fetchCredentialStatus(credentialStatusUrl, opts.statusListCache) : Promise.resolve(null),
5480
- agentDid ? opts.reputationOracle.score(agentDid) : Promise.resolve(baseline)
5481
- ]);
5482
- if (didResult.status === "rejected") {
5483
- if (isDidResolverError(didResult.reason)) {
5484
- return blockWithParseError(
5485
- didResult.reason instanceof Error ? didResult.reason.message : String(didResult.reason),
5486
- opts.enforcementMode
5487
- );
5488
- }
5489
- throw didResult.reason;
5490
- }
5491
- if (statusResult.status === "rejected") {
5492
- if (statusResult.reason instanceof UnsafeOutboundUrl) {
5493
- return blockWithParseError(statusResult.reason.message, opts.enforcementMode);
5494
- }
5495
- throw statusResult.reason;
5496
- }
5497
- if (repResult.status === "rejected") {
5498
- throw repResult.reason;
5499
- }
5500
- const didDoc = didResult.value;
5501
- const revokedIndices = statusResult.value;
5502
- const repScore = repResult.value;
5503
- const tenantDecision = await opts.policyEvaluator.evaluate({
5504
- tenantHost: opts.tenantHost,
5505
- reputation: repScore
5506
- });
5507
- const ctx = {
5508
- didDocs: didDoc && issuer ? { [issuer]: didDoc } : {},
5509
- revoked: revokedIndices !== null && credentialStatusUrl ? { [credentialStatusUrl]: revokedIndices } : {},
5510
- reputation: agentDid ? { [agentDid]: repScore } : {},
5511
- tenantDecision,
5512
- nowUnix: opts.clock.nowUnix(),
5513
- enforcementMode: opts.enforcementMode
5514
- };
5515
- return engineVerify(agentRequest, ctx);
5516
- }
5517
- async function fetchCredentialStatus(credentialStatusUrl, statusListCache) {
5518
- assertSafeHttpsUrl(credentialStatusUrl, "credential status URL");
5519
- return statusListCache.fetch(credentialStatusUrl);
5520
- }
5521
- function isDidResolverError(err) {
5522
- if (!(err instanceof Error)) return false;
5523
- const kind = err.kind;
5524
- return kind === "DidNotFound" || kind === "DidResolverTimeout" || kind === "DidResolverError" || kind === "MalformedDid" || kind === "UnsupportedKeyType" || kind === "UnsupportedDidMethod";
5525
- }
5526
- function blockWithParseError(detail, enforcementMode) {
5527
- return {
5528
- decision: {
5529
- kind: "Block",
5530
- reason: {
5531
- kind: "ParseError",
5532
- detail
5533
- }
5534
- },
5535
- enforcementMode,
5536
- engineInfo: {
5537
- name: "checkpoint-engine-wasm",
5538
- version: "0.0.0-host-synth",
5539
- rulesetHash: "sha256:host-synthesized",
5540
- rulesetVersion: "0.0.0-host-synth",
5541
- extras: { synthesized: true }
5542
- }
5543
- };
5544
- }
5545
- function renderDecisionAsResponse(result) {
5546
- const baseHeaders = buildBaseHeaders(result);
5547
- if (result.enforcementMode === "observe") {
5548
- return {
5549
- status: null,
5550
- headers: {
5551
- ...baseHeaders,
5552
- "X-Checkpoint-Mode": "observe",
5553
- "X-Checkpoint-Would-Have-Been": result.decision.kind,
5554
- ...wouldHaveBeenReasonHeader(result)
5555
- }
5556
- };
5557
- }
5558
- switch (result.decision.kind) {
5559
- case "Permit":
5560
- return {
5561
- status: null,
5562
- headers: { ...baseHeaders, "X-Checkpoint-Decision": "permit" }
5563
- };
5564
- case "Block": {
5565
- const reason = result.decision.reason;
5566
- return {
5567
- status: httpStatusForBlockReason(reason),
5568
- headers: {
5569
- ...baseHeaders,
5570
- ...blockHeaders(reason),
5571
- "X-Checkpoint-Decision": "block",
5572
- "X-Checkpoint-Reason": reason.kind
5573
- },
5574
- body: blockResponseBody(reason)
5575
- };
5576
- }
5577
- case "Challenge": {
5578
- const params = result.decision.params;
5579
- return {
5580
- status: 401,
5581
- headers: {
5582
- ...baseHeaders,
5583
- "X-Checkpoint-Decision": "challenge",
5584
- "X-Checkpoint-Challenge": params.nonce
5585
- },
5586
- body: {
5587
- challenge: params
5588
- }
5589
- };
5590
- }
5591
- case "Redirect": {
5592
- const target = result.decision.target;
5593
- return {
5594
- status: 302,
5595
- headers: {
5596
- ...baseHeaders,
5597
- "X-Checkpoint-Decision": "redirect",
5598
- Location: target.url,
5599
- "X-Checkpoint-Redirect-Reason": target.reason
5600
- }
5601
- };
5602
- }
5603
- case "Instruct": {
5604
- const payload = result.decision.payload;
5605
- return {
5606
- status: 422,
5607
- headers: {
5608
- ...baseHeaders,
5609
- "X-Checkpoint-Decision": "instruct",
5610
- "Content-Type": "application/problem+json"
5611
- },
5612
- body: {
5613
- type: payload.problem,
5614
- title: payload.title,
5615
- suggestedActions: payload.suggestedActions
5616
- }
5617
- };
5618
- }
5619
- }
5620
- }
5621
- function buildBaseHeaders(result) {
5622
- const headers = {
5623
- "X-Checkpoint-Engine": result.engineInfo.name,
5624
- "X-Checkpoint-Engine-Version": result.engineInfo.version
5625
- };
5626
- if (result.engineInfo.rulesetHash) {
5627
- headers["X-Checkpoint-Ruleset-Hash"] = result.engineInfo.rulesetHash;
5628
- }
5629
- return headers;
5630
- }
5631
- function httpStatusForBlockReason(reason) {
5632
- switch (reason.kind) {
5633
- case "Unauthenticated":
5634
- case "Expired":
5635
- return 401;
5636
- case "ParseError":
5637
- return 400;
5638
- case "InvalidSignature":
5639
- case "Revoked":
5640
- case "OutOfScope":
5641
- case "LowReputation":
5642
- case "PolicyDenied":
5643
- return 403;
5644
- }
5645
- }
5646
- function blockHeaders(reason) {
5647
- if (reason.kind === "Unauthenticated") {
5648
- return { "WWW-Authenticate": 'KyaProof realm="checkpoint"' };
5649
- }
5650
- return {};
5651
- }
5652
- function blockResponseBody(reason) {
5653
- switch (reason.kind) {
5654
- case "Revoked":
5655
- case "InvalidSignature":
5656
- case "Unauthenticated":
5657
- case "Expired":
5658
- return { error: humanError(reason.kind), reason: reason.kind };
5659
- case "OutOfScope":
5660
- return {
5661
- error: "requested scope is not granted",
5662
- reason: "OutOfScope",
5663
- requested: reason.requested,
5664
- granted: reason.granted
5665
- };
5666
- case "LowReputation":
5667
- return {
5668
- error: "agent reputation below tenant threshold",
5669
- reason: "LowReputation",
5670
- score: reason.score,
5671
- threshold: reason.threshold
5672
- };
5673
- case "PolicyDenied":
5674
- return {
5675
- error: "tenant policy denied the request",
5676
- reason: "PolicyDenied",
5677
- detail: reason.detail
5678
- };
5679
- case "ParseError":
5680
- return {
5681
- error: "request envelope could not be parsed",
5682
- reason: "ParseError",
5683
- detail: reason.detail
5684
- };
5685
- }
5686
- }
5687
- function humanError(kind) {
5688
- switch (kind) {
5689
- case "Revoked":
5690
- return "credential has been revoked";
5691
- case "InvalidSignature":
5692
- return "request signature failed verification";
5693
- case "Unauthenticated":
5694
- return "authentication required";
5695
- case "Expired":
5696
- return "credential is expired";
5697
- }
5698
- }
5699
- function wouldHaveBeenReasonHeader(result) {
5700
- if (result.decision.kind === "Block") {
5701
- return { "X-Checkpoint-Would-Have-Been-Reason": result.decision.reason.kind };
5702
- }
5703
- return {};
5704
- }
5705
- function coerce(o) {
5706
- if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") {
5707
- return o;
5708
- }
5709
- if (o instanceof ArrayBuffer) {
5710
- return new Uint8Array(o);
5711
- }
5712
- if (ArrayBuffer.isView(o)) {
5713
- return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
5714
- }
5715
- throw new Error("Unknown type, must be binary type");
5716
- }
5717
-
5718
- // ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/vendor/base-x.js
5719
- function base(ALPHABET, name) {
5720
- if (ALPHABET.length >= 255) {
5721
- throw new TypeError("Alphabet too long");
5722
- }
5723
- var BASE_MAP = new Uint8Array(256);
5724
- for (var j = 0; j < BASE_MAP.length; j++) {
5725
- BASE_MAP[j] = 255;
5726
- }
5727
- for (var i = 0; i < ALPHABET.length; i++) {
5728
- var x = ALPHABET.charAt(i);
5729
- var xc = x.charCodeAt(0);
5730
- if (BASE_MAP[xc] !== 255) {
5731
- throw new TypeError(x + " is ambiguous");
5732
- }
5733
- BASE_MAP[xc] = i;
5734
- }
5735
- var BASE = ALPHABET.length;
5736
- var LEADER = ALPHABET.charAt(0);
5737
- var FACTOR = Math.log(BASE) / Math.log(256);
5738
- var iFACTOR = Math.log(256) / Math.log(BASE);
5739
- function encode(source) {
5740
- if (source instanceof Uint8Array)
5741
- ;
5742
- else if (ArrayBuffer.isView(source)) {
5743
- source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
5744
- } else if (Array.isArray(source)) {
5745
- source = Uint8Array.from(source);
5746
- }
5747
- if (!(source instanceof Uint8Array)) {
5748
- throw new TypeError("Expected Uint8Array");
5749
- }
5750
- if (source.length === 0) {
5751
- return "";
5752
- }
5753
- var zeroes = 0;
5754
- var length = 0;
5755
- var pbegin = 0;
5756
- var pend = source.length;
5757
- while (pbegin !== pend && source[pbegin] === 0) {
5758
- pbegin++;
5759
- zeroes++;
5760
- }
5761
- var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
5762
- var b58 = new Uint8Array(size);
5763
- while (pbegin !== pend) {
5764
- var carry = source[pbegin];
5765
- var i2 = 0;
5766
- for (var it1 = size - 1; (carry !== 0 || i2 < length) && it1 !== -1; it1--, i2++) {
5767
- carry += 256 * b58[it1] >>> 0;
5768
- b58[it1] = carry % BASE >>> 0;
5769
- carry = carry / BASE >>> 0;
5770
- }
5771
- if (carry !== 0) {
5772
- throw new Error("Non-zero carry");
5773
- }
5774
- length = i2;
5775
- pbegin++;
5776
- }
5777
- var it2 = size - length;
5778
- while (it2 !== size && b58[it2] === 0) {
5779
- it2++;
5780
- }
5781
- var str = LEADER.repeat(zeroes);
5782
- for (; it2 < size; ++it2) {
5783
- str += ALPHABET.charAt(b58[it2]);
5784
- }
5785
- return str;
5786
- }
5787
- function decodeUnsafe(source) {
5788
- if (typeof source !== "string") {
5789
- throw new TypeError("Expected String");
5790
- }
5791
- if (source.length === 0) {
5792
- return new Uint8Array();
5793
- }
5794
- var psz = 0;
5795
- if (source[psz] === " ") {
5796
- return;
5797
- }
5798
- var zeroes = 0;
5799
- var length = 0;
5800
- while (source[psz] === LEADER) {
5801
- zeroes++;
5802
- psz++;
5803
- }
5804
- var size = (source.length - psz) * FACTOR + 1 >>> 0;
5805
- var b256 = new Uint8Array(size);
5806
- while (source[psz]) {
5807
- var carry = BASE_MAP[source.charCodeAt(psz)];
5808
- if (carry === 255) {
5809
- return;
5810
- }
5811
- var i2 = 0;
5812
- for (var it3 = size - 1; (carry !== 0 || i2 < length) && it3 !== -1; it3--, i2++) {
5813
- carry += BASE * b256[it3] >>> 0;
5814
- b256[it3] = carry % 256 >>> 0;
5815
- carry = carry / 256 >>> 0;
5816
- }
5817
- if (carry !== 0) {
5818
- throw new Error("Non-zero carry");
5819
- }
5820
- length = i2;
5821
- psz++;
5822
- }
5823
- if (source[psz] === " ") {
5824
- return;
5825
- }
5826
- var it4 = size - length;
5827
- while (it4 !== size && b256[it4] === 0) {
5828
- it4++;
5829
- }
5830
- var vch = new Uint8Array(zeroes + (size - it4));
5831
- var j2 = zeroes;
5832
- while (it4 !== size) {
5833
- vch[j2++] = b256[it4++];
5834
- }
5835
- return vch;
5836
- }
5837
- function decode2(string) {
5838
- var buffer = decodeUnsafe(string);
5839
- if (buffer) {
5840
- return buffer;
5841
- }
5842
- throw new Error(`Non-${name} character`);
5843
- }
5844
- return {
5845
- encode,
5846
- decodeUnsafe,
5847
- decode: decode2
5848
- };
5849
- }
5850
- var src = base;
5851
- var _brrp__multiformats_scope_baseX = src;
5852
- var base_x_default = _brrp__multiformats_scope_baseX;
5853
-
5854
- // ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/bases/base.js
5855
- var Encoder = class {
5856
- name;
5857
- prefix;
5858
- baseEncode;
5859
- constructor(name, prefix, baseEncode) {
5860
- this.name = name;
5861
- this.prefix = prefix;
5862
- this.baseEncode = baseEncode;
5863
- }
5864
- encode(bytes) {
5865
- if (bytes instanceof Uint8Array) {
5866
- return `${this.prefix}${this.baseEncode(bytes)}`;
5867
- } else {
5868
- throw Error("Unknown type, must be binary type");
5869
- }
5870
- }
5871
- };
5872
- var Decoder = class {
5873
- name;
5874
- prefix;
5875
- baseDecode;
5876
- prefixCodePoint;
5877
- constructor(name, prefix, baseDecode) {
5878
- this.name = name;
5879
- this.prefix = prefix;
5880
- const prefixCodePoint = prefix.codePointAt(0);
5881
- if (prefixCodePoint === void 0) {
5882
- throw new Error("Invalid prefix character");
5883
- }
5884
- this.prefixCodePoint = prefixCodePoint;
5885
- this.baseDecode = baseDecode;
5886
- }
5887
- decode(text) {
5888
- if (typeof text === "string") {
5889
- if (text.codePointAt(0) !== this.prefixCodePoint) {
5890
- throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
5891
- }
5892
- return this.baseDecode(text.slice(this.prefix.length));
5893
- } else {
5894
- throw Error("Can only multibase decode strings");
5895
- }
5896
- }
5897
- or(decoder) {
5898
- return or(this, decoder);
5899
- }
5900
- };
5901
- var ComposedDecoder = class {
5902
- decoders;
5903
- constructor(decoders) {
5904
- this.decoders = decoders;
5905
- }
5906
- or(decoder) {
5907
- return or(this, decoder);
5908
- }
5909
- decode(input) {
5910
- const prefix = input[0];
5911
- const decoder = this.decoders[prefix];
5912
- if (decoder != null) {
5913
- return decoder.decode(input);
5914
- } else {
5915
- throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
5916
- }
5917
- }
5918
- };
5919
- function or(left, right) {
5920
- return new ComposedDecoder({
5921
- ...left.decoders ?? { [left.prefix]: left },
5922
- ...right.decoders ?? { [right.prefix]: right }
5923
- });
5924
- }
5925
- var Codec = class {
5926
- name;
5927
- prefix;
5928
- baseEncode;
5929
- baseDecode;
5930
- encoder;
5931
- decoder;
5932
- constructor(name, prefix, baseEncode, baseDecode) {
5933
- this.name = name;
5934
- this.prefix = prefix;
5935
- this.baseEncode = baseEncode;
5936
- this.baseDecode = baseDecode;
5937
- this.encoder = new Encoder(name, prefix, baseEncode);
5938
- this.decoder = new Decoder(name, prefix, baseDecode);
5939
- }
5940
- encode(input) {
5941
- return this.encoder.encode(input);
5942
- }
5943
- decode(input) {
5944
- return this.decoder.decode(input);
5945
- }
5946
- };
5947
- function from({ name, prefix, encode, decode: decode2 }) {
5948
- return new Codec(name, prefix, encode, decode2);
5949
- }
5950
- function baseX({ name, prefix, alphabet }) {
5951
- const { encode, decode: decode2 } = base_x_default(alphabet, name);
5952
- return from({
5953
- prefix,
5954
- name,
5955
- encode,
5956
- decode: (text) => coerce(decode2(text))
5957
- });
5958
- }
5959
-
5960
- // ../../node_modules/.pnpm/multiformats@13.4.2/node_modules/multiformats/dist/src/bases/base58.js
5961
- var base58btc = baseX({
5962
- name: "base58btc",
5963
- prefix: "z",
5964
- alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
5965
- });
5966
- baseX({
5967
- name: "base58flickr",
5968
- prefix: "Z",
5969
- alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
5970
- });
5971
- var BLOCKED_HOSTNAMES2 = /* @__PURE__ */ new Set(["localhost", "metadata", "metadata.google.internal"]);
5972
- var UnsafeOutboundUrl2 = class extends Error {
5973
- kind = "UnsafeOutboundUrl";
5974
- };
5975
- function assertSafeHttpsUrl2(rawUrl, label = "outbound URL") {
5976
- let parsed;
5977
- try {
5978
- parsed = new URL(rawUrl);
5979
- } catch {
5980
- throw new UnsafeOutboundUrl2(`${label} must be a valid URL: ${rawUrl}`);
5981
- }
5982
- if (parsed.protocol !== "https:") {
5983
- throw new UnsafeOutboundUrl2(`${label} must use https: ${rawUrl}`);
5984
- }
5985
- if (parsed.username || parsed.password) {
5986
- throw new UnsafeOutboundUrl2(`${label} must not contain credentials: ${rawUrl}`);
5987
- }
5988
- const hostname = normalizeHostname2(parsed.hostname);
5989
- if (!hostname || isBlockedHostname2(hostname)) {
5990
- throw new UnsafeOutboundUrl2(`${label} targets a local or private host: ${rawUrl}`);
5991
- }
5992
- return rawUrl;
5993
- }
5994
- function normalizeHostname2(hostname) {
5995
- let normalized = hostname.trim().toLowerCase();
5996
- if (normalized.startsWith("[") && normalized.endsWith("]")) {
5997
- normalized = normalized.slice(1, -1);
5998
- }
5999
- while (normalized.endsWith(".")) {
6000
- normalized = normalized.slice(0, -1);
6001
- }
6002
- return normalized;
6003
- }
6004
- function isBlockedHostname2(hostname) {
6005
- if (BLOCKED_HOSTNAMES2.has(hostname) || hostname.endsWith(".localhost")) {
6006
- return true;
6007
- }
6008
- const ipv4 = parseIpv42(hostname);
6009
- if (ipv4) {
6010
- return isBlockedIpv42(ipv4);
6011
- }
6012
- return isBlockedIpv62(hostname);
6013
- }
6014
- function parseIpv42(hostname) {
6015
- const parts = hostname.split(".");
6016
- if (parts.length !== 4) return null;
6017
- const octets = parts.map((part) => {
6018
- if (!/^\d{1,3}$/.test(part)) return Number.NaN;
6019
- const value = Number(part);
6020
- return value >= 0 && value <= 255 ? value : Number.NaN;
6021
- });
6022
- if (octets.some(Number.isNaN)) return null;
6023
- return octets;
6024
- }
6025
- function isBlockedIpv42([a, b]) {
6026
- return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 198 && (b === 18 || b === 19) || a >= 224;
6027
- }
6028
- function isBlockedIpv62(hostname) {
6029
- if (!hostname.includes(":")) return false;
6030
- const ipv4Mapped = hostname.match(/(?:^|:)ffff:(\d{1,3}(?:\.\d{1,3}){3})$/);
6031
- if (ipv4Mapped) {
6032
- const ipv4 = parseIpv42(ipv4Mapped[1]);
6033
- return ipv4 ? isBlockedIpv42(ipv4) : true;
6034
- }
6035
- if (hostname === "::" || hostname === "::1" || hostname === "0:0:0:0:0:0:0:1") {
6036
- return true;
6037
- }
6038
- const firstSegment = Number.parseInt(hostname.split(":")[0] || "0", 16);
6039
- if (Number.isNaN(firstSegment)) return true;
6040
- return (firstSegment & 65024) === 64512 || // unique local fc00::/7
6041
- (firstSegment & 65472) === 65152 || // link-local fe80::/10
6042
- (firstSegment & 65280) === 65280;
6043
- }
6044
- function base64UrlDecode2(input) {
6045
- const padded = input.replace(/-/g, "+").replace(/_/g, "/");
6046
- const padding = padded.length % 4 === 0 ? "" : "=".repeat(4 - padded.length % 4);
6047
- return new Uint8Array(Buffer.from(padded + padding, "base64"));
6048
- }
6049
- var ED25519_PUBLIC_KEY_LENGTH = 32;
6050
- var MalformedDid = class extends Error {
6051
- kind = "MalformedDid";
6052
- };
6053
- var UnsupportedKeyType = class extends Error {
6054
- kind = "UnsupportedKeyType";
6055
- };
6056
- var DidNotFound = class extends Error {
6057
- kind = "DidNotFound";
6058
- };
6059
- var DidResolverTimeout = class extends Error {
6060
- kind = "DidResolverTimeout";
6061
- };
6062
- var DidResolverError = class extends Error {
6063
- kind = "DidResolverError";
6064
- };
6065
- var UnsupportedDidMethod = class extends Error {
6066
- kind = "UnsupportedDidMethod";
6067
- };
6068
- var ED25519_MULTICODEC_PREFIX = [237, 1];
6069
- var DEFAULT_FETCH_TIMEOUT_MS = 3e3;
6070
- var DEFAULT_TTL_MS = 5 * 6e4;
6071
- function makeDidResolver(opts = {}) {
6072
- const timeoutMs = opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
6073
- const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
6074
- const fetchImpl = opts.fetch ?? fetch;
6075
- const cache = opts.cache ?? /* @__PURE__ */ new Map();
6076
- const now = opts.now ?? (() => Date.now());
6077
- return {
6078
- async resolve(did) {
6079
- const cached = cache.get(did);
6080
- if (cached && now() - cached.fetchedAt < ttlMs) {
6081
- return cached.value;
6082
- }
6083
- if (did.startsWith("did:key:")) {
6084
- const doc = decodeDidKey(did);
6085
- cache.set(did, { value: doc, fetchedAt: now() });
6086
- return doc;
6087
- }
6088
- if (did.startsWith("did:web:")) {
6089
- const doc = await resolveDidWeb(did, fetchImpl, timeoutMs);
6090
- cache.set(did, { value: doc, fetchedAt: now() });
6091
- return doc;
6092
- }
6093
- throw new UnsupportedDidMethod(`Phase 1 supports did:key and did:web only; got: ${did}`);
6094
- }
6095
- };
6096
- }
6097
- function decodeDidKey(did) {
6098
- if (!did.startsWith("did:key:")) {
6099
- throw new MalformedDid(`expected did:key prefix, got: ${did}`);
6100
- }
6101
- const multibaseValue = did.slice("did:key:".length);
6102
- if (!multibaseValue.startsWith("z")) {
6103
- throw new MalformedDid(
6104
- `did:key expects base58btc (multibase 'z' prefix); got: ${multibaseValue[0] ?? "<empty>"}`
6105
- );
6106
- }
6107
- let decoded;
6108
- try {
6109
- decoded = base58btc.decode(multibaseValue);
6110
- } catch (cause) {
6111
- throw new MalformedDid(`did:key multibase decode failed: ${String(cause)}`);
6112
- }
6113
- if (decoded.length < 2 || decoded[0] !== ED25519_MULTICODEC_PREFIX[0] || decoded[1] !== ED25519_MULTICODEC_PREFIX[1]) {
6114
- const prefixHex = decoded.length >= 2 ? `0x${decoded[0].toString(16).padStart(2, "0")}${decoded[1].toString(16).padStart(2, "0")}` : "<too short>";
6115
- throw new UnsupportedKeyType(
6116
- `did:key expects Ed25519 multicodec 0xed01; got ${prefixHex} (only Ed25519 supported in Phase 1)`
6117
- );
6118
- }
6119
- const publicKey = decoded.slice(2);
6120
- if (publicKey.length !== 32) {
6121
- throw new MalformedDid(`did:key Ed25519 public key must be 32 bytes; got ${publicKey.length}`);
6122
- }
6123
- const vm = {
6124
- id: `${did}#${multibaseValue}`,
6125
- // multibase as fragment — mcp-i-core PR #16
6126
- keyType: "Ed25519",
6127
- publicKeyBytes: Array.from(publicKey)
6128
- };
6129
- return {
6130
- id: did,
6131
- verificationMethods: [vm]
6132
- };
6133
- }
6134
- async function resolveDidWeb(did, fetchImpl, timeoutMs) {
6135
- const transformedUrl = didWebToUrl(did);
6136
- let url;
6137
- try {
6138
- url = assertSafeHttpsUrl2(transformedUrl, "did:web resolution URL");
6139
- } catch (cause) {
6140
- if (cause instanceof UnsafeOutboundUrl2) {
6141
- throw new DidResolverError(cause.message);
6142
- }
6143
- throw cause;
6144
- }
6145
- const controller = new AbortController();
6146
- const timer = setTimeout(() => controller.abort(), timeoutMs);
6147
- let response;
6148
- try {
6149
- response = await fetchImpl(url, { signal: controller.signal });
6150
- } catch (cause) {
6151
- if (cause instanceof Error && cause.name === "AbortError") {
6152
- throw new DidResolverTimeout(`did:web fetch timed out after ${timeoutMs}ms: ${url}`);
6153
- }
6154
- throw new DidResolverError(`did:web fetch failed: ${url}: ${String(cause)}`);
6155
- } finally {
6156
- clearTimeout(timer);
6157
- }
6158
- if (response.status === 404) {
6159
- throw new DidNotFound(`no DID document at ${url}`);
6160
- }
6161
- if (!response.ok) {
6162
- throw new DidResolverError(`did:web HTTP ${response.status} at ${url}`);
6163
- }
6164
- let raw;
6165
- try {
6166
- raw = await response.json();
6167
- } catch (cause) {
6168
- throw new DidResolverError(`did:web response not valid JSON at ${url}: ${String(cause)}`);
6169
- }
6170
- return mapW3CDocToEngineShape(raw, did);
6171
- }
6172
- function didWebToUrl(did) {
6173
- const path = did.slice("did:web:".length);
6174
- if (!path) {
6175
- throw new MalformedDid(`did:web with empty path: ${did}`);
6176
- }
6177
- const parts = path.split(":").map((segment) => {
6178
- try {
6179
- return decodeURIComponent(segment);
6180
- } catch {
6181
- throw new MalformedDid(`did:web segment contains invalid percent-encoding: ${segment}`);
6182
- }
6183
- });
6184
- if (parts.length === 1) {
6185
- return `https://${parts[0]}/.well-known/did.json`;
6186
- }
6187
- return `https://${parts[0]}/${parts.slice(1).join("/")}/did.json`;
6188
- }
6189
- function mapW3CDocToEngineShape(raw, requestedDid) {
6190
- if (raw === null || typeof raw !== "object") {
6191
- throw new DidResolverError(`did:web response must be a JSON object`);
6192
- }
6193
- const doc = raw;
6194
- const id = typeof doc.id === "string" ? doc.id : requestedDid;
6195
- const w3cMethods = Array.isArray(doc.verificationMethod) ? doc.verificationMethod : [];
6196
- const verificationMethods = [];
6197
- for (const entry of w3cMethods) {
6198
- if (entry === null || typeof entry !== "object") continue;
6199
- const vm = entry;
6200
- if (!isEd25519Type(vm.type)) continue;
6201
- const vmId = typeof vm.id === "string" ? vm.id : void 0;
6202
- if (!vmId) continue;
6203
- const pubKey = extractEd25519PublicKey(vm);
6204
- if (!pubKey) continue;
6205
- verificationMethods.push({
6206
- id: vmId,
6207
- keyType: "Ed25519",
6208
- publicKeyBytes: Array.from(pubKey)
6209
- });
6210
- }
6211
- return { id, verificationMethods };
6212
- }
6213
- function isEd25519Type(type) {
6214
- return type === "Ed25519VerificationKey2020" || type === "Ed25519VerificationKey2018";
6215
- }
6216
- function extractEd25519PublicKey(vm) {
6217
- if (typeof vm.publicKeyMultibase === "string") {
6218
- const mb = vm.publicKeyMultibase;
6219
- if (!mb.startsWith("z")) return null;
6220
- try {
6221
- const decoded = base58btc.decode(mb);
6222
- if (decoded.length === 34 && decoded[0] === ED25519_MULTICODEC_PREFIX[0] && decoded[1] === ED25519_MULTICODEC_PREFIX[1]) {
6223
- return decoded.slice(2);
6224
- }
6225
- if (decoded.length === 32) return decoded;
6226
- } catch {
6227
- return null;
6228
- }
6229
- return null;
6230
- }
6231
- if (vm.publicKeyJwk && typeof vm.publicKeyJwk === "object") {
6232
- const jwk = vm.publicKeyJwk;
6233
- if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519") return null;
6234
- if (typeof jwk.x !== "string") return null;
6235
- let decoded;
6236
- try {
6237
- decoded = base64UrlDecode2(jwk.x);
6238
- } catch {
6239
- return null;
6240
- }
6241
- if (decoded.length !== ED25519_PUBLIC_KEY_LENGTH) {
6242
- return null;
6243
- }
6244
- return decoded;
6245
- }
6246
- return null;
6247
- }
6248
- var StatusListUnavailable = class extends Error {
6249
- kind = "StatusListUnavailable";
6250
- };
6251
- var MalformedStatusList = class extends Error {
6252
- kind = "MalformedStatusList";
6253
- };
6254
- var StatusListTimeout = class extends Error {
6255
- kind = "StatusListTimeout";
6256
- };
6257
- var DEFAULT_FETCH_TIMEOUT_MS2 = 3e3;
6258
- var DEFAULT_TTL_MS2 = 3e4;
6259
- function makeStatusListCache(opts = {}) {
6260
- const timeoutMs = opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS2;
6261
- const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS2;
6262
- const fetchImpl = opts.fetch ?? fetch;
6263
- const cache = opts.cache ?? /* @__PURE__ */ new Map();
6264
- const now = opts.now ?? (() => Date.now());
6265
- return {
6266
- async fetch(url) {
6267
- const cached = cache.get(url);
6268
- if (cached && now() - cached.fetchedAt < ttlMs) {
6269
- return cached.indices;
6270
- }
6271
- const indices = await fetchAndDecode(url, fetchImpl, timeoutMs);
6272
- cache.set(url, { indices, fetchedAt: now() });
6273
- return indices;
6274
- }
6275
- };
6276
- }
6277
- async function fetchAndDecode(url, fetchImpl, timeoutMs) {
6278
- let safeUrl;
6279
- try {
6280
- safeUrl = assertSafeHttpsUrl2(url, "status list URL");
6281
- } catch (cause) {
6282
- if (cause instanceof UnsafeOutboundUrl2) {
6283
- throw new StatusListUnavailable(cause.message);
6284
- }
6285
- throw cause;
6286
- }
6287
- const controller = new AbortController();
6288
- const timer = setTimeout(() => controller.abort(), timeoutMs);
6289
- let response;
6290
- try {
6291
- response = await fetchImpl(safeUrl, { signal: controller.signal });
6292
- } catch (cause) {
6293
- if (cause instanceof Error && cause.name === "AbortError") {
6294
- throw new StatusListTimeout(`status list fetch timed out after ${timeoutMs}ms: ${url}`);
6295
- }
6296
- throw new StatusListUnavailable(`status list fetch failed: ${url}: ${String(cause)}`);
6297
- } finally {
6298
- clearTimeout(timer);
6299
- }
6300
- if (!response.ok) {
6301
- throw new StatusListUnavailable(`status list HTTP ${response.status} at ${url}`);
6302
- }
6303
- let vc;
6304
- try {
6305
- vc = await response.json();
6306
- } catch (cause) {
6307
- throw new MalformedStatusList(
6308
- `status list response not valid JSON at ${url}: ${String(cause)}`
6309
- );
6310
- }
6311
- const encoded = extractEncodedList(vc);
6312
- return enumerateRevokedIndices(encoded);
6313
- }
6314
- function extractEncodedList(vc) {
6315
- if (vc === null || typeof vc !== "object") {
6316
- throw new MalformedStatusList("status list VC must be a JSON object");
6317
- }
6318
- const obj = vc;
6319
- const subject = obj.credentialSubject;
6320
- if (subject === null || typeof subject !== "object") {
6321
- throw new MalformedStatusList("status list VC missing credentialSubject");
6322
- }
6323
- const encoded = subject.encodedList;
6324
- if (typeof encoded !== "string") {
6325
- throw new MalformedStatusList("status list VC missing credentialSubject.encodedList string");
6326
- }
6327
- return encoded;
6328
- }
6329
- function enumerateRevokedIndices(encodedList) {
6330
- let bytes;
6331
- try {
6332
- const compressed = base64UrlDecode2(encodedList);
6333
- bytes = new Uint8Array(gunzipSync(compressed));
6334
- } catch (cause) {
6335
- throw new MalformedStatusList(`status list bitstring decode failed: ${String(cause)}`);
6336
- }
6337
- const indices = [];
6338
- for (let byteIndex = 0; byteIndex < bytes.length; byteIndex += 1) {
6339
- const byte = bytes[byteIndex];
6340
- if (byte === 0) continue;
6341
- for (let bit = 0; bit < 8; bit += 1) {
6342
- const mask = 1 << 7 - bit;
6343
- if ((byte & mask) !== 0) {
6344
- indices.push(byteIndex * 8 + bit);
6345
- }
6346
- }
6347
- }
6348
- return indices;
6349
- }
6350
- var DEFAULT_FETCH_TIMEOUT_MS3 = 1500;
6351
- var DEFAULT_TTL_MS3 = 1e4;
6352
- var DEFAULT_BASELINE = 1;
6353
- function makeReputationOracle(opts = {}) {
6354
- const argusUrl = opts.argusUrl;
6355
- const timeoutMs = opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS3;
6356
- const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS3;
6357
- const fetchImpl = opts.fetch ?? fetch;
6358
- const baseline = opts.baselineWhenUnreachable ?? DEFAULT_BASELINE;
6359
- const cache = opts.cache ?? /* @__PURE__ */ new Map();
6360
- const now = opts.now ?? (() => Date.now());
6361
- const log = opts.logger ?? (() => {
6362
- });
6363
- return {
6364
- async score(agentDid) {
6365
- const cached = cache.get(agentDid);
6366
- if (cached && now() - cached.fetchedAt < ttlMs) {
6367
- return cached.value;
6368
- }
6369
- if (!argusUrl) {
6370
- return baseline;
6371
- }
6372
- const value = await fetchAndValidate(argusUrl, agentDid, fetchImpl, timeoutMs, baseline, log);
6373
- cache.set(agentDid, { value, fetchedAt: now() });
6374
- return value;
6375
- }
6376
- };
6377
- }
6378
- async function fetchAndValidate(argusUrl, agentDid, fetchImpl, timeoutMs, baseline, log) {
6379
- const url = `${argusUrl.replace(/\/$/, "")}/v1/reputation?agent=${encodeURIComponent(agentDid)}`;
6380
- const controller = new AbortController();
6381
- const timer = setTimeout(() => controller.abort(), timeoutMs);
6382
- let response;
6383
- try {
6384
- response = await fetchImpl(url, { signal: controller.signal });
6385
- } catch (cause) {
6386
- if (cause instanceof Error && cause.name === "AbortError") {
6387
- log(
6388
- `[reputation-oracle] Argus timed out after ${timeoutMs}ms (${agentDid}); using baseline ${baseline}`
6389
- );
6390
- } else {
6391
- log(
6392
- `[reputation-oracle] Argus fetch failed (${agentDid}): ${String(cause)}; using baseline ${baseline}`
6393
- );
6394
- }
6395
- return baseline;
6396
- } finally {
6397
- clearTimeout(timer);
6398
- }
6399
- if (!response.ok) {
6400
- log(
6401
- `[reputation-oracle] Argus HTTP ${response.status} (${agentDid}); using baseline ${baseline}`
6402
- );
6403
- return baseline;
6404
- }
6405
- let body;
6406
- try {
6407
- body = await response.json();
6408
- } catch (cause) {
6409
- log(
6410
- `[reputation-oracle] Argus response not JSON (${agentDid}): ${String(cause)}; using baseline ${baseline}`
6411
- );
6412
- return baseline;
6413
- }
6414
- if (body === null || typeof body !== "object") {
6415
- log(
6416
- `[reputation-oracle] Argus response not an object (${agentDid}); using baseline ${baseline}`
6417
- );
6418
- return baseline;
6419
- }
6420
- const score = body.score;
6421
- if (typeof score !== "number" || !Number.isFinite(score)) {
6422
- log(
6423
- `[reputation-oracle] Argus score not a finite number (${agentDid}): ${String(score)}; using baseline ${baseline}`
6424
- );
6425
- return baseline;
6426
- }
6427
- if (score < 0 || score > 1) {
6428
- log(
6429
- `[reputation-oracle] Argus score out of range (${agentDid}): ${score}; using baseline ${baseline}`
6430
- );
6431
- return baseline;
6432
- }
6433
- return score;
6434
- }
6435
- var DEFAULT_FETCH_TIMEOUT_MS4 = 2e3;
6436
- var DEFAULT_TTL_MS4 = 6e4;
6437
- var PERMIT_BY_DEFAULT_POLICY = { reputationThreshold: 0 };
6438
- function makePolicyEvaluator(opts = {}) {
6439
- const dashboardUrl = opts.dashboardUrl;
6440
- const timeoutMs = opts.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS4;
6441
- const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS4;
6442
- const fetchImpl = opts.fetch ?? fetch;
6443
- const fallbackPolicy = opts.defaultPolicy ?? PERMIT_BY_DEFAULT_POLICY;
6444
- const cache = opts.cache ?? /* @__PURE__ */ new Map();
6445
- const now = opts.now ?? (() => Date.now());
6446
- const log = opts.logger ?? (() => {
6447
- });
6448
- return {
6449
- async evaluate(input) {
6450
- const policy = await getOrFetchPolicy(
6451
- input.tenantHost,
6452
- dashboardUrl,
6453
- fetchImpl,
6454
- timeoutMs,
6455
- fallbackPolicy,
6456
- cache,
6457
- ttlMs,
6458
- now,
6459
- log
6460
- );
6461
- return computeDecision(policy, input);
6462
- }
6463
- };
6464
- }
6465
- function computeDecision(policy, input) {
6466
- if (input.reputation < policy.reputationThreshold) {
6467
- return {
6468
- kind: "Block",
6469
- reason: {
6470
- kind: "LowReputation",
6471
- score: input.reputation,
6472
- threshold: policy.reputationThreshold
6473
- }
6474
- };
6475
- }
6476
- return { kind: "Permit" };
6477
- }
6478
- async function getOrFetchPolicy(tenantHost, dashboardUrl, fetchImpl, timeoutMs, fallbackPolicy, cache, ttlMs, now, log) {
6479
- const cached = cache.get(tenantHost);
6480
- if (cached && now() - cached.fetchedAt < ttlMs) {
6481
- return cached.policy;
6482
- }
6483
- const cacheFallback = () => {
6484
- cache.set(tenantHost, { policy: fallbackPolicy, fetchedAt: now() });
6485
- return fallbackPolicy;
6486
- };
6487
- if (!dashboardUrl) {
6488
- return cacheFallback();
6489
- }
6490
- const url = `${dashboardUrl.replace(/\/$/, "")}/api/policy?tenant=${encodeURIComponent(tenantHost)}`;
6491
- const controller = new AbortController();
6492
- const timer = setTimeout(() => controller.abort(), timeoutMs);
6493
- let response;
6494
- try {
6495
- response = await fetchImpl(url, { signal: controller.signal });
6496
- } catch (cause) {
6497
- log(`[policy-evaluator] fetch failed (${tenantHost}): ${String(cause)}; using fallback`);
6498
- return cacheFallback();
6499
- } finally {
6500
- clearTimeout(timer);
6501
- }
6502
- if (!response.ok) {
6503
- log(`[policy-evaluator] dashboard HTTP ${response.status} (${tenantHost}); using fallback`);
6504
- return cacheFallback();
6505
- }
6506
- let body;
6507
- try {
6508
- body = await response.json();
6509
- } catch (cause) {
6510
- log(
6511
- `[policy-evaluator] dashboard response not JSON (${tenantHost}): ${String(cause)}; using fallback`
6512
- );
6513
- return cacheFallback();
6514
- }
6515
- const parsed = parseTenantPolicy(body);
6516
- if (!parsed) {
6517
- log(`[policy-evaluator] dashboard response malformed (${tenantHost}); using fallback`);
6518
- return cacheFallback();
6519
- }
6520
- cache.set(tenantHost, { policy: parsed, fetchedAt: now() });
6521
- return parsed;
6522
- }
6523
- function parseTenantPolicy(raw) {
6524
- if (raw === null || typeof raw !== "object") return null;
6525
- const threshold = raw.reputationThreshold;
6526
- if (typeof threshold !== "number" || !Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
6527
- return null;
6528
- }
6529
- return { reputationThreshold: threshold };
6530
- }
6531
- function makeSystemClock() {
6532
- return { nowUnix: () => Math.floor(Date.now() / 1e3) };
6533
- }
6534
5195
  function adaptToExpressResponse(rendered, req, res, next) {
6535
5196
  const clientAcceptsHtml = acceptsHtml(req.headers);
6536
5197
  const verdictCookie = encodeVerdictCookie(rendered);