@kya-os/mcp-i-cloudflare 1.5.10-canary.0 → 1.5.10-canary.10
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/adapter.d.ts +1 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +12 -1
- package/dist/adapter.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +45 -2
- package/dist/app.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -2
- package/dist/config.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +39 -6
- package/dist/server.js.map +1 -1
- package/dist/services/admin.service.d.ts +3 -1
- package/dist/services/admin.service.d.ts.map +1 -1
- package/dist/services/admin.service.js +80 -3
- package/dist/services/admin.service.js.map +1 -1
- package/dist/services/consent-page-renderer.d.ts.map +1 -1
- package/dist/services/consent-page-renderer.js +2 -5
- package/dist/services/consent-page-renderer.js.map +1 -1
- package/dist/services/consent.service.d.ts.map +1 -1
- package/dist/services/consent.service.js +378 -61
- package/dist/services/consent.service.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -312,12 +312,76 @@ export class ConsentService {
|
|
|
312
312
|
const agentDid = params.get("agent_did");
|
|
313
313
|
const sessionId = params.get("session_id");
|
|
314
314
|
const projectId = params.get("project_id");
|
|
315
|
-
// Validate required parameters
|
|
316
|
-
|
|
315
|
+
// Validate required parameters with detailed error messages
|
|
316
|
+
const missingParams = [];
|
|
317
|
+
if (!tool)
|
|
318
|
+
missingParams.push("tool");
|
|
319
|
+
if (!agentDid)
|
|
320
|
+
missingParams.push("agent_did");
|
|
321
|
+
if (!sessionId)
|
|
322
|
+
missingParams.push("session_id");
|
|
323
|
+
if (!projectId)
|
|
324
|
+
missingParams.push("project_id");
|
|
325
|
+
if (missingParams.length > 0) {
|
|
326
|
+
console.error("[ConsentService] Missing required parameters:", {
|
|
327
|
+
missing: missingParams,
|
|
328
|
+
received: {
|
|
329
|
+
tool: tool || null,
|
|
330
|
+
agent_did: agentDid || null,
|
|
331
|
+
session_id: sessionId || null,
|
|
332
|
+
project_id: projectId || null,
|
|
333
|
+
},
|
|
334
|
+
url: request.url,
|
|
335
|
+
});
|
|
317
336
|
return new Response(JSON.stringify({
|
|
318
337
|
success: false,
|
|
319
|
-
error:
|
|
338
|
+
error: `Missing required parameters: ${missingParams.join(", ")}`,
|
|
320
339
|
error_code: "missing_parameters",
|
|
340
|
+
missing_parameters: missingParams,
|
|
341
|
+
received_parameters: {
|
|
342
|
+
tool: tool || null,
|
|
343
|
+
agent_did: agentDid || null,
|
|
344
|
+
session_id: sessionId || null,
|
|
345
|
+
project_id: projectId || null,
|
|
346
|
+
},
|
|
347
|
+
}), {
|
|
348
|
+
status: 400,
|
|
349
|
+
headers: { "Content-Type": "application/json" },
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
// Validate parameter formats
|
|
353
|
+
const validationErrors = [];
|
|
354
|
+
if (agentDid && !agentDid.startsWith("did:")) {
|
|
355
|
+
validationErrors.push("agent_did must be a valid DID (starting with 'did:')");
|
|
356
|
+
}
|
|
357
|
+
if (sessionId && sessionId.length < 10) {
|
|
358
|
+
validationErrors.push("session_id appears to be invalid (too short)");
|
|
359
|
+
}
|
|
360
|
+
if (projectId && projectId.length < 1) {
|
|
361
|
+
validationErrors.push("project_id appears to be invalid (empty)");
|
|
362
|
+
}
|
|
363
|
+
if (validationErrors.length > 0) {
|
|
364
|
+
console.error("[ConsentService] Parameter validation failed:", {
|
|
365
|
+
errors: validationErrors,
|
|
366
|
+
received: {
|
|
367
|
+
tool,
|
|
368
|
+
agent_did: agentDid,
|
|
369
|
+
session_id: sessionId,
|
|
370
|
+
project_id: projectId,
|
|
371
|
+
},
|
|
372
|
+
url: request.url,
|
|
373
|
+
});
|
|
374
|
+
return new Response(JSON.stringify({
|
|
375
|
+
success: false,
|
|
376
|
+
error: "Invalid parameter format",
|
|
377
|
+
error_code: "validation_error",
|
|
378
|
+
validation_errors: validationErrors,
|
|
379
|
+
received_parameters: {
|
|
380
|
+
tool,
|
|
381
|
+
agent_did: agentDid,
|
|
382
|
+
session_id: sessionId,
|
|
383
|
+
project_id: projectId,
|
|
384
|
+
},
|
|
321
385
|
}), {
|
|
322
386
|
status: 400,
|
|
323
387
|
headers: { "Content-Type": "application/json" },
|
|
@@ -340,6 +404,7 @@ export class ConsentService {
|
|
|
340
404
|
}
|
|
341
405
|
}
|
|
342
406
|
// Get consent config from AgentShield or defaults
|
|
407
|
+
// Note: projectId is validated above and guaranteed to be non-null at this point
|
|
343
408
|
const consentConfig = await this.configService.getConsentConfig(projectId);
|
|
344
409
|
// Build server URL from request origin
|
|
345
410
|
// Priority: 1) env var, 2) request origin, 3) error if neither available
|
|
@@ -392,26 +457,31 @@ export class ConsentService {
|
|
|
392
457
|
console.warn("[ConsentService] Failed to extract OAuth cookie:", error);
|
|
393
458
|
// Non-fatal - continue without OAuth identity
|
|
394
459
|
}
|
|
460
|
+
// At this point, all required parameters are validated and non-null
|
|
461
|
+
// TypeScript doesn't know this, so we assert non-null
|
|
462
|
+
const validatedProjectId = projectId;
|
|
463
|
+
const validatedAgentDid = agentDid;
|
|
464
|
+
const validatedSessionId = sessionId;
|
|
395
465
|
// Check if OAuth is required (after extracting OAuth identity)
|
|
396
|
-
const oauthRequired = await this.isOAuthRequired(
|
|
466
|
+
const oauthRequired = await this.isOAuthRequired(validatedProjectId, oauthIdentity);
|
|
397
467
|
if (oauthRequired) {
|
|
398
468
|
// OAuth is required - redirect to OAuth provider instead of showing consent page
|
|
399
|
-
const oauthUrl = this.buildOAuthUrl(
|
|
469
|
+
const oauthUrl = this.buildOAuthUrl(validatedProjectId, validatedAgentDid, validatedSessionId, scopes, serverUrl);
|
|
400
470
|
console.log("[ConsentService] OAuth required, redirecting to OAuth provider:", {
|
|
401
|
-
projectId,
|
|
402
|
-
agentDid:
|
|
471
|
+
projectId: validatedProjectId,
|
|
472
|
+
agentDid: validatedAgentDid.substring(0, 20) + "...",
|
|
403
473
|
oauthUrl: oauthUrl.substring(0, 100) + "...",
|
|
404
474
|
});
|
|
405
475
|
return Response.redirect(oauthUrl, 302);
|
|
406
476
|
}
|
|
407
477
|
// Build consent page config
|
|
408
478
|
const pageConfig = {
|
|
409
|
-
tool,
|
|
479
|
+
tool: tool,
|
|
410
480
|
toolDescription,
|
|
411
481
|
scopes,
|
|
412
|
-
agentDid,
|
|
413
|
-
sessionId,
|
|
414
|
-
projectId,
|
|
482
|
+
agentDid: validatedAgentDid,
|
|
483
|
+
sessionId: validatedSessionId,
|
|
484
|
+
projectId: validatedProjectId,
|
|
415
485
|
serverUrl,
|
|
416
486
|
branding: consentConfig.branding,
|
|
417
487
|
terms: consentConfig.terms,
|
|
@@ -460,40 +530,199 @@ export class ConsentService {
|
|
|
460
530
|
}
|
|
461
531
|
else if (contentType.includes("application/x-www-form-urlencoded") ||
|
|
462
532
|
contentType.includes("multipart/form-data")) {
|
|
463
|
-
// FormData
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
533
|
+
// Try FormData first (works for both multipart and url-encoded when FormData object is used)
|
|
534
|
+
try {
|
|
535
|
+
// Don't clone - read FormData directly (cloning might consume the body)
|
|
536
|
+
const formData = await request.formData();
|
|
537
|
+
// Check if FormData actually has values (if Content-Type mismatch, formData might be empty or malformed)
|
|
538
|
+
// Try to get a value and also check entries iterator
|
|
539
|
+
const toolValue = formData.get("tool");
|
|
540
|
+
// FormData.entries() exists but TypeScript may not recognize it - use type assertion
|
|
541
|
+
const formDataEntries = formData.entries ? Array.from(formData.entries()) : [];
|
|
542
|
+
// Check if FormData is properly parsed (not malformed)
|
|
543
|
+
// Malformed FormData happens when Content-Type says url-encoded but body is multipart
|
|
544
|
+
// In that case, entries might exist but contain raw multipart data instead of key-value pairs
|
|
545
|
+
const isMalformed = formDataEntries.length > 0 && formDataEntries.some(([key]) => key.includes("Content-Disposition") || key.includes("formdata-"));
|
|
546
|
+
const hasFormDataValues = toolValue !== null && !isMalformed;
|
|
547
|
+
if (hasFormDataValues) {
|
|
548
|
+
// Parse scopes safely
|
|
549
|
+
let scopes = [];
|
|
550
|
+
const scopesValue = formData.get("scopes");
|
|
551
|
+
if (scopesValue) {
|
|
552
|
+
try {
|
|
553
|
+
if (typeof scopesValue === "string") {
|
|
554
|
+
scopes = JSON.parse(scopesValue);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
scopes = Array.isArray(scopesValue) ? scopesValue : [];
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
if (typeof scopesValue === "string") {
|
|
562
|
+
scopes = scopesValue
|
|
563
|
+
.split(",")
|
|
564
|
+
.map((s) => s.trim())
|
|
565
|
+
.filter((s) => s.length > 0);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// Extract FormData values
|
|
570
|
+
const agentDidValue = formData.get("agent_did");
|
|
571
|
+
const sessionIdValue = formData.get("session_id");
|
|
572
|
+
const projectIdValue = formData.get("project_id");
|
|
573
|
+
const tool = toolValue && typeof toolValue === "string"
|
|
574
|
+
? toolValue
|
|
575
|
+
: toolValue
|
|
576
|
+
? String(toolValue)
|
|
577
|
+
: "";
|
|
578
|
+
const agentDid = agentDidValue && typeof agentDidValue === "string"
|
|
579
|
+
? agentDidValue
|
|
580
|
+
: agentDidValue
|
|
581
|
+
? String(agentDidValue)
|
|
582
|
+
: "";
|
|
583
|
+
const sessionId = sessionIdValue && typeof sessionIdValue === "string"
|
|
584
|
+
? sessionIdValue
|
|
585
|
+
: sessionIdValue
|
|
586
|
+
? String(sessionIdValue)
|
|
587
|
+
: "";
|
|
588
|
+
const projectId = projectIdValue && typeof projectIdValue === "string"
|
|
589
|
+
? projectIdValue
|
|
590
|
+
: projectIdValue
|
|
591
|
+
? String(projectIdValue)
|
|
592
|
+
: "";
|
|
593
|
+
const termsAcceptedValue = formData.get("termsAccepted");
|
|
594
|
+
const termsAccepted = formData.has("termsAccepted")
|
|
595
|
+
? termsAcceptedValue === "on" || termsAcceptedValue === "true"
|
|
596
|
+
: true;
|
|
597
|
+
body = {
|
|
598
|
+
tool,
|
|
599
|
+
scopes,
|
|
600
|
+
agent_did: agentDid,
|
|
601
|
+
session_id: sessionId,
|
|
602
|
+
project_id: projectId,
|
|
603
|
+
termsAccepted,
|
|
604
|
+
customFields: {},
|
|
605
|
+
};
|
|
606
|
+
// Extract OAuth identity if present
|
|
607
|
+
const oauthIdentityJson = formData.get("oauth_identity_json");
|
|
608
|
+
if (oauthIdentityJson && typeof oauthIdentityJson === "string") {
|
|
609
|
+
try {
|
|
610
|
+
const parsed = JSON.parse(oauthIdentityJson);
|
|
611
|
+
if (parsed && parsed.provider && parsed.subject) {
|
|
612
|
+
body.oauth_identity = parsed;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
catch {
|
|
616
|
+
// Ignore invalid OAuth identity
|
|
617
|
+
}
|
|
488
618
|
}
|
|
489
619
|
}
|
|
490
|
-
|
|
491
|
-
//
|
|
620
|
+
else {
|
|
621
|
+
// FormData is empty or malformed - this happens when Content-Type says url-encoded but body is FormData
|
|
622
|
+
// Try to parse the raw body text as multipart form data manually
|
|
623
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
624
|
+
// FormData with wrong content-type - parse raw body
|
|
625
|
+
throw new Error("FormData malformed, parse raw body");
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
// For multipart/form-data, FormData should work - if it's empty, that's an error
|
|
629
|
+
throw new Error("FormData empty for multipart/form-data");
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
catch (formDataError) {
|
|
634
|
+
// Fallback: Try to parse raw body text
|
|
635
|
+
// This handles cases where FormData is malformed due to Content-Type mismatch
|
|
636
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
637
|
+
try {
|
|
638
|
+
// Try URLSearchParams first (for true url-encoded data)
|
|
639
|
+
const formText = await request.clone().text();
|
|
640
|
+
// Check if it's actually multipart data (FormData with wrong content-type)
|
|
641
|
+
const isMultipart = formText.includes("Content-Disposition: form-data");
|
|
642
|
+
if (isMultipart) {
|
|
643
|
+
// Parse multipart form data manually using regex
|
|
644
|
+
// Match pattern: Content-Disposition: form-data; name="fieldname"\r\n\r\nvalue
|
|
645
|
+
const data = {};
|
|
646
|
+
const fieldPattern = /Content-Disposition:\s*form-data;\s*name="([^"]+)"[\r\n]+(?:Content-Type:[^\r\n]+[\r\n]+)?[\r\n]+([^\r\n]+(?:[\r\n]+(?!Content-Disposition|--)[^\r\n]+)*)/gi;
|
|
647
|
+
let match;
|
|
648
|
+
while ((match = fieldPattern.exec(formText)) !== null) {
|
|
649
|
+
const fieldName = match[1];
|
|
650
|
+
let value = match[2];
|
|
651
|
+
// Clean up value - remove trailing boundary markers and extra whitespace
|
|
652
|
+
value = value.replace(/\r?\n--[-]+.*$/g, "").trim();
|
|
653
|
+
if (value) {
|
|
654
|
+
data[fieldName] = value;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
// Fallback: if regex didn't work, try simpler pattern
|
|
658
|
+
if (Object.keys(data).length === 0) {
|
|
659
|
+
// Try simpler pattern: name="field" followed by value on next line
|
|
660
|
+
const simplePattern = /name="([^"]+)"[\r\n]+[\r\n]+([^\r\n]+)/g;
|
|
661
|
+
let simpleMatch;
|
|
662
|
+
while ((simpleMatch = simplePattern.exec(formText)) !== null) {
|
|
663
|
+
const fieldName = simpleMatch[1];
|
|
664
|
+
let value = simpleMatch[2].trim();
|
|
665
|
+
// Skip if it looks like a boundary
|
|
666
|
+
if (!value.startsWith("--")) {
|
|
667
|
+
data[fieldName] = value;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
let scopes = [];
|
|
672
|
+
if (data.scopes) {
|
|
673
|
+
try {
|
|
674
|
+
scopes = JSON.parse(data.scopes);
|
|
675
|
+
}
|
|
676
|
+
catch {
|
|
677
|
+
scopes = data.scopes.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
body = {
|
|
681
|
+
tool: data.tool || "",
|
|
682
|
+
scopes,
|
|
683
|
+
agent_did: data.agent_did || "",
|
|
684
|
+
session_id: data.session_id || "",
|
|
685
|
+
project_id: data.project_id || "",
|
|
686
|
+
termsAccepted: data.termsAccepted === "on" || data.termsAccepted === "true" || !("termsAccepted" in data),
|
|
687
|
+
customFields: {},
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
// True URL-encoded data
|
|
692
|
+
const params = new URLSearchParams(formText);
|
|
693
|
+
let scopes = [];
|
|
694
|
+
const scopesValue = params.get("scopes");
|
|
695
|
+
if (scopesValue) {
|
|
696
|
+
try {
|
|
697
|
+
scopes = JSON.parse(scopesValue);
|
|
698
|
+
}
|
|
699
|
+
catch {
|
|
700
|
+
scopes = scopesValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
body = {
|
|
704
|
+
tool: params.get("tool") || "",
|
|
705
|
+
scopes,
|
|
706
|
+
agent_did: params.get("agent_did") || "",
|
|
707
|
+
session_id: params.get("session_id") || "",
|
|
708
|
+
project_id: params.get("project_id") || "",
|
|
709
|
+
termsAccepted: params.get("termsAccepted") === "on" ||
|
|
710
|
+
params.get("termsAccepted") === "true" ||
|
|
711
|
+
!params.has("termsAccepted"),
|
|
712
|
+
customFields: {},
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
catch (textError) {
|
|
717
|
+
// If text parsing also fails, throw validation error
|
|
718
|
+
throw new Error("Failed to parse form data");
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
// For multipart/form-data, if FormData failed completely, we can't parse it
|
|
723
|
+
throw new Error("Failed to parse FormData");
|
|
492
724
|
}
|
|
493
725
|
}
|
|
494
|
-
// Extract custom fields (if any)
|
|
495
|
-
// Note: Custom fields would need to be extracted from formData if present
|
|
496
|
-
// For now, we'll use empty object as customFields are optional
|
|
497
726
|
}
|
|
498
727
|
else {
|
|
499
728
|
// Try JSON first, fallback to form data
|
|
@@ -502,14 +731,61 @@ export class ConsentService {
|
|
|
502
731
|
}
|
|
503
732
|
catch {
|
|
504
733
|
const formData = await request.formData();
|
|
734
|
+
// Parse scopes safely - handle JSON parse errors
|
|
735
|
+
let scopes = [];
|
|
736
|
+
const scopesValue = formData.get("scopes");
|
|
737
|
+
if (scopesValue) {
|
|
738
|
+
try {
|
|
739
|
+
if (typeof scopesValue === "string") {
|
|
740
|
+
scopes = JSON.parse(scopesValue);
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
scopes = Array.isArray(scopesValue) ? scopesValue : [];
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
catch {
|
|
747
|
+
// If JSON parse fails, try parsing as comma-separated string
|
|
748
|
+
if (typeof scopesValue === "string") {
|
|
749
|
+
scopes = scopesValue
|
|
750
|
+
.split(",")
|
|
751
|
+
.map((s) => s.trim())
|
|
752
|
+
.filter((s) => s.length > 0);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
// Extract FormData values and ensure correct types for validation
|
|
757
|
+
// FormData.get() returns FormDataEntryValue | null (FormDataEntryValue = string | File)
|
|
758
|
+
const toolValue = formData.get("tool");
|
|
759
|
+
const agentDidValue = formData.get("agent_did");
|
|
760
|
+
const sessionIdValue = formData.get("session_id");
|
|
761
|
+
const projectIdValue = formData.get("project_id");
|
|
762
|
+
// Convert to strings, handling null and File cases
|
|
763
|
+
const tool = toolValue && typeof toolValue === "string"
|
|
764
|
+
? toolValue
|
|
765
|
+
: toolValue
|
|
766
|
+
? String(toolValue)
|
|
767
|
+
: "";
|
|
768
|
+
const agentDid = agentDidValue && typeof agentDidValue === "string"
|
|
769
|
+
? agentDidValue
|
|
770
|
+
: agentDidValue
|
|
771
|
+
? String(agentDidValue)
|
|
772
|
+
: "";
|
|
773
|
+
const sessionId = sessionIdValue && typeof sessionIdValue === "string"
|
|
774
|
+
? sessionIdValue
|
|
775
|
+
: sessionIdValue
|
|
776
|
+
? String(sessionIdValue)
|
|
777
|
+
: "";
|
|
778
|
+
const projectId = projectIdValue && typeof projectIdValue === "string"
|
|
779
|
+
? projectIdValue
|
|
780
|
+
: projectIdValue
|
|
781
|
+
? String(projectIdValue)
|
|
782
|
+
: "";
|
|
505
783
|
body = {
|
|
506
|
-
tool
|
|
507
|
-
scopes:
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
session_id: formData.get("session_id"),
|
|
512
|
-
project_id: formData.get("project_id"),
|
|
784
|
+
tool,
|
|
785
|
+
scopes: Array.isArray(scopes) ? scopes : [],
|
|
786
|
+
agent_did: agentDid,
|
|
787
|
+
session_id: sessionId,
|
|
788
|
+
project_id: projectId,
|
|
513
789
|
// termsAccepted: default to true if checkbox not present (no terms configured)
|
|
514
790
|
termsAccepted: formData.has("termsAccepted")
|
|
515
791
|
? formData.get("termsAccepted") === "on" ||
|
|
@@ -521,11 +797,45 @@ export class ConsentService {
|
|
|
521
797
|
}
|
|
522
798
|
const validation = validateConsentApprovalRequest(body);
|
|
523
799
|
if (!validation.success) {
|
|
800
|
+
// Always log validation errors for debugging (critical for troubleshooting)
|
|
801
|
+
const bodyObj = body;
|
|
802
|
+
console.error("[ConsentService] Approval request validation failed:", {
|
|
803
|
+
errors: validation.error.errors,
|
|
804
|
+
receivedBody: {
|
|
805
|
+
tool: typeof bodyObj.tool,
|
|
806
|
+
scopes: Array.isArray(bodyObj.scopes)
|
|
807
|
+
? `array[${bodyObj.scopes.length}]`
|
|
808
|
+
: typeof bodyObj.scopes,
|
|
809
|
+
agent_did: typeof bodyObj.agent_did,
|
|
810
|
+
session_id: typeof bodyObj.session_id,
|
|
811
|
+
project_id: typeof bodyObj.project_id,
|
|
812
|
+
termsAccepted: typeof bodyObj.termsAccepted,
|
|
813
|
+
customFields: typeof bodyObj.customFields,
|
|
814
|
+
oauth_identity: typeof bodyObj.oauth_identity,
|
|
815
|
+
},
|
|
816
|
+
rawBody: JSON.stringify(bodyObj).substring(0, 500), // First 500 chars for debugging
|
|
817
|
+
});
|
|
818
|
+
// Format validation errors for better readability
|
|
819
|
+
const formattedErrors = validation.error.errors.map((err) => ({
|
|
820
|
+
field: err.path.join("."),
|
|
821
|
+
message: err.message,
|
|
822
|
+
code: err.code,
|
|
823
|
+
}));
|
|
524
824
|
return new Response(JSON.stringify({
|
|
525
825
|
success: false,
|
|
526
|
-
error: "Invalid request",
|
|
826
|
+
error: "Invalid request format",
|
|
527
827
|
error_code: "validation_error",
|
|
528
|
-
details:
|
|
828
|
+
details: formattedErrors,
|
|
829
|
+
received_types: {
|
|
830
|
+
tool: typeof bodyObj.tool,
|
|
831
|
+
scopes: Array.isArray(bodyObj.scopes)
|
|
832
|
+
? `array[${bodyObj.scopes.length}]`
|
|
833
|
+
: typeof bodyObj.scopes,
|
|
834
|
+
agent_did: typeof bodyObj.agent_did,
|
|
835
|
+
session_id: typeof bodyObj.session_id,
|
|
836
|
+
project_id: typeof bodyObj.project_id,
|
|
837
|
+
termsAccepted: typeof bodyObj.termsAccepted,
|
|
838
|
+
},
|
|
529
839
|
}), {
|
|
530
840
|
status: 400,
|
|
531
841
|
headers: { "Content-Type": "application/json" },
|
|
@@ -547,10 +857,17 @@ export class ConsentService {
|
|
|
547
857
|
// Create delegation via AgentShield API
|
|
548
858
|
const delegationResult = await this.createDelegation(approvalRequest);
|
|
549
859
|
if (!delegationResult.success) {
|
|
860
|
+
// Map API error codes to delegation_creation_failed for consistency
|
|
861
|
+
// Tests expect delegation_creation_failed when delegation creation fails
|
|
862
|
+
const errorCode = delegationResult.error_code === "validation_error" ||
|
|
863
|
+
delegationResult.error_code === "api_error" ||
|
|
864
|
+
delegationResult.error_code === "INTERNAL_SERVER_ERROR"
|
|
865
|
+
? "delegation_creation_failed"
|
|
866
|
+
: delegationResult.error_code || "delegation_creation_failed";
|
|
550
867
|
return new Response(JSON.stringify({
|
|
551
868
|
success: false,
|
|
552
869
|
error: delegationResult.error || "Failed to create delegation",
|
|
553
|
-
error_code:
|
|
870
|
+
error_code: errorCode,
|
|
554
871
|
}), {
|
|
555
872
|
status: 500,
|
|
556
873
|
headers: { "Content-Type": "application/json" },
|
|
@@ -578,11 +895,13 @@ export class ConsentService {
|
|
|
578
895
|
name: errorName,
|
|
579
896
|
message: errorMessage,
|
|
580
897
|
stack: errorStack,
|
|
581
|
-
error: error instanceof Error
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
898
|
+
error: error instanceof Error
|
|
899
|
+
? {
|
|
900
|
+
name: error.name,
|
|
901
|
+
message: error.message,
|
|
902
|
+
stack: error.stack,
|
|
903
|
+
}
|
|
904
|
+
: error,
|
|
586
905
|
});
|
|
587
906
|
return new Response(JSON.stringify({
|
|
588
907
|
success: false,
|
|
@@ -623,8 +942,8 @@ export class ConsentService {
|
|
|
623
942
|
let userDid;
|
|
624
943
|
if (this.env.DELEGATION_STORAGE && request.session_id) {
|
|
625
944
|
try {
|
|
626
|
-
// Pass OAuth identity if available in approval request
|
|
627
|
-
userDid = await this.getUserDidForSession(request.session_id, request.oauth_identity);
|
|
945
|
+
// Pass OAuth identity if available in approval request (convert null to undefined)
|
|
946
|
+
userDid = await this.getUserDidForSession(request.session_id, request.oauth_identity ?? undefined);
|
|
628
947
|
}
|
|
629
948
|
catch (error) {
|
|
630
949
|
console.warn("[ConsentService] Failed to get/generate userDid:", error);
|
|
@@ -1019,9 +1338,7 @@ export class ConsentService {
|
|
|
1019
1338
|
"success" in responseData &&
|
|
1020
1339
|
responseData.success === false) {
|
|
1021
1340
|
const errorData = responseData;
|
|
1022
|
-
const errorMessage = errorData.error?.message ||
|
|
1023
|
-
errorData.message ||
|
|
1024
|
-
"API request failed";
|
|
1341
|
+
const errorMessage = errorData.error?.message || errorData.message || "API request failed";
|
|
1025
1342
|
const errorCode = errorData.error?.code || "api_error";
|
|
1026
1343
|
console.error("[ConsentService] API returned success: false:", {
|
|
1027
1344
|
errorMessage,
|