@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,414 @@
1
+ "use strict";
2
+ /**
3
+ * Credentials Template
4
+ *
5
+ * Username/password authentication flow.
6
+ * HTML structure matches AgentShield's CredentialsPreview.tsx EXACTLY.
7
+ *
8
+ * This is a pixel-perfect port of the React component to static HTML.
9
+ * Any changes here MUST be synchronized with AgentShield.
10
+ *
11
+ * @module @kya-os/consent/templates/modes/credentials
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.CredentialsTemplate = void 0;
15
+ const base_template_js_1 = require("../base/base-template.js");
16
+ const escape_js_1 = require("../../security/escape.js");
17
+ const stylesheet_js_1 = require("../../styles/stylesheet.js");
18
+ const modes_types_js_1 = require("../../types/modes.types.js");
19
+ /**
20
+ * Credentials Template
21
+ *
22
+ * Renders a login form matching AgentShield's CredentialsPreview exactly:
23
+ * - PreviewShell wrapper with branding
24
+ * - PreviewHeader with title
25
+ * - PreviewContent with spacing
26
+ * - PreviewAgentInfo with icon + description
27
+ * - Username/email field (shadcn Input style)
28
+ * - Password field with show/hide toggle
29
+ * - Remember me checkbox (label toggles checkbox)
30
+ * - Forgot password link
31
+ * - Cancel + Sign in buttons (PreviewButtonGroup)
32
+ */
33
+ class CredentialsTemplate extends base_template_js_1.BaseConsentTemplate {
34
+ constructor(config, resolved, remoteCredentials) {
35
+ super(config, resolved);
36
+ this.remoteCredentialsConfig = remoteCredentials;
37
+ }
38
+ get authMode() {
39
+ return modes_types_js_1.AUTH_MODES.CREDENTIALS;
40
+ }
41
+ get credentialsConfig() {
42
+ // Merge remote config with modeConfig, preferring modeConfig for overrides
43
+ const remote = this.remoteCredentialsConfig || {};
44
+ const local = this.config.modeConfig?.credentials || {};
45
+ return {
46
+ usernameLabel: local.usernameLabel || remote.usernameLabel || "Username",
47
+ usernamePlaceholder: local.usernamePlaceholder ||
48
+ remote.usernamePlaceholder ||
49
+ "Enter your username",
50
+ passwordLabel: local.passwordLabel || remote.passwordLabel || "Password",
51
+ passwordPlaceholder: local.passwordPlaceholder ||
52
+ remote.passwordPlaceholder ||
53
+ "Enter your password",
54
+ showRememberMe: local.showRememberMe ?? remote.showRememberMe ?? true,
55
+ showForgotPassword: local.showForgotPassword ?? remote.showForgotPassword ?? true,
56
+ forgotPasswordUrl: local.forgotPasswordUrl || remote.forgotPasswordUrl,
57
+ };
58
+ }
59
+ /**
60
+ * Override the main render method to match AgentShield's exact structure.
61
+ * This bypasses the base template's structure to ensure pixel-perfect match.
62
+ */
63
+ render() {
64
+ const { branding, copy } = this.resolved;
65
+ const config = this.credentialsConfig;
66
+ const primaryColor = branding.primaryColor;
67
+ return `<!DOCTYPE html>
68
+ <html lang="en">
69
+ <head>
70
+ ${this.renderHead()}
71
+ </head>
72
+ <body class="bg-gray-50 min-h-screen flex items-center justify-center p-4">
73
+ <!-- PreviewShell: bg-white rounded-[20px] border border-black/10 shadow-xl w-full overflow-hidden max-w-[512px] -->
74
+ <div
75
+ class="bg-white rounded-[20px] border border-black/10 shadow-xl w-full overflow-hidden"
76
+ style="max-width: 512px; --consent-primary: ${(0, escape_js_1.escapeAttr)(primaryColor)}; --consent-secondary: ${(0, escape_js_1.escapeAttr)(branding.secondaryColor)};"
77
+ >
78
+ <!-- PreviewHeader: px-8 pt-5 -->
79
+ <div class="px-8 pt-5">
80
+ <h2 class="text-2xl font-bold text-[#333333]">${(0, escape_js_1.escapeHtml)(copy.title)}</h2>
81
+ </div>
82
+
83
+ <!-- PreviewContent: p-8 pt-4 space-y-6 -->
84
+ <div class="p-8 pt-4 space-y-6">
85
+ <!-- PreviewAgentInfo: flex gap-4 items-start -->
86
+ <div class="flex gap-4 items-start">
87
+ <!-- Icon: w-[54px] h-[54px] rounded-[10px] border border-gray-300 -->
88
+ <div class="w-[54px] h-[54px] rounded-[10px] border border-gray-300 flex items-center justify-center flex-shrink-0 overflow-hidden bg-white">
89
+ ${this.renderAgentIcon()}
90
+ </div>
91
+ <!-- Description: text-base text-black leading-[1.4] flex-1 -->
92
+ <p class="text-base text-black leading-[1.4] flex-1">${(0, escape_js_1.escapeHtml)(copy.resolvedDescription)}</p>
93
+ </div>
94
+
95
+ <!-- Login Form: space-y-4 -->
96
+ <form id="credential-form" class="space-y-4">
97
+ <!-- Username Field: space-y-2 -->
98
+ <div class="space-y-2">
99
+ <label for="username" class="text-sm font-medium text-gray-700">
100
+ ${(0, escape_js_1.escapeHtml)(config.usernameLabel || "Username")}
101
+ </label>
102
+ <input
103
+ type="text"
104
+ id="username"
105
+ name="username"
106
+ placeholder="${(0, escape_js_1.escapeAttr)(config.usernamePlaceholder || "Enter your username")}"
107
+ required
108
+ autocomplete="username"
109
+ class="flex h-11 w-full rounded-md border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:cursor-not-allowed disabled:opacity-50"
110
+ />
111
+ </div>
112
+
113
+ <!-- Password Field: space-y-2 -->
114
+ <div class="space-y-2">
115
+ <label for="password" class="text-sm font-medium text-gray-700">
116
+ ${(0, escape_js_1.escapeHtml)(config.passwordLabel || "Password")}
117
+ </label>
118
+ <div class="relative">
119
+ <input
120
+ type="password"
121
+ id="password"
122
+ name="password"
123
+ placeholder="${(0, escape_js_1.escapeAttr)(config.passwordPlaceholder || "Enter your password")}"
124
+ required
125
+ autocomplete="current-password"
126
+ class="flex h-11 w-full rounded-md border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:cursor-not-allowed disabled:opacity-50 pr-10"
127
+ />
128
+ <button
129
+ type="button"
130
+ id="toggle-password"
131
+ class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
132
+ aria-label="Toggle password visibility"
133
+ >
134
+ <!-- Eye icon (visible when password is hidden) -->
135
+ <svg id="eye-icon" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
136
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
137
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
138
+ </svg>
139
+ <!-- Eye-off icon (visible when password is shown) -->
140
+ <svg id="eye-off-icon" class="w-4 h-4 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
141
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"></path>
142
+ </svg>
143
+ </button>
144
+ </div>
145
+ </div>
146
+
147
+ <!-- Remember Me & Forgot Password: flex items-center justify-between -->
148
+ ${this.renderRememberAndForgot(config, primaryColor)}
149
+
150
+ <!-- Error Container (hidden by default) -->
151
+ <div id="error-container" class="hidden">
152
+ <div class="p-3 bg-red-50 border border-red-200 rounded-lg text-red-700 text-sm"></div>
153
+ </div>
154
+ </form>
155
+
156
+ <!-- PreviewButtonGroup: flex gap-3 justify-end -->
157
+ <div class="flex gap-3 justify-end">
158
+ <button
159
+ type="button"
160
+ onclick="window.close()"
161
+ class="font-medium text-sm rounded-lg transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed px-4 py-2.5 h-10 border-[1.5px] bg-transparent"
162
+ style="border-color: ${(0, escape_js_1.escapeAttr)(primaryColor)}; color: ${(0, escape_js_1.escapeAttr)(primaryColor)};"
163
+ >
164
+ ${(0, escape_js_1.escapeHtml)(copy.cancelButtonText)}
165
+ </button>
166
+ <button
167
+ type="submit"
168
+ form="credential-form"
169
+ class="font-medium text-sm rounded-lg transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed px-4 py-3 h-11 text-white"
170
+ style="background-color: ${(0, escape_js_1.escapeAttr)(primaryColor)};"
171
+ >
172
+ Sign in
173
+ </button>
174
+ </div>
175
+ </div>
176
+ </div>
177
+
178
+ ${this.renderModeScript()}
179
+ </body>
180
+ </html>`;
181
+ }
182
+ /**
183
+ * Render the <head> section with meta tags, styles, and scripts.
184
+ */
185
+ renderHead() {
186
+ const { branding } = this.resolved;
187
+ return `
188
+ <meta charset="UTF-8">
189
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
190
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; img-src 'self' data: https:; font-src 'self' data:;">
191
+ <title>${this.getPageTitle()}</title>
192
+ <script src="https://cdn.tailwindcss.com"></script>
193
+ <style>
194
+ ${(0, stylesheet_js_1.generateHeadStyles)(branding)}
195
+ </style>
196
+ `;
197
+ }
198
+ /**
199
+ * Render agent icon SVG (matches AgentIconPlaceholder in AgentShield)
200
+ */
201
+ renderAgentIcon() {
202
+ const logoUrl = this.resolved.branding.logoUrl;
203
+ if (logoUrl) {
204
+ return `<img src="${(0, escape_js_1.escapeAttr)(logoUrl)}" alt="Agent" class="w-full h-full object-contain" />`;
205
+ }
206
+ // Default placeholder icon matching AgentShield exactly
207
+ return `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="text-gray-400">
208
+ <rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" />
209
+ <circle cx="8" cy="8" r="1.5" fill="currentColor" />
210
+ <circle cx="16" cy="8" r="1.5" fill="currentColor" />
211
+ <path d="M8 14s1.5 2 4 2 4-2 4-2" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
212
+ </svg>`;
213
+ }
214
+ /**
215
+ * Render remember me checkbox and forgot password link.
216
+ * The checkbox uses a <label> that wraps everything so clicking toggles.
217
+ */
218
+ renderRememberAndForgot(config, primaryColor) {
219
+ const showRemember = config.showRememberMe !== false;
220
+ const showForgot = config.showForgotPassword === true;
221
+ if (!showRemember && !showForgot)
222
+ return "";
223
+ // Match PreviewCheckbox exactly: custom div with border-2 border-gray-300 bg-white when unchecked
224
+ // When checked: backgroundColor and borderColor set to primaryColor, with white Check icon
225
+ const rememberHtml = showRemember
226
+ ? `
227
+ <div id="remember-label" class="flex items-center gap-3 cursor-pointer select-none" role="button" tabindex="0">
228
+ <div
229
+ id="remember-checkbox"
230
+ class="w-4 h-4 rounded flex items-center justify-center transition-colors border-2 border-gray-300 bg-white"
231
+ role="checkbox"
232
+ aria-checked="false"
233
+ >
234
+ <!-- Checkmark (hidden by default, shown when checked) -->
235
+ <svg id="remember-check" class="w-3 h-3 text-white hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
236
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"></path>
237
+ </svg>
238
+ </div>
239
+ <span class="text-base text-black">Remember me</span>
240
+ <input type="hidden" name="rememberMe" id="rememberMe-input" value="false" />
241
+ </div>
242
+ `
243
+ : "<span></span>";
244
+ const forgotHtml = showForgot
245
+ ? `
246
+ <a href="${(0, escape_js_1.escapeAttr)(config.forgotPasswordUrl || "#")}"
247
+ class="text-sm hover:underline"
248
+ style="color: ${(0, escape_js_1.escapeAttr)(primaryColor)}">
249
+ Forgot password?
250
+ </a>
251
+ `
252
+ : "";
253
+ return `
254
+ <div class="flex items-center justify-between">
255
+ ${rememberHtml}
256
+ ${forgotHtml}
257
+ </div>
258
+ `;
259
+ }
260
+ /**
261
+ * These methods are overridden to prevent base template rendering
262
+ * since we completely override render()
263
+ */
264
+ renderAuthContent() {
265
+ return "";
266
+ }
267
+ renderActionButtons() {
268
+ return "";
269
+ }
270
+ renderTermsSection() {
271
+ return "";
272
+ }
273
+ /**
274
+ * Render mode-specific scripts for password toggle and checkbox
275
+ */
276
+ renderModeScript() {
277
+ // Escape values for safe insertion into JavaScript strings
278
+ // Use replace to escape quotes and backslashes
279
+ const escapeForJs = (str) => str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"');
280
+ const serverUrl = escapeForJs(this.config.serverUrl);
281
+ const projectId = escapeForJs(this.config.projectId);
282
+ const sessionId = escapeForJs(this.config.sessionId);
283
+ const agentDid = escapeForJs(this.config.agentDid);
284
+ const tool = escapeForJs(this.config.tool);
285
+ const scopes = JSON.stringify(this.config.scopes);
286
+ const provider = escapeForJs(this.config.provider || "credentials");
287
+ const primaryColor = escapeForJs(this.resolved.branding.primaryColor);
288
+ return `
289
+ <script>
290
+ (function() {
291
+ // Password visibility toggle
292
+ var toggleBtn = document.getElementById('toggle-password');
293
+ var passwordInput = document.getElementById('password');
294
+ var eyeIcon = document.getElementById('eye-icon');
295
+ var eyeOffIcon = document.getElementById('eye-off-icon');
296
+
297
+ if (toggleBtn && passwordInput) {
298
+ toggleBtn.addEventListener('click', function() {
299
+ var isPassword = passwordInput.type === 'password';
300
+ passwordInput.type = isPassword ? 'text' : 'password';
301
+ eyeIcon.classList.toggle('hidden', isPassword);
302
+ eyeOffIcon.classList.toggle('hidden', !isPassword);
303
+ });
304
+ }
305
+
306
+ // Remember me checkbox toggle
307
+ var rememberLabel = document.getElementById('remember-label');
308
+ var rememberCheckbox = document.getElementById('remember-checkbox');
309
+ var rememberCheck = document.getElementById('remember-check');
310
+ var rememberInput = document.getElementById('rememberMe-input');
311
+ var checkboxColor = '${primaryColor}';
312
+
313
+ if (rememberLabel && rememberCheckbox && rememberCheck) {
314
+ var isChecked = false;
315
+
316
+ rememberLabel.onclick = function() {
317
+ isChecked = !isChecked;
318
+
319
+ if (isChecked) {
320
+ rememberCheckbox.style.backgroundColor = checkboxColor;
321
+ rememberCheckbox.style.borderColor = checkboxColor;
322
+ rememberCheck.classList.remove('hidden');
323
+ } else {
324
+ rememberCheckbox.style.backgroundColor = 'white';
325
+ rememberCheckbox.style.borderColor = '#d1d5db';
326
+ rememberCheck.classList.add('hidden');
327
+ }
328
+
329
+ rememberCheckbox.setAttribute('aria-checked', isChecked.toString());
330
+ if (rememberInput) rememberInput.value = isChecked ? 'true' : 'false';
331
+ };
332
+ }
333
+
334
+ // Form submission
335
+ var form = document.getElementById('credential-form');
336
+ if (!form) return;
337
+
338
+ var formServerUrl = '${serverUrl}';
339
+ var formProjectId = '${projectId}';
340
+ var errorContainer = document.getElementById('error-container');
341
+ var errorDiv = errorContainer ? errorContainer.querySelector('div') : null;
342
+
343
+ form.addEventListener('submit', function(e) {
344
+ e.preventDefault();
345
+
346
+ var submitBtn = document.querySelector('button[type="submit"]');
347
+ var originalText = submitBtn.textContent;
348
+
349
+ if (errorContainer) errorContainer.classList.add('hidden');
350
+
351
+ submitBtn.disabled = true;
352
+ submitBtn.textContent = 'Signing in...';
353
+ submitBtn.style.opacity = '0.7';
354
+
355
+ var formData = new FormData(form);
356
+
357
+ var data = {
358
+ auth_mode: 'credentials',
359
+ provider_type: 'credential',
360
+ provider: '${provider}',
361
+ username: formData.get('username'),
362
+ password: formData.get('password'),
363
+ rememberMe: formData.get('rememberMe') === 'true',
364
+ tool: '${tool}',
365
+ scopes: ${scopes},
366
+ agent_did: '${agentDid}',
367
+ session_id: '${sessionId}',
368
+ project_id: '${projectId}'
369
+ };
370
+
371
+ fetch(formServerUrl + '/consent/approve', {
372
+ method: 'POST',
373
+ headers: { 'Content-Type': 'application/json' },
374
+ body: JSON.stringify(data)
375
+ })
376
+ .then(function(response) { return response.json(); })
377
+ .then(function(result) {
378
+ if (result.success) {
379
+ submitBtn.textContent = 'Success! Redirecting...';
380
+ submitBtn.style.backgroundColor = '#10B981';
381
+
382
+ if (result.redirectUrl) {
383
+ window.location.href = result.redirectUrl;
384
+ } else if (result.delegation_id) {
385
+ window.location.href = formServerUrl + '/consent/success?delegation_id=' +
386
+ encodeURIComponent(result.delegation_id) +
387
+ '&project_id=' + encodeURIComponent(formProjectId);
388
+ }
389
+ } else {
390
+ if (errorDiv) {
391
+ errorDiv.textContent = result.error || 'Authentication failed. Please check your credentials.';
392
+ errorContainer.classList.remove('hidden');
393
+ }
394
+ submitBtn.disabled = false;
395
+ submitBtn.textContent = originalText;
396
+ submitBtn.style.opacity = '1';
397
+ }
398
+ })
399
+ .catch(function(err) {
400
+ if (errorDiv) {
401
+ errorDiv.textContent = 'Network error. Please try again.';
402
+ errorContainer.classList.remove('hidden');
403
+ }
404
+ submitBtn.disabled = false;
405
+ submitBtn.textContent = originalText;
406
+ submitBtn.style.opacity = '1';
407
+ });
408
+ });
409
+ })();
410
+ </script>`;
411
+ }
412
+ }
413
+ exports.CredentialsTemplate = CredentialsTemplate;
414
+ //# sourceMappingURL=credentials.template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.template.js","sourceRoot":"","sources":["../../../../src/templates/modes/credentials.template.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,+DAA+D;AAC/D,wDAAkE;AAClE,8DAAgE;AAIhE,+DAAwD;AAExD;;;;;;;;;;;;;GAaG;AACH,MAAa,mBAAoB,SAAQ,sCAAmB;IAG1D,YACE,MAAiC,EACjC,QAA+B,EAC/B,iBAAqC;QAErC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACxB,IAAI,CAAC,uBAAuB,GAAG,iBAAiB,CAAC;IACnD,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,2BAAU,CAAC,WAAW,CAAC;IAChC,CAAC;IAED,IAAY,iBAAiB;QAC3B,2EAA2E;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,uBAAuB,IAAI,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,IAAI,EAAE,CAAC;QACxD,OAAO;YACL,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,IAAI,UAAU;YACxE,mBAAmB,EACjB,KAAK,CAAC,mBAAmB;gBACzB,MAAM,CAAC,mBAAmB;gBAC1B,qBAAqB;YACvB,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,IAAI,UAAU;YACxE,mBAAmB,EACjB,KAAK,CAAC,mBAAmB;gBACzB,MAAM,CAAC,mBAAmB;gBAC1B,qBAAqB;YACvB,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,IAAI,IAAI;YACrE,kBAAkB,EAChB,KAAK,CAAC,kBAAkB,IAAI,MAAM,CAAC,kBAAkB,IAAI,IAAI;YAC/D,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,MAAM,CAAC,iBAAiB;SACvE,CAAC;IACJ,CAAC;IAED;;;OAGG;IACM,MAAM;QACb,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACtC,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;QAE3C,OAAO;;;IAGP,IAAI,CAAC,UAAU,EAAE;;;;;;kDAM6B,IAAA,sBAAU,EAAC,YAAY,CAAC,0BAA0B,IAAA,sBAAU,EAAC,QAAQ,CAAC,cAAc,CAAC;;;;sDAIjF,IAAA,sBAAU,EAAC,IAAI,CAAC,KAAK,CAAC;;;;;;;;;YAShE,IAAI,CAAC,eAAe,EAAE;;;+DAG6B,IAAA,sBAAU,EAAC,IAAI,CAAC,mBAAmB,CAAC;;;;;;;;cAQrF,IAAA,sBAAU,EAAC,MAAM,CAAC,aAAa,IAAI,UAAU,CAAC;;;;;;2BAMjC,IAAA,sBAAU,EAAC,MAAM,CAAC,mBAAmB,IAAI,qBAAqB,CAAC;;;;;;;;;;cAU5E,IAAA,sBAAU,EAAC,MAAM,CAAC,aAAa,IAAI,UAAU,CAAC;;;;;;;6BAO/B,IAAA,sBAAU,EAAC,MAAM,CAAC,mBAAmB,IAAI,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;UAyBlF,IAAI,CAAC,uBAAuB,CAAC,MAAM,EAAE,YAAY,CAAC;;;;;;;;;;;;;;iCAc3B,IAAA,sBAAU,EAAC,YAAY,CAAC,YAAY,IAAA,sBAAU,EAAC,YAAY,CAAC;;YAEjF,IAAA,sBAAU,EAAC,IAAI,CAAC,gBAAgB,CAAC;;;;;;qCAMR,IAAA,sBAAU,EAAC,YAAY,CAAC;;;;;;;;IAQzD,IAAI,CAAC,gBAAgB,EAAE;;QAEnB,CAAC;IACP,CAAC;IAED;;OAEG;IACgB,UAAU;QAC3B,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QACnC,OAAO;;;;eAII,IAAI,CAAC,YAAY,EAAE;;;UAGxB,IAAA,kCAAkB,EAAC,QAAQ,CAAC;;KAEjC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC/C,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,aAAa,IAAA,sBAAU,EAAC,OAAO,CAAC,uDAAuD,CAAC;QACjG,CAAC;QACD,wDAAwD;QACxD,OAAO;;;;;WAKA,CAAC;IACV,CAAC;IAED;;;OAGG;IACK,uBAAuB,CAC7B,MAAyB,EACzB,YAAoB;QAEpB,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,KAAK,KAAK,CAAC;QACrD,MAAM,UAAU,GAAG,MAAM,CAAC,kBAAkB,KAAK,IAAI,CAAC;QAEtD,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU;YAAE,OAAO,EAAE,CAAC;QAE5C,kGAAkG;QAClG,2FAA2F;QAC3F,MAAM,YAAY,GAAG,YAAY;YAC/B,CAAC,CAAC;;;;;;;;;;;;;;;;KAgBH;YACC,CAAC,CAAC,eAAe,CAAC;QAEpB,MAAM,UAAU,GAAG,UAAU;YAC3B,CAAC,CAAC;iBACS,IAAA,sBAAU,EAAC,MAAM,CAAC,iBAAiB,IAAI,GAAG,CAAC;;yBAEnC,IAAA,sBAAU,EAAC,YAAY,CAAC;;;KAG5C;YACC,CAAC,CAAC,EAAE,CAAC;QAEP,OAAO;;UAED,YAAY;UACZ,UAAU;;KAEf,CAAC;IACJ,CAAC;IAED;;;OAGG;IACM,iBAAiB;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAEkB,mBAAmB;QACpC,OAAO,EAAE,CAAC;IACZ,CAAC;IAEkB,kBAAkB;QACnC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;OAEG;IACgB,gBAAgB;QACjC,2DAA2D;QAC3D,+CAA+C;QAC/C,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE,CAClC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAEvE,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,aAAa,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAEtE,OAAO;;;;;;;;;;;;;;;;;;;;;;;yBAuBc,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA2BZ,SAAS;yBACT,SAAS;;;;;;;;;;;;;;;;;;;;;mBAqBf,QAAQ;;;;eAIZ,IAAI;gBACH,MAAM;oBACF,QAAQ;qBACP,SAAS;qBACT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA0CpB,CAAC;IACT,CAAC;CACF;AAxZD,kDAwZC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * Mode Templates Index
4
+ *
5
+ * Re-exports all authentication mode templates.
6
+ *
7
+ * @module @kya-os/consent/templates/modes
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.renderSuccessPage = exports.SuccessTemplate = exports.OTPTemplate = exports.MagicLinkTemplate = exports.OAuthTemplate = exports.CredentialsTemplate = exports.ConsentOnlyTemplate = void 0;
11
+ var consent_only_template_js_1 = require("./consent-only.template.js");
12
+ Object.defineProperty(exports, "ConsentOnlyTemplate", { enumerable: true, get: function () { return consent_only_template_js_1.ConsentOnlyTemplate; } });
13
+ var credentials_template_js_1 = require("./credentials.template.js");
14
+ Object.defineProperty(exports, "CredentialsTemplate", { enumerable: true, get: function () { return credentials_template_js_1.CredentialsTemplate; } });
15
+ var oauth_template_js_1 = require("./oauth.template.js");
16
+ Object.defineProperty(exports, "OAuthTemplate", { enumerable: true, get: function () { return oauth_template_js_1.OAuthTemplate; } });
17
+ var magic_link_template_js_1 = require("./magic-link.template.js");
18
+ Object.defineProperty(exports, "MagicLinkTemplate", { enumerable: true, get: function () { return magic_link_template_js_1.MagicLinkTemplate; } });
19
+ var otp_template_js_1 = require("./otp.template.js");
20
+ Object.defineProperty(exports, "OTPTemplate", { enumerable: true, get: function () { return otp_template_js_1.OTPTemplate; } });
21
+ var success_template_js_1 = require("./success.template.js");
22
+ Object.defineProperty(exports, "SuccessTemplate", { enumerable: true, get: function () { return success_template_js_1.SuccessTemplate; } });
23
+ Object.defineProperty(exports, "renderSuccessPage", { enumerable: true, get: function () { return success_template_js_1.renderSuccessPage; } });
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/templates/modes/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,uEAAiE;AAAxD,+HAAA,mBAAmB,OAAA;AAC5B,qEAAgE;AAAvD,8HAAA,mBAAmB,OAAA;AAC5B,yDAAoD;AAA3C,kHAAA,aAAa,OAAA;AACtB,mEAA6D;AAApD,2HAAA,iBAAiB,OAAA;AAC1B,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AACpB,6DAA2E;AAAlE,sHAAA,eAAe,OAAA;AAAE,wHAAA,iBAAiB,OAAA"}
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ /**
3
+ * Magic Link Template
4
+ *
5
+ * Passwordless authentication via email link.
6
+ *
7
+ * @module @kya-os/consent/templates/modes/magic-link
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.MagicLinkTemplate = void 0;
11
+ const base_template_js_1 = require("../base/base-template.js");
12
+ const components_js_1 = require("../base/components.js");
13
+ const escape_js_1 = require("../../security/escape.js");
14
+ const modes_types_js_1 = require("../../types/modes.types.js");
15
+ /**
16
+ * Magic Link Template
17
+ *
18
+ * Renders an email-based passwordless login:
19
+ * - Email input field
20
+ * - Submit button
21
+ * - Success/waiting state
22
+ * - Resend link functionality
23
+ */
24
+ class MagicLinkTemplate extends base_template_js_1.BaseConsentTemplate {
25
+ get authMode() {
26
+ return modes_types_js_1.AUTH_MODES.MAGIC_LINK;
27
+ }
28
+ get magicLinkConfig() {
29
+ return this.config.modeConfig?.magicLink;
30
+ }
31
+ renderAuthContent() {
32
+ const config = this.magicLinkConfig;
33
+ return `
34
+ <div id="magic-link-form-container">
35
+ <form id="magic-link-form" class="space-y-4">
36
+ ${this.renderEmailField(config)}
37
+ ${(0, components_js_1.renderErrorContainer)()}
38
+ ${(0, components_js_1.renderFullWidthButton)(config?.buttonText || "Send Magic Link", "submit")}
39
+ </form>
40
+ </div>
41
+ <div id="magic-link-sent" class="hidden text-center py-4 space-y-4">
42
+ <div class="w-16 h-16 mx-auto rounded-full bg-green-100 flex items-center justify-center">
43
+ <svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
44
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
45
+ </svg>
46
+ </div>
47
+ <h3 class="text-lg font-semibold text-gray-900">Check your email</h3>
48
+ <p class="text-sm text-gray-600">
49
+ We've sent a magic link to <span id="sent-email" class="font-medium"></span>.<br/>
50
+ Click the link to continue.
51
+ </p>
52
+ <button type="button" id="resend-btn" class="text-sm link-primary mt-4 disabled:opacity-50">
53
+ Resend link
54
+ </button>
55
+ </div>
56
+ `;
57
+ }
58
+ /**
59
+ * Render email input field.
60
+ */
61
+ renderEmailField(config) {
62
+ return (0, components_js_1.renderInput)("email", "email", config?.emailLabel || "Email address", config?.emailPlaceholder || "Enter your email", true, "email");
63
+ }
64
+ /**
65
+ * Override action buttons - form has its own submit.
66
+ */
67
+ renderActionButtons() {
68
+ return "";
69
+ }
70
+ renderModeScript() {
71
+ const serverUrl = (0, escape_js_1.escapeJs)(this.config.serverUrl);
72
+ const projectId = (0, escape_js_1.escapeJs)(this.config.projectId);
73
+ const sessionId = (0, escape_js_1.escapeJs)(this.config.sessionId);
74
+ const agentDid = (0, escape_js_1.escapeJs)(this.config.agentDid);
75
+ const tool = (0, escape_js_1.escapeJs)(this.config.tool);
76
+ const scopes = JSON.stringify(this.config.scopes);
77
+ const resendCooldown = this.magicLinkConfig?.resendCooldown || 60;
78
+ return `
79
+ <script>
80
+ (function() {
81
+ const form = document.getElementById('magic-link-form');
82
+ const formContainer = document.getElementById('magic-link-form-container');
83
+ const sentContainer = document.getElementById('magic-link-sent');
84
+ const sentEmail = document.getElementById('sent-email');
85
+ const resendBtn = document.getElementById('resend-btn');
86
+ const errorContainer = document.getElementById('error-container');
87
+ const errorDiv = errorContainer?.querySelector('div');
88
+
89
+ if (!form) return;
90
+
91
+ const serverUrl = ${serverUrl};
92
+ const cooldown = ${resendCooldown};
93
+ let lastEmail = '';
94
+ let resendTimer = null;
95
+
96
+ async function sendMagicLink(email) {
97
+ const data = {
98
+ provider_type: 'magic_link',
99
+ email: email,
100
+ tool: ${tool},
101
+ scopes: ${scopes},
102
+ agent_did: ${agentDid},
103
+ session_id: ${sessionId},
104
+ project_id: ${projectId},
105
+ };
106
+
107
+ const response = await fetch(serverUrl + '/consent/magic-link', {
108
+ method: 'POST',
109
+ headers: { 'Content-Type': 'application/json' },
110
+ body: JSON.stringify(data)
111
+ });
112
+
113
+ return response.json();
114
+ }
115
+
116
+ function showSent(email) {
117
+ formContainer.classList.add('hidden');
118
+ sentContainer.classList.remove('hidden');
119
+ sentEmail.textContent = email;
120
+
121
+ // Start cooldown
122
+ resendBtn.disabled = true;
123
+ let remaining = cooldown;
124
+ resendBtn.textContent = 'Resend link (' + remaining + 's)';
125
+
126
+ resendTimer = setInterval(() => {
127
+ remaining--;
128
+ if (remaining <= 0) {
129
+ clearInterval(resendTimer);
130
+ resendBtn.disabled = false;
131
+ resendBtn.textContent = 'Resend link';
132
+ } else {
133
+ resendBtn.textContent = 'Resend link (' + remaining + 's)';
134
+ }
135
+ }, 1000);
136
+ }
137
+
138
+ function showError(message) {
139
+ if (errorDiv) {
140
+ errorDiv.textContent = message;
141
+ errorContainer.classList.remove('hidden');
142
+ }
143
+ }
144
+
145
+ form.addEventListener('submit', async function(e) {
146
+ e.preventDefault();
147
+
148
+ const button = form.querySelector('button[type="submit"]');
149
+ const originalText = button.textContent;
150
+ const emailInput = form.querySelector('input[name="email"]');
151
+ lastEmail = emailInput.value;
152
+
153
+ if (errorContainer) errorContainer.classList.add('hidden');
154
+ button.disabled = true;
155
+ button.textContent = 'Sending...';
156
+
157
+ try {
158
+ const result = await sendMagicLink(lastEmail);
159
+
160
+ if (result.success) {
161
+ showSent(lastEmail);
162
+ } else {
163
+ showError(result.error || 'Failed to send magic link');
164
+ button.disabled = false;
165
+ button.textContent = originalText;
166
+ }
167
+ } catch (err) {
168
+ showError('Network error. Please try again.');
169
+ button.disabled = false;
170
+ button.textContent = originalText;
171
+ }
172
+ });
173
+
174
+ resendBtn?.addEventListener('click', async function() {
175
+ if (!lastEmail || resendBtn.disabled) return;
176
+
177
+ resendBtn.disabled = true;
178
+ try {
179
+ const result = await sendMagicLink(lastEmail);
180
+ if (result.success) {
181
+ showSent(lastEmail);
182
+ } else {
183
+ alert(result.error || 'Failed to resend');
184
+ resendBtn.disabled = false;
185
+ }
186
+ } catch (err) {
187
+ alert('Network error');
188
+ resendBtn.disabled = false;
189
+ }
190
+ });
191
+ })();
192
+ </script>`;
193
+ }
194
+ }
195
+ exports.MagicLinkTemplate = MagicLinkTemplate;
196
+ //# sourceMappingURL=magic-link.template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-link.template.js","sourceRoot":"","sources":["../../../../src/templates/modes/magic-link.template.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,+DAA+D;AAC/D,yDAI+B;AAC/B,wDAAoD;AAEpD,+DAAwD;AAExD;;;;;;;;GAQG;AACH,MAAa,iBAAkB,SAAQ,sCAAmB;IACxD,IAAI,QAAQ;QACV,OAAO,2BAAU,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,IAAY,eAAe;QACzB,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC;IAC3C,CAAC;IAEQ,iBAAiB;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC;QAEpC,OAAO;;;YAGC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;YAC7B,IAAA,oCAAoB,GAAE;YACtB,IAAA,qCAAqB,EAAC,MAAM,EAAE,UAAU,IAAI,iBAAiB,EAAE,QAAQ,CAAC;;;;;;;;;;;;;;;;;;KAkB/E,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,MAAwB;QAC/C,OAAO,IAAA,2BAAW,EAChB,OAAO,EACP,OAAO,EACP,MAAM,EAAE,UAAU,IAAI,eAAe,EACrC,MAAM,EAAE,gBAAgB,IAAI,kBAAkB,EAC9C,IAAI,EACJ,OAAO,CACR,CAAC;IACJ,CAAC;IAED;;OAEG;IACgB,mBAAmB;QACpC,OAAO,EAAE,CAAC;IACZ,CAAC;IAEkB,gBAAgB;QACjC,MAAM,SAAS,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,EAAE,cAAc,IAAI,EAAE,CAAC;QAElE,OAAO;;;;;;;;;;;;;sBAaW,SAAS;qBACV,cAAc;;;;;;;;cAQrB,IAAI;gBACF,MAAM;mBACH,QAAQ;oBACP,SAAS;oBACT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAwFnB,CAAC;IACT,CAAC;CACF;AAxLD,8CAwLC"}