@kya-os/consent 0.1.13 → 0.1.15

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.
Files changed (131) hide show
  1. package/dist/bundle/inline.d.ts.map +1 -1
  2. package/dist/bundle/inline.js +2 -2
  3. package/dist/bundle/inline.js.map +1 -1
  4. package/dist/bundle/shell.d.ts +5 -0
  5. package/dist/bundle/shell.d.ts.map +1 -1
  6. package/dist/bundle/shell.js +3 -1
  7. package/dist/bundle/shell.js.map +1 -1
  8. package/dist/cjs/bundle/index.js +57 -0
  9. package/dist/cjs/bundle/index.js.map +1 -0
  10. package/dist/cjs/bundle/inline.js +22 -0
  11. package/dist/cjs/bundle/inline.js.map +1 -0
  12. package/dist/cjs/bundle/shell.js +291 -0
  13. package/dist/cjs/bundle/shell.js.map +1 -0
  14. package/dist/cjs/components/consent-button.js +180 -0
  15. package/dist/cjs/components/consent-button.js.map +1 -0
  16. package/dist/cjs/components/consent-checkbox.js +223 -0
  17. package/dist/cjs/components/consent-checkbox.js.map +1 -0
  18. package/dist/cjs/components/consent-input.js +335 -0
  19. package/dist/cjs/components/consent-input.js.map +1 -0
  20. package/dist/cjs/components/consent-oauth-button.js +392 -0
  21. package/dist/cjs/components/consent-oauth-button.js.map +1 -0
  22. package/dist/cjs/components/consent-otp-input.js +388 -0
  23. package/dist/cjs/components/consent-otp-input.js.map +1 -0
  24. package/dist/cjs/components/consent-permissions.js +433 -0
  25. package/dist/cjs/components/consent-permissions.js.map +1 -0
  26. package/dist/cjs/components/consent-shell.js +234 -0
  27. package/dist/cjs/components/consent-shell.js.map +1 -0
  28. package/dist/cjs/components/consent-terms.js +287 -0
  29. package/dist/cjs/components/consent-terms.js.map +1 -0
  30. package/dist/cjs/components/index.js +37 -0
  31. package/dist/cjs/components/index.js.map +1 -0
  32. package/dist/cjs/components/mcp-consent.js +1034 -0
  33. package/dist/cjs/components/mcp-consent.js.map +1 -0
  34. package/dist/cjs/constants/auth-modes.js +128 -0
  35. package/dist/cjs/constants/auth-modes.js.map +1 -0
  36. package/dist/cjs/constants/colors.js +40 -0
  37. package/dist/cjs/constants/colors.js.map +1 -0
  38. package/dist/cjs/constants/defaults.js +146 -0
  39. package/dist/cjs/constants/defaults.js.map +1 -0
  40. package/dist/cjs/constants/index.js +40 -0
  41. package/dist/cjs/constants/index.js.map +1 -0
  42. package/dist/cjs/index.js +49 -0
  43. package/dist/cjs/index.js.map +1 -0
  44. package/dist/cjs/package.json +1 -0
  45. package/dist/cjs/react/index.js +190 -0
  46. package/dist/cjs/react/index.js.map +1 -0
  47. package/dist/cjs/resolution/index.js +28 -0
  48. package/dist/cjs/resolution/index.js.map +1 -0
  49. package/dist/cjs/resolution/resolve-branding.js +159 -0
  50. package/dist/cjs/resolution/resolve-branding.js.map +1 -0
  51. package/dist/cjs/resolution/resolve-config.js +270 -0
  52. package/dist/cjs/resolution/resolve-config.js.map +1 -0
  53. package/dist/cjs/resolution/resolve-copy.js +136 -0
  54. package/dist/cjs/resolution/resolve-copy.js.map +1 -0
  55. package/dist/cjs/schemas/api.schemas.js +162 -0
  56. package/dist/cjs/schemas/api.schemas.js.map +1 -0
  57. package/dist/cjs/schemas/branding.schemas.js +57 -0
  58. package/dist/cjs/schemas/branding.schemas.js.map +1 -0
  59. package/dist/cjs/schemas/config.schemas.js +147 -0
  60. package/dist/cjs/schemas/config.schemas.js.map +1 -0
  61. package/dist/cjs/schemas/index.js +29 -0
  62. package/dist/cjs/schemas/index.js.map +1 -0
  63. package/dist/cjs/schemas/modes.schemas.js +107 -0
  64. package/dist/cjs/schemas/modes.schemas.js.map +1 -0
  65. package/dist/cjs/security/escape.js +206 -0
  66. package/dist/cjs/security/escape.js.map +1 -0
  67. package/dist/cjs/security/index.js +26 -0
  68. package/dist/cjs/security/index.js.map +1 -0
  69. package/dist/cjs/security/validators.js +210 -0
  70. package/dist/cjs/security/validators.js.map +1 -0
  71. package/dist/cjs/styles/css-variables.js +129 -0
  72. package/dist/cjs/styles/css-variables.js.map +1 -0
  73. package/dist/cjs/styles/index.js +28 -0
  74. package/dist/cjs/styles/index.js.map +1 -0
  75. package/dist/cjs/styles/stylesheet.js +204 -0
  76. package/dist/cjs/styles/stylesheet.js.map +1 -0
  77. package/dist/cjs/styles/tokens.js +183 -0
  78. package/dist/cjs/styles/tokens.js.map +1 -0
  79. package/dist/cjs/templates/base/base-template.js +282 -0
  80. package/dist/cjs/templates/base/base-template.js.map +1 -0
  81. package/dist/cjs/templates/base/components.js +295 -0
  82. package/dist/cjs/templates/base/components.js.map +1 -0
  83. package/dist/cjs/templates/base/index.js +26 -0
  84. package/dist/cjs/templates/base/index.js.map +1 -0
  85. package/dist/cjs/templates/index.js +34 -0
  86. package/dist/cjs/templates/index.js.map +1 -0
  87. package/dist/cjs/templates/modes/consent-only.template.js +74 -0
  88. package/dist/cjs/templates/modes/consent-only.template.js.map +1 -0
  89. package/dist/cjs/templates/modes/credentials.template.js +414 -0
  90. package/dist/cjs/templates/modes/credentials.template.js.map +1 -0
  91. package/dist/cjs/templates/modes/index.js +24 -0
  92. package/dist/cjs/templates/modes/index.js.map +1 -0
  93. package/dist/cjs/templates/modes/magic-link.template.js +196 -0
  94. package/dist/cjs/templates/modes/magic-link.template.js.map +1 -0
  95. package/dist/cjs/templates/modes/oauth.template.js +153 -0
  96. package/dist/cjs/templates/modes/oauth.template.js.map +1 -0
  97. package/dist/cjs/templates/modes/otp.template.js +316 -0
  98. package/dist/cjs/templates/modes/otp.template.js.map +1 -0
  99. package/dist/cjs/templates/modes/success.template.js +140 -0
  100. package/dist/cjs/templates/modes/success.template.js.map +1 -0
  101. package/dist/cjs/templates/registry.js +133 -0
  102. package/dist/cjs/templates/registry.js.map +1 -0
  103. package/dist/cjs/types/api.types.js +10 -0
  104. package/dist/cjs/types/api.types.js.map +1 -0
  105. package/dist/cjs/types/branding.types.js +10 -0
  106. package/dist/cjs/types/branding.types.js.map +1 -0
  107. package/dist/cjs/types/config.types.js +10 -0
  108. package/dist/cjs/types/config.types.js.map +1 -0
  109. package/dist/cjs/types/copy.types.js +10 -0
  110. package/dist/cjs/types/copy.types.js.map +1 -0
  111. package/dist/cjs/types/index.js +31 -0
  112. package/dist/cjs/types/index.js.map +1 -0
  113. package/dist/cjs/types/modes.types.js +140 -0
  114. package/dist/cjs/types/modes.types.js.map +1 -0
  115. package/dist/cjs/types/page.types.js +10 -0
  116. package/dist/cjs/types/page.types.js.map +1 -0
  117. package/dist/components/mcp-consent.d.ts +6 -0
  118. package/dist/components/mcp-consent.d.ts.map +1 -1
  119. package/dist/components/mcp-consent.js +14 -0
  120. package/dist/components/mcp-consent.js.map +1 -1
  121. package/dist/consent.js +7 -0
  122. package/dist/consent.min.js +2 -2
  123. package/dist/schemas/api.schemas.d.ts +177 -169
  124. package/dist/schemas/api.schemas.d.ts.map +1 -1
  125. package/dist/schemas/api.schemas.js +6 -0
  126. package/dist/schemas/api.schemas.js.map +1 -1
  127. package/dist/schemas/config.schemas.d.ts +116 -116
  128. package/dist/schemas/modes.schemas.d.ts +28 -28
  129. package/dist/types/api.types.d.ts +6 -0
  130. package/dist/types/api.types.d.ts.map +1 -1
  131. package/package.json +29 -15
@@ -0,0 +1,1034 @@
1
+ "use strict";
2
+ /**
3
+ * MCP Consent Composite Web Component
4
+ *
5
+ * The main entry point component that orchestrates the full consent flow.
6
+ * Handles all auth modes, form submission, and state management.
7
+ *
8
+ * @module components/mcp-consent
9
+ */
10
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.McpConsent = void 0;
18
+ const lit_1 = require("lit");
19
+ const decorators_js_1 = require("lit/decorators.js");
20
+ const modes_types_js_1 = require("../types/modes.types.js");
21
+ const resolve_config_js_1 = require("../resolution/resolve-config.js");
22
+ // Import component definitions for side effects
23
+ require("./consent-shell.js");
24
+ require("./consent-button.js");
25
+ require("./consent-checkbox.js");
26
+ require("./consent-input.js");
27
+ require("./consent-permissions.js");
28
+ require("./consent-terms.js");
29
+ require("./consent-oauth-button.js");
30
+ require("./consent-otp-input.js");
31
+ /**
32
+ * McpConsent - Full consent flow component
33
+ *
34
+ * @example
35
+ * ```html
36
+ * <mcp-consent
37
+ * config='{"branding": {"primaryColor": "#2563eb"}}'
38
+ * tool="greet"
39
+ * scopes='["read:profile"]'
40
+ * agent-did="did:key:z123"
41
+ * session-id="sess_123"
42
+ * project-id="proj_123"
43
+ * server-url="https://example.com"
44
+ * ></mcp-consent>
45
+ * ```
46
+ *
47
+ * @fires mcp-consent:approve - User approved, delegation created
48
+ * @fires mcp-consent:deny - User clicked cancel
49
+ * @fires mcp-consent:error - Submission failed
50
+ */
51
+ let McpConsent = class McpConsent extends lit_1.LitElement {
52
+ constructor() {
53
+ // === INPUT PROPERTIES (from config) ===
54
+ super(...arguments);
55
+ // === CONSENT DATA (hidden form fields) ===
56
+ /**
57
+ * Tool being authorized
58
+ */
59
+ this.tool = "";
60
+ /**
61
+ * Permission scopes requested
62
+ */
63
+ this.scopes = [];
64
+ /**
65
+ * Agent DID
66
+ */
67
+ this.agentDid = "";
68
+ /**
69
+ * Session ID
70
+ */
71
+ this.sessionId = "";
72
+ /**
73
+ * Project ID
74
+ */
75
+ this.projectId = "";
76
+ /**
77
+ * Server URL for form submission
78
+ */
79
+ this.serverUrl = "";
80
+ /**
81
+ * Agent name for display
82
+ */
83
+ this.agentName = "";
84
+ /**
85
+ * Auth provider identifier (e.g., 'credentials', 'google', 'github')
86
+ * Required for credential auth and OAuth flows to identify the provider
87
+ */
88
+ this.provider = "";
89
+ /**
90
+ * CSRF token for form security
91
+ * Required for credential auth flows to prevent CSRF attacks
92
+ */
93
+ this.csrfToken = "";
94
+ // === POST-CREDENTIAL AUTH PARAMS (for 3-screen flow) ===
95
+ /**
96
+ * Credential provider type from prior auth step
97
+ * Set when redirecting from credential auth → clickwrap page
98
+ * Used to ensure delegation is created with correct authorization type ('password')
99
+ */
100
+ this.credentialProviderType = "";
101
+ /**
102
+ * Credential provider name from prior auth step
103
+ * Set when redirecting from credential auth → clickwrap page
104
+ */
105
+ this.credentialProvider = "";
106
+ /**
107
+ * User DID from prior auth step
108
+ * Set when redirecting from credential auth → clickwrap page
109
+ * CRITICAL: Bypasses KV eventual consistency issues by passing userDid directly
110
+ */
111
+ this.userDid = "";
112
+ this.currentMode = modes_types_js_1.AUTH_MODES.CONSENT_ONLY;
113
+ this.loading = false;
114
+ this.step = "consent";
115
+ this.termsAccepted = false;
116
+ this.formData = {};
117
+ this.resendCooldown = 0;
118
+ this.selectedScopes = [];
119
+ }
120
+ // === LIFECYCLE ===
121
+ connectedCallback() {
122
+ super.connectedCallback();
123
+ this.resolved = (0, resolve_config_js_1.resolveConsentConfig)(this.config, this.agentName);
124
+ this.currentMode =
125
+ this.mode ?? (0, resolve_config_js_1.determineAuthMode)(this.config) ?? modes_types_js_1.AUTH_MODES.CONSENT_ONLY;
126
+ // Initialize selected scopes with all requested scopes
127
+ this.selectedScopes = [...this.scopes];
128
+ }
129
+ disconnectedCallback() {
130
+ super.disconnectedCallback();
131
+ // Clean up interval timer to prevent memory leaks
132
+ if (this.resendCooldownInterval !== undefined) {
133
+ clearInterval(this.resendCooldownInterval);
134
+ this.resendCooldownInterval = undefined;
135
+ }
136
+ }
137
+ updated(changedProperties) {
138
+ if (changedProperties.has("config") || changedProperties.has("agentName")) {
139
+ this.resolved = (0, resolve_config_js_1.resolveConsentConfig)(this.config, this.agentName);
140
+ }
141
+ if (changedProperties.has("mode") && this.mode) {
142
+ this.currentMode = this.mode;
143
+ }
144
+ // Update selected scopes when scopes change
145
+ if (changedProperties.has("scopes")) {
146
+ this.selectedScopes = [...this.scopes];
147
+ }
148
+ // Update CSS variables from resolved config
149
+ if (this.resolved) {
150
+ this.style.setProperty("--consent-primary", this.resolved.branding.primaryColor);
151
+ this.style.setProperty("--consent-secondary", this.resolved.branding.secondaryColor);
152
+ }
153
+ }
154
+ // === FORM SUBMISSION ===
155
+ /**
156
+ * Get the provider_type based on the current auth mode.
157
+ *
158
+ * Uses the centralized AUTH_MODE_TO_PROVIDER_TYPE mapping from modes.types.ts
159
+ * to ensure type-safety and DRY principle compliance.
160
+ *
161
+ * For OAuth mode, returns the specific provider from oauthIdentity if available.
162
+ *
163
+ * @see getProviderTypeForAuthMode - The canonical mapping function
164
+ */
165
+ getProviderType() {
166
+ // For OAuth, prefer the specific provider name if available
167
+ if (this.currentMode === modes_types_js_1.AUTH_MODES.OAUTH && this.oauthIdentity?.provider) {
168
+ return this.oauthIdentity.provider;
169
+ }
170
+ // Use the centralized type-safe mapping
171
+ return (0, modes_types_js_1.getProviderTypeForAuthMode)(this.currentMode);
172
+ }
173
+ /**
174
+ * Handle consent approval - TRIGGERS DELEGATIONCREDENTIAL (VC) CREATION
175
+ *
176
+ * This is the critical method where the user's consent is submitted.
177
+ * When this succeeds, a DelegationCredential (W3C Verifiable Credential)
178
+ * is created on the server, authorizing the agent to act on behalf of the user.
179
+ *
180
+ * ## Flow Context
181
+ *
182
+ * This method is called when the user clicks "Approve" on the Consent Screen:
183
+ * - Consent Only: [Consent Screen] → handleApprove() → [Success Screen]
184
+ * - Auth flows: [Auth Screen] → [Consent Screen] → handleApprove() → [Success Screen]
185
+ *
186
+ * In both cases, the VC is created HERE, not during authentication.
187
+ * Authentication only verifies identity; consent grants the delegation.
188
+ *
189
+ * @fires mcp-consent:approve - Emitted when consent is successfully submitted
190
+ * @fires mcp-consent:error - Emitted if consent submission fails
191
+ */
192
+ async handleApprove(e) {
193
+ e?.preventDefault();
194
+ // Guard against duplicate submissions
195
+ if (this.loading) {
196
+ return;
197
+ }
198
+ if (!this.termsAccepted && this.resolved?.terms.required) {
199
+ this.error = "Please accept the terms to continue";
200
+ return;
201
+ }
202
+ if (this.scopes.length > 0 && this.selectedScopes.length === 0) {
203
+ this.error = "Please select at least one permission";
204
+ return;
205
+ }
206
+ this.loading = true;
207
+ this.error = undefined;
208
+ try {
209
+ // Build consent approval request
210
+ // The server creates the DelegationCredential (VC) when this request succeeds
211
+ const formData = new FormData();
212
+ formData.append("tool", this.tool);
213
+ formData.append("scopes", JSON.stringify(this.selectedScopes));
214
+ formData.append("agent_did", this.agentDid);
215
+ formData.append("session_id", this.sessionId);
216
+ formData.append("project_id", this.projectId);
217
+ formData.append("auth_mode", this.currentMode);
218
+ // Set provider_type based on auth mode to ensure correct server-side routing
219
+ // This is stored in delegation metadata to track what auth method was used
220
+ formData.append("provider_type", this.getProviderType());
221
+ // Include provider for credential auth and OAuth flows - REQUIRED by consent.service.ts validation
222
+ if (this.provider) {
223
+ formData.append("provider", this.provider);
224
+ }
225
+ // Include CSRF token for security - REQUIRED by consent.service.ts for credential auth
226
+ if (this.csrfToken) {
227
+ formData.append("csrf_token", this.csrfToken);
228
+ }
229
+ formData.append("termsAccepted", String(this.termsAccepted));
230
+ // Include credential auth params if present (3-screen flow: Auth → Clickwrap → Success)
231
+ // These are set when redirecting from credential auth page to clickwrap page
232
+ // They ensure the delegation is created with correct authorization.type ('password')
233
+ if (this.credentialProviderType) {
234
+ formData.append("credential_provider_type", this.credentialProviderType);
235
+ }
236
+ if (this.credentialProvider) {
237
+ formData.append("credential_provider", this.credentialProvider);
238
+ }
239
+ // CRITICAL: Pass userDid directly to bypass KV eventual consistency issues
240
+ // Without this, the delegation might be stored with wrong key due to stale KV read
241
+ if (this.userDid) {
242
+ formData.append("user_did", this.userDid);
243
+ }
244
+ // Add custom form data (e.g., username/password for credential auth)
245
+ Object.entries(this.formData).forEach(([key, value]) => {
246
+ formData.append(key, value);
247
+ });
248
+ // Submit consent - server creates DelegationCredential on success
249
+ const response = await fetch(`${this.serverUrl}/consent/approve`, {
250
+ method: "POST",
251
+ body: formData,
252
+ });
253
+ if (!response.ok) {
254
+ const errorData = await response.json().catch(() => ({}));
255
+ throw new Error(errorData.message || "Approval failed");
256
+ }
257
+ const result = await response.json();
258
+ // Check if server wants us to redirect (e.g., credential auth → clickwrap page)
259
+ // This implements the 3-screen flow: Auth → Clickwrap → Success
260
+ if (result.redirectUrl) {
261
+ // Dispatch event before redirect for any listeners that need to know
262
+ this.dispatchEvent(new CustomEvent("mcp-consent:approve", {
263
+ detail: { success: true, redirectUrl: result.redirectUrl },
264
+ bubbles: true,
265
+ composed: true,
266
+ }));
267
+ // Navigate to the redirect URL (clickwrap page after credential/OAuth auth)
268
+ // The clickwrap page will show user info + scopes, then create the delegation
269
+ window.location.href = result.redirectUrl;
270
+ return; // Don't show success yet - the redirect page will handle it
271
+ }
272
+ // No redirect - VC/delegation created successfully, show success screen
273
+ this.step = "success";
274
+ this.dispatchEvent(new CustomEvent("mcp-consent:approve", {
275
+ detail: { success: true, delegationId: result.delegation_id },
276
+ bubbles: true,
277
+ composed: true,
278
+ }));
279
+ }
280
+ catch (e) {
281
+ this.error = e instanceof Error ? e.message : "Unknown error";
282
+ this.dispatchEvent(new CustomEvent("mcp-consent:error", {
283
+ detail: { error: this.error },
284
+ bubbles: true,
285
+ composed: true,
286
+ }));
287
+ }
288
+ finally {
289
+ this.loading = false;
290
+ }
291
+ }
292
+ handleDeny() {
293
+ this.dispatchEvent(new CustomEvent("mcp-consent:deny", {
294
+ bubbles: true,
295
+ composed: true,
296
+ }));
297
+ // Try to close the window/tab
298
+ window.close();
299
+ }
300
+ handleTermsChange(e) {
301
+ this.termsAccepted = e.detail.checked;
302
+ }
303
+ handleInputChange(name, value) {
304
+ this.formData = { ...this.formData, [name]: value };
305
+ }
306
+ handleResendOtp() {
307
+ if (this.resendCooldown > 0) {
308
+ return;
309
+ }
310
+ const cooldownSeconds = this.resolved?.otp?.resendCooldown ?? 60;
311
+ this.resendCooldown = cooldownSeconds;
312
+ // Clear any existing interval before starting a new one
313
+ if (this.resendCooldownInterval !== undefined) {
314
+ clearInterval(this.resendCooldownInterval);
315
+ }
316
+ // Start countdown timer (stored in class property for cleanup)
317
+ this.resendCooldownInterval = setInterval(() => {
318
+ this.resendCooldown--;
319
+ if (this.resendCooldown <= 0) {
320
+ clearInterval(this.resendCooldownInterval);
321
+ this.resendCooldownInterval = undefined;
322
+ }
323
+ }, 1000);
324
+ // Dispatch event for parent to handle actual resend
325
+ this.dispatchEvent(new CustomEvent("mcp-consent:resend-otp", {
326
+ bubbles: true,
327
+ composed: true,
328
+ }));
329
+ }
330
+ // === RENDER METHODS ===
331
+ renderAgentInfo() {
332
+ const agentDisplay = this.agentName || "this agent";
333
+ return (0, lit_1.html) `
334
+ <div class="agent-info">
335
+ <div class="agent-icon">
336
+ <svg
337
+ xmlns="http://www.w3.org/2000/svg"
338
+ viewBox="0 0 24 24"
339
+ fill="none"
340
+ stroke="currentColor"
341
+ stroke-width="2"
342
+ >
343
+ <circle cx="12" cy="12" r="10" />
344
+ <path d="M12 16v-4M12 8h.01" />
345
+ </svg>
346
+ </div>
347
+ <div class="agent-text">
348
+ <p>
349
+ <strong>${agentDisplay}</strong> is requesting permission to
350
+ ${this.tool
351
+ ? (0, lit_1.html) `use the <strong>${this.tool}</strong> tool`
352
+ : "access your data"}
353
+ on your behalf.
354
+ </p>
355
+ </div>
356
+ </div>
357
+ `;
358
+ }
359
+ handlePermissionsChange(e) {
360
+ this.selectedScopes = e.detail.selected;
361
+ }
362
+ renderPermissions() {
363
+ if (this.scopes.length === 0)
364
+ return lit_1.nothing;
365
+ return (0, lit_1.html) `
366
+ <p class="permissions-header">
367
+ ${this.resolved?.ui.permissionsHeader ??
368
+ "The agent is requesting the following permissions:"}
369
+ </p>
370
+ <div class="permissions">
371
+ <consent-permissions
372
+ .scopes=${this.scopes}
373
+ interactive
374
+ select-all
375
+ @change=${this.handlePermissionsChange}
376
+ ></consent-permissions>
377
+ </div>
378
+ `;
379
+ }
380
+ renderExpiration() {
381
+ const days = this.resolved?.expirationDays ?? 7;
382
+ return (0, lit_1.html) `
383
+ <p class="expiration">
384
+ ${this.resolved?.ui.expirationText ?? "This delegation will expire in"}
385
+ <strong>${days} ${days === 1 ? "day" : "days"}</strong>
386
+ </p>
387
+ `;
388
+ }
389
+ renderTerms() {
390
+ if (!this.resolved?.terms)
391
+ return lit_1.nothing;
392
+ return (0, lit_1.html) `
393
+ <div class="terms">
394
+ <consent-terms
395
+ name="termsAccepted"
396
+ text=${this.resolved.terms.text}
397
+ url=${this.resolved.terms.url ?? ""}
398
+ ?required=${this.resolved.terms.required}
399
+ @change=${this.handleTermsChange}
400
+ ></consent-terms>
401
+ </div>
402
+ `;
403
+ }
404
+ renderError() {
405
+ if (!this.error)
406
+ return lit_1.nothing;
407
+ return (0, lit_1.html) `<div class="error-message">${this.error}</div>`;
408
+ }
409
+ renderFooter() {
410
+ return (0, lit_1.html) `
411
+ <div slot="footer">
412
+ <consent-button variant="secondary" @click=${this.handleDeny}>
413
+ ${this.resolved?.ui.cancelButtonText ?? "Cancel"}
414
+ </consent-button>
415
+ <consent-button
416
+ variant="primary"
417
+ ?loading=${this.loading}
418
+ ?disabled=${this.resolved?.terms.required && !this.termsAccepted}
419
+ @click=${this.handleApprove}
420
+ >
421
+ ${this.resolved?.ui.submitButtonText ?? "Allow access"}
422
+ </consent-button>
423
+ </div>
424
+ `;
425
+ }
426
+ // === MODE-SPECIFIC RENDERS ===
427
+ renderConsentOnly() {
428
+ return (0, lit_1.html) `
429
+ <consent-shell
430
+ page-title=${this.resolved?.ui.title ?? "Permission Request"}
431
+ company-name=${this.resolved?.branding.companyName ?? ""}
432
+ logo-url=${this.resolved?.branding.logoUrl ?? ""}
433
+ primary-color=${this.resolved?.branding.primaryColor ?? "#2563eb"}
434
+ secondary-color=${this.resolved?.branding.secondaryColor ?? "#dbeafe"}
435
+ >
436
+ <div slot="content">
437
+ ${this.renderError()} ${this.renderAgentInfo()}
438
+ ${this.renderPermissions()} ${this.renderExpiration()}
439
+ ${this.renderTerms()}
440
+ </div>
441
+ ${this.renderFooter()}
442
+ </consent-shell>
443
+ `;
444
+ }
445
+ renderCredentials() {
446
+ const creds = this.resolved?.credentials;
447
+ return (0, lit_1.html) `
448
+ <consent-shell
449
+ page-title=${this.resolved?.ui.title ?? "Sign In"}
450
+ company-name=${this.resolved?.branding.companyName ?? ""}
451
+ logo-url=${this.resolved?.branding.logoUrl ?? ""}
452
+ primary-color=${this.resolved?.branding.primaryColor ?? "#2563eb"}
453
+ secondary-color=${this.resolved?.branding.secondaryColor ?? "#dbeafe"}
454
+ >
455
+ <div slot="content">
456
+ ${this.renderError()} ${this.renderAgentInfo()}
457
+
458
+ <div class="form-fields">
459
+ <consent-input
460
+ type="text"
461
+ name="username"
462
+ label=${creds?.usernameLabel ?? "Username"}
463
+ placeholder=${creds?.usernamePlaceholder ?? "Enter your username"}
464
+ autocomplete="username"
465
+ required
466
+ @input=${(e) => {
467
+ // Handle both CustomEvent (from consent-input) and native InputEvent
468
+ const customEvent = e;
469
+ const value = customEvent.detail?.value ??
470
+ e.target?.value ??
471
+ "";
472
+ this.handleInputChange("username", value);
473
+ }}
474
+ ></consent-input>
475
+
476
+ <consent-input
477
+ type="password"
478
+ name="password"
479
+ label=${creds?.passwordLabel ?? "Password"}
480
+ placeholder=${creds?.passwordPlaceholder ?? "Enter your password"}
481
+ autocomplete="current-password"
482
+ required
483
+ @input=${(e) => {
484
+ // Handle both CustomEvent (from consent-input) and native InputEvent
485
+ const customEvent = e;
486
+ const value = customEvent.detail?.value ??
487
+ e.target?.value ??
488
+ "";
489
+ this.handleInputChange("password", value);
490
+ }}
491
+ ></consent-input>
492
+ </div>
493
+
494
+ ${creds?.showForgotPassword && creds.forgotPasswordUrl
495
+ ? (0, lit_1.html) `
496
+ <p style="text-align: right; margin-bottom: 1rem;">
497
+ <a
498
+ href=${creds.forgotPasswordUrl}
499
+ style="font-size: 0.75rem; color: var(--_primary);"
500
+ >
501
+ Forgot password?
502
+ </a>
503
+ </p>
504
+ `
505
+ : lit_1.nothing}
506
+ ${this.renderPermissions()} ${this.renderExpiration()}
507
+ ${this.renderTerms()}
508
+ </div>
509
+ ${this.renderFooter()}
510
+ </consent-shell>
511
+ `;
512
+ }
513
+ renderOAuth() {
514
+ const oauth = this.resolved?.oauth;
515
+ const provider = oauth?.providerId ?? "oauth";
516
+ const providerName = oauth?.providerName ?? "OAuth Provider";
517
+ return (0, lit_1.html) `
518
+ <consent-shell
519
+ page-title=${this.resolved?.ui.title ?? "Sign In"}
520
+ company-name=${this.resolved?.branding.companyName ?? ""}
521
+ logo-url=${this.resolved?.branding.logoUrl ?? ""}
522
+ primary-color=${this.resolved?.branding.primaryColor ?? "#2563eb"}
523
+ secondary-color=${this.resolved?.branding.secondaryColor ?? "#dbeafe"}
524
+ >
525
+ <div slot="content">
526
+ ${this.renderError()} ${this.renderAgentInfo()}
527
+
528
+ <consent-oauth-button
529
+ provider=${provider}
530
+ provider-name=${providerName}
531
+ url=${`${this.serverUrl}/oauth/${encodeURIComponent(provider)}?session_id=${encodeURIComponent(this.sessionId)}`}
532
+ button-text=${oauth?.buttonText ?? `Continue with ${providerName}`}
533
+ full-width
534
+ ></consent-oauth-button>
535
+
536
+ ${this.renderPermissions()}
537
+
538
+ <div class="divider">or</div>
539
+
540
+ ${this.renderExpiration()} ${this.renderTerms()}
541
+ </div>
542
+ ${this.renderFooter()}
543
+ </consent-shell>
544
+ `;
545
+ }
546
+ renderMagicLink() {
547
+ const ml = this.resolved?.magicLink;
548
+ return (0, lit_1.html) `
549
+ <consent-shell
550
+ page-title=${this.resolved?.ui.title ?? "Sign In"}
551
+ company-name=${this.resolved?.branding.companyName ?? ""}
552
+ logo-url=${this.resolved?.branding.logoUrl ?? ""}
553
+ primary-color=${this.resolved?.branding.primaryColor ?? "#2563eb"}
554
+ secondary-color=${this.resolved?.branding.secondaryColor ?? "#dbeafe"}
555
+ >
556
+ <div slot="content">
557
+ ${this.renderError()} ${this.renderAgentInfo()}
558
+
559
+ <div class="form-fields">
560
+ <consent-input
561
+ type="email"
562
+ name="email"
563
+ label=${ml?.emailLabel ?? "Email"}
564
+ placeholder=${ml?.emailPlaceholder ?? "Enter your email address"}
565
+ autocomplete="email"
566
+ required
567
+ @input=${(e) => {
568
+ // Handle both CustomEvent (from consent-input) and native InputEvent
569
+ const customEvent = e;
570
+ const value = customEvent.detail?.value ??
571
+ e.target?.value ??
572
+ "";
573
+ this.handleInputChange("email", value);
574
+ }}
575
+ ></consent-input>
576
+ </div>
577
+
578
+ ${this.renderPermissions()} ${this.renderExpiration()}
579
+ ${this.renderTerms()}
580
+ </div>
581
+
582
+ <div slot="footer">
583
+ <consent-button variant="secondary" @click=${this.handleDeny}>
584
+ Cancel
585
+ </consent-button>
586
+ <consent-button
587
+ variant="primary"
588
+ ?loading=${this.loading}
589
+ ?disabled=${this.resolved?.terms.required && !this.termsAccepted}
590
+ @click=${this.handleApprove}
591
+ >
592
+ ${ml?.buttonText ?? "Send magic link"}
593
+ </consent-button>
594
+ </div>
595
+ </consent-shell>
596
+ `;
597
+ }
598
+ renderOTP() {
599
+ const otp = this.resolved?.otp;
600
+ return (0, lit_1.html) `
601
+ <consent-shell
602
+ page-title=${this.resolved?.ui.title ?? "Verify Code"}
603
+ company-name=${this.resolved?.branding.companyName ?? ""}
604
+ logo-url=${this.resolved?.branding.logoUrl ?? ""}
605
+ primary-color=${this.resolved?.branding.primaryColor ?? "#2563eb"}
606
+ secondary-color=${this.resolved?.branding.secondaryColor ?? "#dbeafe"}
607
+ >
608
+ <div slot="content">
609
+ ${this.renderError()} ${this.renderAgentInfo()}
610
+
611
+ <div class="otp-section">
612
+ <p class="otp-instructions">
613
+ ${otp?.instructions ??
614
+ "Enter the verification code sent to your device"}
615
+ </p>
616
+ <consent-otp-input
617
+ length=${otp?.digits ?? 6}
618
+ name="otp"
619
+ auto-focus
620
+ @complete=${(e) => {
621
+ const customEvent = e;
622
+ const value = customEvent.detail?.value ?? "";
623
+ this.handleInputChange("otp", value);
624
+ this.handleApprove();
625
+ }}
626
+ @input=${(e) => {
627
+ const customEvent = e;
628
+ const value = customEvent.detail?.value ?? "";
629
+ this.handleInputChange("otp", value);
630
+ }}
631
+ ></consent-otp-input>
632
+ <div class="otp-resend">
633
+ Didn't receive the code?
634
+ <button
635
+ type="button"
636
+ ?disabled=${this.resendCooldown > 0}
637
+ @click=${this.handleResendOtp}
638
+ >
639
+ ${this.resendCooldown > 0
640
+ ? `Resend in ${this.resendCooldown}s`
641
+ : "Resend"}
642
+ </button>
643
+ </div>
644
+ </div>
645
+
646
+ ${this.renderPermissions()} ${this.renderTerms()}
647
+ </div>
648
+ ${this.renderFooter()}
649
+ </consent-shell>
650
+ `;
651
+ }
652
+ renderSuccess() {
653
+ const success = this.resolved?.success;
654
+ return (0, lit_1.html) `
655
+ <consent-shell
656
+ page-title=${success?.title ?? "Access Granted"}
657
+ company-name=${this.resolved?.branding.companyName ?? ""}
658
+ logo-url=${this.resolved?.branding.logoUrl ?? ""}
659
+ primary-color=${this.resolved?.branding.primaryColor ?? "#2563eb"}
660
+ secondary-color=${this.resolved?.branding.secondaryColor ?? "#dbeafe"}
661
+ >
662
+ <div slot="content">
663
+ <div class="success-view">
664
+ <div class="success-icon">
665
+ <svg
666
+ xmlns="http://www.w3.org/2000/svg"
667
+ viewBox="0 0 24 24"
668
+ fill="none"
669
+ stroke="currentColor"
670
+ stroke-width="2"
671
+ >
672
+ <polyline points="20 6 9 17 4 12" />
673
+ </svg>
674
+ </div>
675
+ <h2 class="success-title">${success?.title ?? "Access Granted"}</h2>
676
+ <p class="success-description">
677
+ ${success?.description ??
678
+ "You have successfully granted access. You can now close this window."}
679
+ </p>
680
+ </div>
681
+ </div>
682
+
683
+ <div slot="footer">
684
+ <consent-button
685
+ variant="primary"
686
+ full-width
687
+ @click=${() => window.close()}
688
+ >
689
+ ${success?.continueButtonText ?? "Close"}
690
+ </consent-button>
691
+ </div>
692
+ </consent-shell>
693
+ `;
694
+ }
695
+ // === MAIN RENDER ===
696
+ render() {
697
+ // Use previewStep if provided (for WYSIWYG editor), otherwise fall back to internal step
698
+ const displayStep = this.previewStep ?? this.step;
699
+ if (displayStep === "success") {
700
+ return this.renderSuccess();
701
+ }
702
+ // For "consent" previewStep or normal flow, render based on auth mode
703
+ switch (this.currentMode) {
704
+ case modes_types_js_1.AUTH_MODES.CREDENTIALS:
705
+ return this.renderCredentials();
706
+ case modes_types_js_1.AUTH_MODES.OAUTH:
707
+ return this.renderOAuth();
708
+ case modes_types_js_1.AUTH_MODES.MAGIC_LINK:
709
+ return this.renderMagicLink();
710
+ case modes_types_js_1.AUTH_MODES.OTP:
711
+ return this.renderOTP();
712
+ case modes_types_js_1.AUTH_MODES.CONSENT_ONLY:
713
+ default:
714
+ return this.renderConsentOnly();
715
+ }
716
+ }
717
+ };
718
+ exports.McpConsent = McpConsent;
719
+ McpConsent.styles = (0, lit_1.css) `
720
+ :host {
721
+ display: block;
722
+ /* System font stack with font smoothing for crisp text */
723
+ font-family:
724
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
725
+ Arial, sans-serif;
726
+ -webkit-font-smoothing: antialiased;
727
+ -moz-osx-font-smoothing: grayscale;
728
+ --_primary: var(--consent-primary, #2563eb);
729
+ --_secondary: var(--consent-secondary, #dbeafe);
730
+ }
731
+
732
+ /* Agent info box */
733
+ .agent-info {
734
+ display: flex;
735
+ gap: 1rem;
736
+ padding: 1rem;
737
+ background: #f9fafb;
738
+ border-radius: 0.5rem;
739
+ margin-bottom: 1rem;
740
+ }
741
+
742
+ .agent-icon {
743
+ width: 40px;
744
+ height: 40px;
745
+ background: var(--_secondary);
746
+ border-radius: 0.5rem;
747
+ display: flex;
748
+ align-items: center;
749
+ justify-content: center;
750
+ flex-shrink: 0;
751
+ }
752
+
753
+ .agent-icon svg {
754
+ width: 20px;
755
+ height: 20px;
756
+ color: var(--_primary);
757
+ }
758
+
759
+ .agent-text {
760
+ flex: 1;
761
+ }
762
+
763
+ .agent-text p {
764
+ margin: 0;
765
+ font-size: 0.875rem;
766
+ color: #374151;
767
+ line-height: 1.5;
768
+ }
769
+
770
+ .agent-text strong {
771
+ color: #111827;
772
+ }
773
+
774
+ /* Permissions section */
775
+ .permissions-header {
776
+ font-size: 0.875rem;
777
+ color: #6b7280;
778
+ margin-bottom: 0.5rem;
779
+ }
780
+
781
+ .permissions {
782
+ margin-bottom: 1rem;
783
+ }
784
+
785
+ /* Expiration */
786
+ .expiration {
787
+ font-size: 0.75rem;
788
+ color: #6b7280;
789
+ margin-top: 1rem;
790
+ }
791
+
792
+ .expiration strong {
793
+ color: #374151;
794
+ }
795
+
796
+ /* Terms */
797
+ .terms {
798
+ margin-top: 1.5rem;
799
+ }
800
+
801
+ /* Error message */
802
+ .error-message {
803
+ background: #fef2f2;
804
+ border: 1px solid #fecaca;
805
+ border-radius: 0.5rem;
806
+ padding: 0.75rem 1rem;
807
+ margin-bottom: 1rem;
808
+ color: #dc2626;
809
+ font-size: 0.875rem;
810
+ }
811
+
812
+ /* Form fields */
813
+ .form-fields {
814
+ display: flex;
815
+ flex-direction: column;
816
+ gap: 1rem;
817
+ margin-bottom: 1rem;
818
+ }
819
+
820
+ /* Divider */
821
+ .divider {
822
+ display: flex;
823
+ align-items: center;
824
+ gap: 1rem;
825
+ margin: 1.5rem 0;
826
+ color: #6b7280;
827
+ font-size: 0.75rem;
828
+ }
829
+
830
+ .divider::before,
831
+ .divider::after {
832
+ content: "";
833
+ flex: 1;
834
+ height: 1px;
835
+ background: #e5e7eb;
836
+ }
837
+
838
+ /* Success view */
839
+ .success-view {
840
+ text-align: center;
841
+ padding: 2rem 0;
842
+ }
843
+
844
+ .success-icon {
845
+ width: 64px;
846
+ height: 64px;
847
+ background: #d1fae5;
848
+ border-radius: 50%;
849
+ display: flex;
850
+ align-items: center;
851
+ justify-content: center;
852
+ margin: 0 auto 1.5rem;
853
+ }
854
+
855
+ .success-icon svg {
856
+ width: 32px;
857
+ height: 32px;
858
+ color: #059669;
859
+ }
860
+
861
+ .success-title {
862
+ font-size: 1.25rem;
863
+ font-weight: 600;
864
+ color: #111827;
865
+ margin: 0 0 0.5rem;
866
+ }
867
+
868
+ .success-description {
869
+ font-size: 0.875rem;
870
+ color: #6b7280;
871
+ margin: 0 0 1.5rem;
872
+ }
873
+
874
+ /* OTP section */
875
+ .otp-section {
876
+ text-align: center;
877
+ margin-bottom: 1.5rem;
878
+ }
879
+
880
+ .otp-instructions {
881
+ font-size: 0.875rem;
882
+ color: #6b7280;
883
+ margin-bottom: 1rem;
884
+ }
885
+
886
+ .otp-resend {
887
+ margin-top: 1rem;
888
+ font-size: 0.75rem;
889
+ }
890
+
891
+ .otp-resend button {
892
+ background: none;
893
+ border: none;
894
+ color: var(--_primary);
895
+ cursor: pointer;
896
+ text-decoration: underline;
897
+ }
898
+
899
+ .otp-resend button:disabled {
900
+ color: #9ca3af;
901
+ cursor: not-allowed;
902
+ }
903
+ `;
904
+ __decorate([
905
+ (0, decorators_js_1.property)({
906
+ type: Object,
907
+ converter: {
908
+ fromAttribute: (value) => {
909
+ if (!value)
910
+ return undefined;
911
+ try {
912
+ return JSON.parse(value);
913
+ }
914
+ catch {
915
+ return undefined;
916
+ }
917
+ },
918
+ toAttribute: (value) => {
919
+ return value ? JSON.stringify(value) : "";
920
+ },
921
+ },
922
+ })
923
+ ], McpConsent.prototype, "config", void 0);
924
+ __decorate([
925
+ (0, decorators_js_1.property)({ type: String })
926
+ ], McpConsent.prototype, "mode", void 0);
927
+ __decorate([
928
+ (0, decorators_js_1.property)({ type: String })
929
+ ], McpConsent.prototype, "tool", void 0);
930
+ __decorate([
931
+ (0, decorators_js_1.property)({
932
+ type: Array,
933
+ converter: {
934
+ fromAttribute: (value) => {
935
+ if (!value)
936
+ return [];
937
+ try {
938
+ return JSON.parse(value);
939
+ }
940
+ catch {
941
+ return [];
942
+ }
943
+ },
944
+ toAttribute: (value) => {
945
+ return JSON.stringify(value);
946
+ },
947
+ },
948
+ })
949
+ ], McpConsent.prototype, "scopes", void 0);
950
+ __decorate([
951
+ (0, decorators_js_1.property)({ type: String, attribute: "agent-did" })
952
+ ], McpConsent.prototype, "agentDid", void 0);
953
+ __decorate([
954
+ (0, decorators_js_1.property)({ type: String, attribute: "session-id" })
955
+ ], McpConsent.prototype, "sessionId", void 0);
956
+ __decorate([
957
+ (0, decorators_js_1.property)({ type: String, attribute: "project-id" })
958
+ ], McpConsent.prototype, "projectId", void 0);
959
+ __decorate([
960
+ (0, decorators_js_1.property)({ type: String, attribute: "server-url" })
961
+ ], McpConsent.prototype, "serverUrl", void 0);
962
+ __decorate([
963
+ (0, decorators_js_1.property)({ type: String, attribute: "agent-name" })
964
+ ], McpConsent.prototype, "agentName", void 0);
965
+ __decorate([
966
+ (0, decorators_js_1.property)({ type: String, attribute: "provider" })
967
+ ], McpConsent.prototype, "provider", void 0);
968
+ __decorate([
969
+ (0, decorators_js_1.property)({ type: String, attribute: "csrf-token" })
970
+ ], McpConsent.prototype, "csrfToken", void 0);
971
+ __decorate([
972
+ (0, decorators_js_1.property)({ type: String, attribute: "preview-step" })
973
+ ], McpConsent.prototype, "previewStep", void 0);
974
+ __decorate([
975
+ (0, decorators_js_1.property)({ type: String, attribute: "credential-provider-type" })
976
+ ], McpConsent.prototype, "credentialProviderType", void 0);
977
+ __decorate([
978
+ (0, decorators_js_1.property)({ type: String, attribute: "credential-provider" })
979
+ ], McpConsent.prototype, "credentialProvider", void 0);
980
+ __decorate([
981
+ (0, decorators_js_1.property)({ type: String, attribute: "user-did" })
982
+ ], McpConsent.prototype, "userDid", void 0);
983
+ __decorate([
984
+ (0, decorators_js_1.property)({
985
+ type: Object,
986
+ attribute: "oauth-identity",
987
+ converter: {
988
+ fromAttribute: (value) => {
989
+ if (!value)
990
+ return undefined;
991
+ try {
992
+ return JSON.parse(value);
993
+ }
994
+ catch {
995
+ return undefined;
996
+ }
997
+ },
998
+ toAttribute: (value) => {
999
+ return value ? JSON.stringify(value) : "";
1000
+ },
1001
+ },
1002
+ })
1003
+ ], McpConsent.prototype, "oauthIdentity", void 0);
1004
+ __decorate([
1005
+ (0, decorators_js_1.state)()
1006
+ ], McpConsent.prototype, "resolved", void 0);
1007
+ __decorate([
1008
+ (0, decorators_js_1.state)()
1009
+ ], McpConsent.prototype, "currentMode", void 0);
1010
+ __decorate([
1011
+ (0, decorators_js_1.state)()
1012
+ ], McpConsent.prototype, "loading", void 0);
1013
+ __decorate([
1014
+ (0, decorators_js_1.state)()
1015
+ ], McpConsent.prototype, "error", void 0);
1016
+ __decorate([
1017
+ (0, decorators_js_1.state)()
1018
+ ], McpConsent.prototype, "step", void 0);
1019
+ __decorate([
1020
+ (0, decorators_js_1.state)()
1021
+ ], McpConsent.prototype, "termsAccepted", void 0);
1022
+ __decorate([
1023
+ (0, decorators_js_1.state)()
1024
+ ], McpConsent.prototype, "formData", void 0);
1025
+ __decorate([
1026
+ (0, decorators_js_1.state)()
1027
+ ], McpConsent.prototype, "resendCooldown", void 0);
1028
+ __decorate([
1029
+ (0, decorators_js_1.state)()
1030
+ ], McpConsent.prototype, "selectedScopes", void 0);
1031
+ exports.McpConsent = McpConsent = __decorate([
1032
+ (0, decorators_js_1.customElement)("mcp-consent")
1033
+ ], McpConsent);
1034
+ //# sourceMappingURL=mcp-consent.js.map