@kya-os/consent 0.1.0 → 0.1.1

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