@epicdm/flowstate-auth-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,501 @@
1
+ // src/styles.ts
2
+ var BRAND_CSS = `
3
+ /* --- Reset --- */
4
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
5
+
6
+ /* --- Theme variables --- */
7
+ :root{
8
+ --fs-brand:#00c3ff;
9
+ --fs-brand-light:#4dd8ff;
10
+ --fs-brand-dark:#0088cc;
11
+ --fs-bg:#f8fafc;
12
+ --fs-card-bg:#fff;
13
+ --fs-card-border:1px solid #e2e8f0;
14
+ --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.08);
15
+ --fs-text:#0f172a;
16
+ --fs-text-secondary:#475569;
17
+ --fs-muted:#94a3b8;
18
+ --fs-border:#e2e8f0;
19
+ --fs-input-bg:#fff;
20
+ --fs-input-border:#cbd5e1;
21
+ --fs-input-focus:#00c3ff;
22
+ --fs-footer-bg:#f1f5f9;
23
+ --fs-footer-border:#e2e8f0;
24
+ --fs-error:#dc2626;
25
+ --fs-error-bg:#fef2f2;
26
+ --fs-success:#16a34a;
27
+ --fs-success-bg:#f0fdf4;
28
+ --fs-logo-text:#0f172a;
29
+ --fs-header-bg:rgba(255,255,255,.8);
30
+ }
31
+ @media(prefers-color-scheme:dark){
32
+ :root:not([data-theme="light"]){
33
+ --fs-bg:#0f172a;
34
+ --fs-card-bg:#1e293b;
35
+ --fs-card-border:1px solid #334155;
36
+ --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.3);
37
+ --fs-text:#e2e8f0;
38
+ --fs-text-secondary:#94a3b8;
39
+ --fs-muted:#64748b;
40
+ --fs-border:#334155;
41
+ --fs-input-bg:#0f172a;
42
+ --fs-input-border:#475569;
43
+ --fs-input-focus:#00c3ff;
44
+ --fs-footer-bg:#020617;
45
+ --fs-footer-border:#1e293b;
46
+ --fs-error:#ef4444;
47
+ --fs-error-bg:rgba(239,68,68,.12);
48
+ --fs-success:#22c55e;
49
+ --fs-success-bg:rgba(0,195,255,.12);
50
+ --fs-logo-text:#e2e8f0;
51
+ --fs-header-bg:rgba(15,23,42,.8);
52
+ }
53
+ }
54
+ [data-theme="dark"]{
55
+ --fs-bg:#0f172a;
56
+ --fs-card-bg:#1e293b;
57
+ --fs-card-border:1px solid #334155;
58
+ --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.3);
59
+ --fs-text:#e2e8f0;
60
+ --fs-text-secondary:#94a3b8;
61
+ --fs-muted:#64748b;
62
+ --fs-border:#334155;
63
+ --fs-input-bg:#0f172a;
64
+ --fs-input-border:#475569;
65
+ --fs-input-focus:#00c3ff;
66
+ --fs-footer-bg:#020617;
67
+ --fs-footer-border:#1e293b;
68
+ --fs-error:#ef4444;
69
+ --fs-error-bg:rgba(239,68,68,.12);
70
+ --fs-success:#22c55e;
71
+ --fs-success-bg:rgba(0,195,255,.12);
72
+ --fs-logo-text:#e2e8f0;
73
+ --fs-header-bg:rgba(15,23,42,.8);
74
+ }
75
+ [data-theme="light"]{
76
+ --fs-bg:#f8fafc;
77
+ --fs-card-bg:#fff;
78
+ --fs-card-border:1px solid #e2e8f0;
79
+ --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.08);
80
+ --fs-text:#0f172a;
81
+ --fs-text-secondary:#475569;
82
+ --fs-muted:#94a3b8;
83
+ --fs-border:#e2e8f0;
84
+ --fs-input-bg:#fff;
85
+ --fs-input-border:#cbd5e1;
86
+ --fs-input-focus:#00c3ff;
87
+ --fs-footer-bg:#f1f5f9;
88
+ --fs-footer-border:#e2e8f0;
89
+ --fs-error:#dc2626;
90
+ --fs-error-bg:#fef2f2;
91
+ --fs-success:#16a34a;
92
+ --fs-success-bg:#f0fdf4;
93
+ --fs-logo-text:#0f172a;
94
+ --fs-header-bg:rgba(255,255,255,.8);
95
+ }
96
+
97
+ /* --- Base --- */
98
+ body{
99
+ font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
100
+ background:var(--fs-bg);
101
+ color:var(--fs-text);
102
+ min-height:100vh;
103
+ display:flex;
104
+ flex-direction:column;
105
+ transition:background .2s,color .2s;
106
+ }
107
+ a{color:var(--fs-muted);text-decoration:none;transition:color .15s}
108
+ a:hover{color:var(--fs-text)}
109
+
110
+ /* --- Header --- */
111
+ .fs-header{
112
+ position:sticky;top:0;z-index:50;
113
+ display:flex;align-items:center;justify-content:space-between;
114
+ padding:16px 32px;
115
+ background:var(--fs-header-bg);
116
+ backdrop-filter:blur(8px);
117
+ -webkit-backdrop-filter:blur(8px);
118
+ }
119
+ .fs-header-left{display:flex;align-items:center;gap:32px}
120
+ .fs-header-left svg{color:var(--fs-logo-text)}
121
+ .fs-header-right{display:flex;align-items:center;gap:16px}
122
+ .fs-nav-link{font-size:14px;color:var(--fs-muted);transition:color .15s}
123
+ .fs-nav-link:hover{color:var(--fs-text)}
124
+
125
+ /* --- Theme toggle --- */
126
+ .fs-theme-toggle{
127
+ background:none;border:1px solid var(--fs-border);
128
+ border-radius:8px;padding:6px 8px;cursor:pointer;
129
+ color:var(--fs-muted);display:flex;align-items:center;gap:4px;
130
+ transition:color .15s,border-color .15s;
131
+ font-size:12px;
132
+ }
133
+ .fs-theme-toggle:hover{color:var(--fs-text);border-color:var(--fs-muted)}
134
+ .fs-theme-toggle .sun{display:none}
135
+ .fs-theme-toggle .moon{display:inline-flex}
136
+ [data-theme="dark"] .fs-theme-toggle .sun{display:inline-flex}
137
+ [data-theme="dark"] .fs-theme-toggle .moon{display:none}
138
+ @media(prefers-color-scheme:dark){
139
+ :root:not([data-theme="light"]) .fs-theme-toggle .sun{display:inline-flex}
140
+ :root:not([data-theme="light"]) .fs-theme-toggle .moon{display:none}
141
+ }
142
+ [data-theme="light"] .fs-theme-toggle .sun{display:none}
143
+ [data-theme="light"] .fs-theme-toggle .moon{display:inline-flex}
144
+
145
+ /* --- Main content --- */
146
+ .fs-main{flex:1;display:flex;align-items:center;justify-content:center;padding:24px 16px}
147
+
148
+ /* --- Card --- */
149
+ .fs-card{
150
+ width:100%;max-width:448px;padding:32px;
151
+ background:var(--fs-card-bg);
152
+ border:var(--fs-card-border);
153
+ border-radius:12px;
154
+ box-shadow:var(--fs-card-shadow);
155
+ }
156
+ .fs-card h1{font-size:24px;font-weight:700;color:var(--fs-text);margin-bottom:8px;text-align:center}
157
+ .fs-card .fs-subtitle{font-size:14px;color:var(--fs-text-secondary);text-align:center;margin-bottom:24px;line-height:1.6}
158
+ .fs-card p{font-size:14px;color:var(--fs-text-secondary);line-height:1.6}
159
+
160
+ /* --- Card status icons --- */
161
+ .fs-status-icon{
162
+ margin:0 auto 24px;width:64px;height:64px;border-radius:50%;
163
+ display:flex;align-items:center;justify-content:center;
164
+ }
165
+ .fs-status-icon.success{background:var(--fs-success-bg)}
166
+ .fs-status-icon.error{background:var(--fs-error-bg)}
167
+ .fs-status-icon svg{width:32px;height:32px}
168
+ .fs-card .fs-action{margin-top:24px;font-size:13px;color:var(--fs-muted);text-align:center}
169
+
170
+ /* --- Client info badge --- */
171
+ .fs-client-info{
172
+ background:var(--fs-bg);border:1px solid var(--fs-border);
173
+ border-radius:8px;padding:12px;margin-bottom:24px;text-align:center;
174
+ font-size:14px;color:var(--fs-text-secondary);
175
+ }
176
+ .fs-client-info strong{color:var(--fs-brand);font-weight:600}
177
+
178
+ /* --- Forms --- */
179
+ .fs-form{display:flex;flex-direction:column;gap:16px}
180
+ .fs-form label{font-weight:500;color:var(--fs-text);font-size:14px}
181
+ .fs-form input[type="email"],
182
+ .fs-form input[type="text"]{
183
+ width:100%;padding:12px 16px;
184
+ background:var(--fs-input-bg);
185
+ border:2px solid var(--fs-input-border);
186
+ border-radius:8px;font-size:16px;
187
+ color:var(--fs-text);
188
+ transition:border-color .2s;
189
+ }
190
+ .fs-form input::placeholder{color:var(--fs-muted)}
191
+ .fs-form input:focus{outline:none;border-color:var(--fs-input-focus)}
192
+ .fs-btn{
193
+ background:var(--fs-brand);color:#fff;border:none;
194
+ padding:14px;border-radius:8px;font-size:16px;font-weight:600;
195
+ cursor:pointer;transition:background .2s;width:100%;
196
+ }
197
+ .fs-btn:hover{background:var(--fs-brand-dark)}
198
+ .fs-btn:disabled{opacity:.5;cursor:not-allowed}
199
+ .fs-error-text{color:var(--fs-error);font-size:14px;text-align:center}
200
+ .fs-success-text{color:var(--fs-success);font-size:14px;text-align:center}
201
+ .fs-back-link{text-align:center;margin-top:16px}
202
+ .fs-back-link a{color:var(--fs-brand);font-size:14px}
203
+ .fs-back-link a:hover{color:var(--fs-brand-light)}
204
+
205
+ /* --- Footer --- */
206
+ .fs-footer{background:var(--fs-footer-bg);padding:48px 32px;transition:background .2s}
207
+ .fs-footer-grid{
208
+ max-width:1280px;margin:0 auto;
209
+ display:grid;grid-template-columns:repeat(4,1fr);gap:32px;
210
+ }
211
+ @media(max-width:768px){.fs-footer-grid{grid-template-columns:repeat(2,1fr)}}
212
+ @media(max-width:480px){.fs-footer-grid{grid-template-columns:1fr}}
213
+ .fs-footer-col h3{
214
+ font-size:12px;font-weight:600;text-transform:uppercase;
215
+ letter-spacing:.05em;color:var(--fs-text);margin-bottom:16px;
216
+ }
217
+ .fs-footer-col ul{list-style:none}
218
+ .fs-footer-col li{margin-bottom:12px}
219
+ .fs-footer-col a{font-size:14px;color:var(--fs-muted)}
220
+ .fs-footer-bottom{
221
+ max-width:1280px;margin:0 auto;
222
+ display:flex;align-items:center;justify-content:space-between;
223
+ border-top:1px solid var(--fs-footer-border);
224
+ padding-top:32px;margin-top:48px;
225
+ }
226
+ .fs-footer-bottom-left{display:flex;align-items:center;gap:12px}
227
+ .fs-footer-bottom p{font-size:14px;color:var(--fs-muted)}
228
+ `;
229
+
230
+ // src/brand.ts
231
+ var ICON_SVG = `<svg aria-hidden="true" viewBox="0 0 36 36" fill="none" style="height:36px;width:36px"><g fill="none" stroke-linejoin="round" stroke-width="3"><path d="M10.308 5L18 17.5 10.308 30 2.615 17.5 10.308 5z" stroke="var(--fs-brand,#00c3ff)"/><path d="M18 17.5L10.308 5h15.144l7.933 12.5M18 17.5h15.385L25.452 30H10.308L18 17.5z" stroke="var(--fs-brand-dark,#0088cc)"/></g></svg>`;
232
+ var LOGO_SVG = `<svg aria-label="Epic FlowState" viewBox="0 0 4000 594.516" style="height:36px;width:auto"><g id="icon"><path d="M 0,0 -90.883,157.413 H 64.324 c 16.382,0 31.646,-8.812 39.835,-23 L 181.764,0 Z" fill="#4dd8ff" transform="matrix(1.333,0,0,-1.333,349.797,271.737)"/><path d="M 0,0 90.883,157.413 H 272.647 L 195.044,22.999 C 186.853,8.812 171.589,0 155.206,0 Z" fill="#0088cc" transform="matrix(1.333,0,0,-1.333,228.62,532.663)"/><path d="M 0,0 C -8.189,14.188 -8.189,31.815 0.002,46.002 L 77.605,180.416 168.488,23.001 77.605,-134.413 Z" fill="#00c3ff" transform="matrix(1.333,0,0,-1.333,80.942,327.926)"/></g><g id="text" fill="currentColor"><path d="M 0,0 H -116.758 V -28.172 H -83.377 0 c 28.481,0 49.92,-10.106 49.92,-43.792 0,-33.991 -20.212,-44.404 -50.224,-44.71 h -83.073 -6.534 c -14.828,0 -26.847,-12.02 -26.847,-26.847 v -71.149 h 33.381 v 69.823 h 82.769 c 45.932,0 84.213,22.66 84.213,72.883 C 83.605,-23.273 48.998,0 0,0" transform="matrix(1.333,0,0,-1.333,1657.659,148.441)"/><path d="M 0,0 H 95.263 V -28.785 H 60.661 -0.613 c -44.711,0 -72.883,-35.218 -72.883,-80.233 0,-45.018 28.785,-77.479 72.883,-77.479 h 61.274 34.602 v -28.479 H 0 c -63.697,0 -106.573,46.241 -106.877,107.488 C -106.877,-46.241 -63.393,0 0,0" transform="matrix(1.333,0,0,-1.333,2341.873,148.032)"/><path d="M 0,0 H -79.658 V -28.785 H 151.629 V 0 Z" transform="matrix(1.333,0,0,-1.333,1085.02,396.287)"/><path d="m 0,0 v -27.868 h 79.658 83.134 V 0 H 79.658 Z" transform="matrix(1.333,0,0,-1.333,978.809,273.382)"/><path d="m 734.107,305.464 h 231.287 v 28.785 H 734.107 Z" transform="matrix(1.333,0,0,-1.333,0,594.516)"/><path d="m 1475.135,119.887 h 33.381 V 334.25 h -33.381 z" transform="matrix(1.333,0,0,-1.333,0,594.516)"/><rect x="2650" y="140" width="8" height="320" opacity="0.3"/><text x="2850" y="405" font-family="system-ui,-apple-system,sans-serif" font-size="285" font-weight="300">Flowstate</text></g></svg>`;
233
+ var GITHUB_SVG = `<svg aria-hidden="true" viewBox="0 0 16 16" style="height:20px;width:20px;fill:var(--fs-muted,#94a3b8)"><path d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"/></svg>`;
234
+ var SUN_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>`;
235
+ var MOON_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>`;
236
+
237
+ // src/shell.ts
238
+ function pageShell(options) {
239
+ const year = (/* @__PURE__ */ new Date()).getFullYear();
240
+ const themeToggle = options.hideThemeToggle ? "" : `<button class="fs-theme-toggle" id="fs-theme-toggle" aria-label="Toggle theme" title="Toggle light/dark mode">
241
+ <span class="sun">${SUN_SVG}</span>
242
+ <span class="moon">${MOON_SVG}</span>
243
+ </button>`;
244
+ const footerContent = options.compactFooter ? `<div class="fs-footer-bottom" style="border:none;padding-top:0;margin-top:0">
245
+ <div class="fs-footer-bottom-left">
246
+ ${ICON_SVG}
247
+ <p>&copy; ${year} Epic Digital Interactive Media LLC</p>
248
+ </div>
249
+ <a href="https://github.com/epicdm/epic-flowstate" aria-label="GitHub">${GITHUB_SVG}</a>
250
+ </div>` : `<div class="fs-footer-grid">
251
+ <div class="fs-footer-col"><h3>Services</h3><ul>
252
+ <li><a href="https://marketplace.epicflowstate.ai">Marketplace</a></li>
253
+ <li><a href="https://cloud.epicflowstate.ai">Cloud Dashboard</a></li>
254
+ <li><a href="https://docs.epicflowstate.ai">Documentation</a></li>
255
+ <li><a href="https://agents.epicflowstate.ai">Agent Directory</a></li>
256
+ <li><a href="https://dojo.epicflowstate.ai">Dojo</a></li>
257
+ <li><a href="https://compliance.epicflowstate.ai">Compliance</a></li>
258
+ </ul></div>
259
+ <div class="fs-footer-col"><h3>Resources</h3><ul>
260
+ <li><a href="https://epicflowstate.ai/blog">Blog</a></li>
261
+ <li><a href="https://docs.epicflowstate.ai/api">API Reference</a></li>
262
+ <li><a href="https://epicflowstate.ai/status">Status</a></li>
263
+ <li><a href="https://epicflowstate.ai/changelog">Changelog</a></li>
264
+ </ul></div>
265
+ <div class="fs-footer-col"><h3>Company</h3><ul>
266
+ <li><a href="https://epicflowstate.ai/about">About</a></li>
267
+ <li><a href="https://epicflowstate.ai/contact">Contact</a></li>
268
+ <li><a href="https://epicflowstate.ai/partners">Partners</a></li>
269
+ </ul></div>
270
+ <div class="fs-footer-col"><h3>Legal</h3><ul>
271
+ <li><a href="https://epicflowstate.ai/privacy">Privacy Policy</a></li>
272
+ <li><a href="https://epicflowstate.ai/terms">Terms of Service</a></li>
273
+ <li><a href="https://epicflowstate.ai/cookies">Cookie Policy</a></li>
274
+ </ul></div>
275
+ </div>
276
+ <div class="fs-footer-bottom">
277
+ <div class="fs-footer-bottom-left">
278
+ ${ICON_SVG}
279
+ <p>&copy; ${year} Epic Digital Interactive Media LLC</p>
280
+ </div>
281
+ <a href="https://github.com/epicdm/epic-flowstate" aria-label="GitHub">${GITHUB_SVG}</a>
282
+ </div>`;
283
+ const themeJs = options.hideThemeToggle ? "" : `<script>
284
+ (function(){
285
+ var btn=document.getElementById('fs-theme-toggle');
286
+ if(!btn)return;
287
+ var stored=localStorage.getItem('fs-theme');
288
+ if(stored)document.documentElement.setAttribute('data-theme',stored);
289
+ btn.addEventListener('click',function(){
290
+ var current=document.documentElement.getAttribute('data-theme');
291
+ var isDark=current==='dark'||(!current&&window.matchMedia('(prefers-color-scheme:dark)').matches);
292
+ var next=isDark?'light':'dark';
293
+ document.documentElement.setAttribute('data-theme',next);
294
+ localStorage.setItem('fs-theme',next);
295
+ });
296
+ })();
297
+ </script>`;
298
+ return `<!DOCTYPE html>
299
+ <html lang="en">
300
+ <head>
301
+ <meta charset="utf-8">
302
+ <meta name="viewport" content="width=device-width,initial-scale=1">
303
+ <title>${escapeHtml(options.title)}</title>
304
+ <style>${BRAND_CSS}${options.extraCss ?? ""}</style>
305
+ <script>
306
+ (function(){var t=localStorage.getItem('fs-theme');if(t)document.documentElement.setAttribute('data-theme',t)})();
307
+ </script>
308
+ </head>
309
+ <body>
310
+ <header class="fs-header">
311
+ <div class="fs-header-left">
312
+ ${LOGO_SVG}
313
+ <a class="fs-nav-link" href="https://id.epicflowstate.ai">Identity</a>
314
+ </div>
315
+ <div class="fs-header-right">
316
+ ${themeToggle}
317
+ <a href="https://github.com/epicdm/epic-flowstate" aria-label="GitHub">
318
+ <svg aria-hidden="true" viewBox="0 0 16 16" style="height:24px;width:24px;fill:var(--fs-muted,#94a3b8)"><path d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"/></svg>
319
+ </a>
320
+ </div>
321
+ </header>
322
+ <main class="fs-main">
323
+ <div class="fs-card">
324
+ ${options.body}
325
+ </div>
326
+ </main>
327
+ <footer class="fs-footer">
328
+ ${footerContent}
329
+ </footer>
330
+ ${themeJs}
331
+ ${options.extraJs ?? ""}
332
+ </body>
333
+ </html>`;
334
+ }
335
+ function escapeHtml(str) {
336
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
337
+ }
338
+
339
+ // src/pages.ts
340
+ function callbackSuccessPage() {
341
+ return pageShell({
342
+ title: "FlowState CLI \u2013 Login Successful",
343
+ body: `
344
+ <div class="fs-status-icon success">
345
+ <svg viewBox="0 0 24 24" fill="none" stroke="var(--fs-success)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
346
+ <polyline points="20 6 9 17 4 12"/>
347
+ </svg>
348
+ </div>
349
+ <h1>Login Successful</h1>
350
+ <p style="text-align:center">You have been authenticated with FlowState CLI.</p>
351
+ <p class="fs-action">You may close this window and return to your terminal.</p>`
352
+ });
353
+ }
354
+ function callbackErrorPage(message) {
355
+ return pageShell({
356
+ title: "FlowState CLI \u2013 Login Failed",
357
+ body: `
358
+ <div class="fs-status-icon error">
359
+ <svg viewBox="0 0 24 24" fill="none" stroke="var(--fs-error)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
360
+ <circle cx="12" cy="12" r="10"/>
361
+ <line x1="15" y1="9" x2="9" y2="15"/>
362
+ <line x1="9" y1="9" x2="15" y2="15"/>
363
+ </svg>
364
+ </div>
365
+ <h1>Login Failed</h1>
366
+ <p style="text-align:center">${escapeHtml(message)}</p>
367
+ <p class="fs-action">Close this window and try again from your terminal.</p>`
368
+ });
369
+ }
370
+ function authorizePage(params) {
371
+ const safeParams = JSON.stringify({
372
+ clientId: params.clientId,
373
+ redirectUri: params.redirectUri,
374
+ codeChallenge: params.codeChallenge,
375
+ codeChallengeMethod: params.codeChallengeMethod,
376
+ state: params.state ?? "",
377
+ scope: params.scope
378
+ });
379
+ return pageShell({
380
+ title: "FlowState \u2013 Sign In",
381
+ body: `
382
+ <h1>Sign in to FlowState</h1>
383
+ <p class="fs-subtitle">Verify your email to continue</p>
384
+
385
+ <div class="fs-client-info">
386
+ <strong>${escapeHtml(params.clientName || params.clientId)}</strong> wants to access your account
387
+ </div>
388
+
389
+ <div id="email-section">
390
+ <form id="email-form" class="fs-form">
391
+ <div>
392
+ <label for="email">Email address</label>
393
+ <input type="email" id="email" name="email" required placeholder="you@example.com">
394
+ </div>
395
+ <button type="submit" id="email-btn" class="fs-btn">Send verification code</button>
396
+ <p class="fs-error-text" id="email-error"></p>
397
+ </form>
398
+ </div>
399
+
400
+ <div id="verify-section" style="display:none">
401
+ <form id="verify-form" class="fs-form">
402
+ <p class="fs-success-text">Check your email for the verification code</p>
403
+ <div>
404
+ <label for="code">Verification code</label>
405
+ <input type="text" id="code" name="code" required placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric">
406
+ </div>
407
+ <button type="submit" id="verify-btn" class="fs-btn">Sign in</button>
408
+ <p class="fs-error-text" id="verify-error"></p>
409
+ <div class="fs-back-link">
410
+ <a href="#" id="back-link">Use a different email</a>
411
+ </div>
412
+ </form>
413
+ </div>`,
414
+ extraJs: `<script>
415
+ var oauthParams = ${safeParams};
416
+ var userEmail = '';
417
+
418
+ document.getElementById('email-form').addEventListener('submit', function(e) {
419
+ e.preventDefault();
420
+ var email = document.getElementById('email').value;
421
+ var btn = document.getElementById('email-btn');
422
+ var error = document.getElementById('email-error');
423
+
424
+ btn.disabled = true;
425
+ btn.textContent = 'Sending...';
426
+ error.textContent = '';
427
+ userEmail = email;
428
+
429
+ fetch('/auth/send-code', {
430
+ method: 'POST',
431
+ headers: { 'Content-Type': 'application/json' },
432
+ body: JSON.stringify({ email: email })
433
+ }).then(function(res) {
434
+ if (res.ok) {
435
+ document.getElementById('email-section').style.display = 'none';
436
+ document.getElementById('verify-section').style.display = 'block';
437
+ } else {
438
+ return res.json().then(function(data) {
439
+ error.textContent = data.error || 'Failed to send code';
440
+ btn.disabled = false;
441
+ btn.textContent = 'Send verification code';
442
+ });
443
+ }
444
+ }).catch(function() {
445
+ error.textContent = 'Network error. Please try again.';
446
+ btn.disabled = false;
447
+ btn.textContent = 'Send verification code';
448
+ });
449
+ });
450
+
451
+ document.getElementById('verify-form').addEventListener('submit', function(e) {
452
+ e.preventDefault();
453
+ var code = document.getElementById('code').value;
454
+ var btn = document.getElementById('verify-btn');
455
+ var error = document.getElementById('verify-error');
456
+
457
+ btn.disabled = true;
458
+ btn.textContent = 'Signing in...';
459
+ error.textContent = '';
460
+
461
+ var form = document.createElement('form');
462
+ form.method = 'POST';
463
+ form.action = '/auth/authorize';
464
+
465
+ var fields = {
466
+ client_id: oauthParams.clientId,
467
+ redirect_uri: oauthParams.redirectUri,
468
+ code_challenge: oauthParams.codeChallenge,
469
+ code_challenge_method: oauthParams.codeChallengeMethod,
470
+ state: oauthParams.state,
471
+ scope: oauthParams.scope,
472
+ email: userEmail,
473
+ code: code
474
+ };
475
+
476
+ for (var key in fields) {
477
+ var input = document.createElement('input');
478
+ input.type = 'hidden';
479
+ input.name = key;
480
+ input.value = fields[key] || '';
481
+ form.appendChild(input);
482
+ }
483
+
484
+ document.body.appendChild(form);
485
+ form.submit();
486
+ });
487
+
488
+ document.getElementById('back-link').addEventListener('click', function(e) {
489
+ e.preventDefault();
490
+ document.getElementById('email-section').style.display = 'block';
491
+ document.getElementById('verify-section').style.display = 'none';
492
+ document.getElementById('code').value = '';
493
+ document.getElementById('verify-error').textContent = '';
494
+ });
495
+ </script>`
496
+ });
497
+ }
498
+
499
+ export { BRAND_CSS, GITHUB_SVG, ICON_SVG, LOGO_SVG, MOON_SVG, SUN_SVG, authorizePage, callbackErrorPage, callbackSuccessPage, escapeHtml, pageShell };
500
+ //# sourceMappingURL=index.mjs.map
501
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles.ts","../src/brand.ts","../src/shell.ts","../src/pages.ts"],"names":[],"mappings":";AAUO,IAAM,SAAA,GAAY;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACDlB,IAAM,QAAA,GAAW,CAAA,oXAAA;AAGjB,IAAM,QAAA,GAAW,CAAA,y3DAAA;AAGjB,IAAM,UAAA,GAAa,CAAA,y3BAAA;AAGnB,IAAM,OAAA,GAAU,CAAA,2hBAAA;AAGhB,IAAM,QAAA,GAAW,CAAA,uNAAA;;;ACMjB,SAAS,UAAU,OAAA,EAAmC;AAC3D,EAAA,MAAM,IAAA,GAAA,iBAAO,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACpC,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,eAAA,GACxB,EAAA,GACA,CAAA;AAAA,0BAAA,EACsB,OAAO,CAAA;AAAA,2BAAA,EACN,QAAQ,CAAA;AAAA,eAAA,CAAA;AAGnC,EAAA,MAAM,aAAA,GAAgB,QAAQ,aAAA,GAC1B,CAAA;AAAA;AAAA,UAAA,EAEM,QAAQ;AAAA,oBAAA,EACE,IAAI,CAAA;AAAA;AAAA,+EAAA,EAEuD,UAAU,CAAA;AAAA,YAAA,CAAA,GAErF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAAA,EA4BM,QAAQ;AAAA,oBAAA,EACE,IAAI,CAAA;AAAA;AAAA,+EAAA,EAEuD,UAAU,CAAA;AAAA,YAAA,CAAA;AAGzF,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,eAAA,GACpB,EAAA,GACA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAA,CAAA;AAgBJ,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAAA,EAKA,UAAA,CAAW,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,OAAA,EACzB,SAAS,CAAA,EAAG,OAAA,CAAQ,QAAA,IAAY,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,EAQrC,QAAQ;AAAA;AAAA;AAAA;AAAA,IAAA,EAIR,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,EAQX,QAAQ,IAAI;AAAA;AAAA;AAAA;AAAA,EAAA,EAId,aAAa;AAAA;AAAA,EAEf,OAAO;AAAA,EACP,OAAA,CAAQ,WAAW,EAAE;AAAA;AAAA,OAAA,CAAA;AAGvB;AAEA,SAAS,WAAW,GAAA,EAAqB;AACvC,EAAA,OAAO,GAAA,CACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,EACrB,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,CAAA,CACpB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B;;;ACpIO,SAAS,mBAAA,GAA8B;AAC5C,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,KAAA,EAAO,uCAAA;AAAA,IACP,IAAA,EAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mFAAA;AAAA,GASP,CAAA;AACH;AAKO,SAAS,kBAAkB,OAAA,EAAyB;AACzD,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,KAAA,EAAO,mCAAA;AAAA,IACP,IAAA,EAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAAA,EASyB,UAAA,CAAW,OAAO,CAAC,CAAA;AAAA,gFAAA;AAAA,GAEnD,CAAA;AACH;AAQO,SAAS,cAAc,MAAA,EAQnB;AACT,EAAA,MAAM,UAAA,GAAa,KAAK,SAAA,CAAU;AAAA,IAChC,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,aAAa,MAAA,CAAO,WAAA;AAAA,IACpB,eAAe,MAAA,CAAO,aAAA;AAAA,IACtB,qBAAqB,MAAA,CAAO,mBAAA;AAAA,IAC5B,KAAA,EAAO,OAAO,KAAA,IAAS,EAAA;AAAA,IACvB,OAAO,MAAA,CAAO;AAAA,GACf,CAAA;AAED,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,KAAA,EAAO,0BAAA;AAAA,IACP,IAAA,EAAM;AAAA;AAAA;;AAAA;AAAA,cAAA,EAKM,UAAA,CAAW,MAAA,CAAO,UAAA,IAAc,MAAA,CAAO,QAAQ,CAAC,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAAA,CAAA;AAAA,IA4B5D,OAAA,EAAS,CAAA;AAAA,kBAAA,EACO,UAAU,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAA;AAAA,GAiF3B,CAAA;AACH","file":"index.mjs","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n// Copyright 2026 Epic Digital Interactive Media LLC\n\n/**\n * Shared CSS for all Epic FlowState auth pages.\n *\n * Uses CSS custom properties for light/dark mode.\n * Automatic: follows prefers-color-scheme.\n * Manual: [data-theme=\"dark\"] or [data-theme=\"light\"] on <html> overrides.\n */\nexport const BRAND_CSS = `\n/* --- Reset --- */\n*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\n\n/* --- Theme variables --- */\n:root{\n --fs-brand:#00c3ff;\n --fs-brand-light:#4dd8ff;\n --fs-brand-dark:#0088cc;\n --fs-bg:#f8fafc;\n --fs-card-bg:#fff;\n --fs-card-border:1px solid #e2e8f0;\n --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.08);\n --fs-text:#0f172a;\n --fs-text-secondary:#475569;\n --fs-muted:#94a3b8;\n --fs-border:#e2e8f0;\n --fs-input-bg:#fff;\n --fs-input-border:#cbd5e1;\n --fs-input-focus:#00c3ff;\n --fs-footer-bg:#f1f5f9;\n --fs-footer-border:#e2e8f0;\n --fs-error:#dc2626;\n --fs-error-bg:#fef2f2;\n --fs-success:#16a34a;\n --fs-success-bg:#f0fdf4;\n --fs-logo-text:#0f172a;\n --fs-header-bg:rgba(255,255,255,.8);\n}\n@media(prefers-color-scheme:dark){\n :root:not([data-theme=\"light\"]){\n --fs-bg:#0f172a;\n --fs-card-bg:#1e293b;\n --fs-card-border:1px solid #334155;\n --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.3);\n --fs-text:#e2e8f0;\n --fs-text-secondary:#94a3b8;\n --fs-muted:#64748b;\n --fs-border:#334155;\n --fs-input-bg:#0f172a;\n --fs-input-border:#475569;\n --fs-input-focus:#00c3ff;\n --fs-footer-bg:#020617;\n --fs-footer-border:#1e293b;\n --fs-error:#ef4444;\n --fs-error-bg:rgba(239,68,68,.12);\n --fs-success:#22c55e;\n --fs-success-bg:rgba(0,195,255,.12);\n --fs-logo-text:#e2e8f0;\n --fs-header-bg:rgba(15,23,42,.8);\n }\n}\n[data-theme=\"dark\"]{\n --fs-bg:#0f172a;\n --fs-card-bg:#1e293b;\n --fs-card-border:1px solid #334155;\n --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.3);\n --fs-text:#e2e8f0;\n --fs-text-secondary:#94a3b8;\n --fs-muted:#64748b;\n --fs-border:#334155;\n --fs-input-bg:#0f172a;\n --fs-input-border:#475569;\n --fs-input-focus:#00c3ff;\n --fs-footer-bg:#020617;\n --fs-footer-border:#1e293b;\n --fs-error:#ef4444;\n --fs-error-bg:rgba(239,68,68,.12);\n --fs-success:#22c55e;\n --fs-success-bg:rgba(0,195,255,.12);\n --fs-logo-text:#e2e8f0;\n --fs-header-bg:rgba(15,23,42,.8);\n}\n[data-theme=\"light\"]{\n --fs-bg:#f8fafc;\n --fs-card-bg:#fff;\n --fs-card-border:1px solid #e2e8f0;\n --fs-card-shadow:0 10px 15px -3px rgba(0,0,0,.08);\n --fs-text:#0f172a;\n --fs-text-secondary:#475569;\n --fs-muted:#94a3b8;\n --fs-border:#e2e8f0;\n --fs-input-bg:#fff;\n --fs-input-border:#cbd5e1;\n --fs-input-focus:#00c3ff;\n --fs-footer-bg:#f1f5f9;\n --fs-footer-border:#e2e8f0;\n --fs-error:#dc2626;\n --fs-error-bg:#fef2f2;\n --fs-success:#16a34a;\n --fs-success-bg:#f0fdf4;\n --fs-logo-text:#0f172a;\n --fs-header-bg:rgba(255,255,255,.8);\n}\n\n/* --- Base --- */\nbody{\n font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif;\n background:var(--fs-bg);\n color:var(--fs-text);\n min-height:100vh;\n display:flex;\n flex-direction:column;\n transition:background .2s,color .2s;\n}\na{color:var(--fs-muted);text-decoration:none;transition:color .15s}\na:hover{color:var(--fs-text)}\n\n/* --- Header --- */\n.fs-header{\n position:sticky;top:0;z-index:50;\n display:flex;align-items:center;justify-content:space-between;\n padding:16px 32px;\n background:var(--fs-header-bg);\n backdrop-filter:blur(8px);\n -webkit-backdrop-filter:blur(8px);\n}\n.fs-header-left{display:flex;align-items:center;gap:32px}\n.fs-header-left svg{color:var(--fs-logo-text)}\n.fs-header-right{display:flex;align-items:center;gap:16px}\n.fs-nav-link{font-size:14px;color:var(--fs-muted);transition:color .15s}\n.fs-nav-link:hover{color:var(--fs-text)}\n\n/* --- Theme toggle --- */\n.fs-theme-toggle{\n background:none;border:1px solid var(--fs-border);\n border-radius:8px;padding:6px 8px;cursor:pointer;\n color:var(--fs-muted);display:flex;align-items:center;gap:4px;\n transition:color .15s,border-color .15s;\n font-size:12px;\n}\n.fs-theme-toggle:hover{color:var(--fs-text);border-color:var(--fs-muted)}\n.fs-theme-toggle .sun{display:none}\n.fs-theme-toggle .moon{display:inline-flex}\n[data-theme=\"dark\"] .fs-theme-toggle .sun{display:inline-flex}\n[data-theme=\"dark\"] .fs-theme-toggle .moon{display:none}\n@media(prefers-color-scheme:dark){\n :root:not([data-theme=\"light\"]) .fs-theme-toggle .sun{display:inline-flex}\n :root:not([data-theme=\"light\"]) .fs-theme-toggle .moon{display:none}\n}\n[data-theme=\"light\"] .fs-theme-toggle .sun{display:none}\n[data-theme=\"light\"] .fs-theme-toggle .moon{display:inline-flex}\n\n/* --- Main content --- */\n.fs-main{flex:1;display:flex;align-items:center;justify-content:center;padding:24px 16px}\n\n/* --- Card --- */\n.fs-card{\n width:100%;max-width:448px;padding:32px;\n background:var(--fs-card-bg);\n border:var(--fs-card-border);\n border-radius:12px;\n box-shadow:var(--fs-card-shadow);\n}\n.fs-card h1{font-size:24px;font-weight:700;color:var(--fs-text);margin-bottom:8px;text-align:center}\n.fs-card .fs-subtitle{font-size:14px;color:var(--fs-text-secondary);text-align:center;margin-bottom:24px;line-height:1.6}\n.fs-card p{font-size:14px;color:var(--fs-text-secondary);line-height:1.6}\n\n/* --- Card status icons --- */\n.fs-status-icon{\n margin:0 auto 24px;width:64px;height:64px;border-radius:50%;\n display:flex;align-items:center;justify-content:center;\n}\n.fs-status-icon.success{background:var(--fs-success-bg)}\n.fs-status-icon.error{background:var(--fs-error-bg)}\n.fs-status-icon svg{width:32px;height:32px}\n.fs-card .fs-action{margin-top:24px;font-size:13px;color:var(--fs-muted);text-align:center}\n\n/* --- Client info badge --- */\n.fs-client-info{\n background:var(--fs-bg);border:1px solid var(--fs-border);\n border-radius:8px;padding:12px;margin-bottom:24px;text-align:center;\n font-size:14px;color:var(--fs-text-secondary);\n}\n.fs-client-info strong{color:var(--fs-brand);font-weight:600}\n\n/* --- Forms --- */\n.fs-form{display:flex;flex-direction:column;gap:16px}\n.fs-form label{font-weight:500;color:var(--fs-text);font-size:14px}\n.fs-form input[type=\"email\"],\n.fs-form input[type=\"text\"]{\n width:100%;padding:12px 16px;\n background:var(--fs-input-bg);\n border:2px solid var(--fs-input-border);\n border-radius:8px;font-size:16px;\n color:var(--fs-text);\n transition:border-color .2s;\n}\n.fs-form input::placeholder{color:var(--fs-muted)}\n.fs-form input:focus{outline:none;border-color:var(--fs-input-focus)}\n.fs-btn{\n background:var(--fs-brand);color:#fff;border:none;\n padding:14px;border-radius:8px;font-size:16px;font-weight:600;\n cursor:pointer;transition:background .2s;width:100%;\n}\n.fs-btn:hover{background:var(--fs-brand-dark)}\n.fs-btn:disabled{opacity:.5;cursor:not-allowed}\n.fs-error-text{color:var(--fs-error);font-size:14px;text-align:center}\n.fs-success-text{color:var(--fs-success);font-size:14px;text-align:center}\n.fs-back-link{text-align:center;margin-top:16px}\n.fs-back-link a{color:var(--fs-brand);font-size:14px}\n.fs-back-link a:hover{color:var(--fs-brand-light)}\n\n/* --- Footer --- */\n.fs-footer{background:var(--fs-footer-bg);padding:48px 32px;transition:background .2s}\n.fs-footer-grid{\n max-width:1280px;margin:0 auto;\n display:grid;grid-template-columns:repeat(4,1fr);gap:32px;\n}\n@media(max-width:768px){.fs-footer-grid{grid-template-columns:repeat(2,1fr)}}\n@media(max-width:480px){.fs-footer-grid{grid-template-columns:1fr}}\n.fs-footer-col h3{\n font-size:12px;font-weight:600;text-transform:uppercase;\n letter-spacing:.05em;color:var(--fs-text);margin-bottom:16px;\n}\n.fs-footer-col ul{list-style:none}\n.fs-footer-col li{margin-bottom:12px}\n.fs-footer-col a{font-size:14px;color:var(--fs-muted)}\n.fs-footer-bottom{\n max-width:1280px;margin:0 auto;\n display:flex;align-items:center;justify-content:space-between;\n border-top:1px solid var(--fs-footer-border);\n padding-top:32px;margin-top:48px;\n}\n.fs-footer-bottom-left{display:flex;align-items:center;gap:12px}\n.fs-footer-bottom p{font-size:14px;color:var(--fs-muted)}\n`\n","// SPDX-License-Identifier: Apache-2.0\n// Copyright 2026 Epic Digital Interactive Media LLC\n\n/**\n * Epic FlowState brand SVG assets for self-contained HTML pages.\n * All SVGs are inline-safe (no external references).\n */\n\n/** Diamond icon mark (36x36) */\nexport const ICON_SVG = `<svg aria-hidden=\"true\" viewBox=\"0 0 36 36\" fill=\"none\" style=\"height:36px;width:36px\"><g fill=\"none\" stroke-linejoin=\"round\" stroke-width=\"3\"><path d=\"M10.308 5L18 17.5 10.308 30 2.615 17.5 10.308 5z\" stroke=\"var(--fs-brand,#00c3ff)\"/><path d=\"M18 17.5L10.308 5h15.144l7.933 12.5M18 17.5h15.385L25.452 30H10.308L18 17.5z\" stroke=\"var(--fs-brand-dark,#0088cc)\"/></g></svg>`\n\n/** Full wordmark logo. Fill adapts via currentColor for light/dark. */\nexport const LOGO_SVG = `<svg aria-label=\"Epic FlowState\" viewBox=\"0 0 4000 594.516\" style=\"height:36px;width:auto\"><g id=\"icon\"><path d=\"M 0,0 -90.883,157.413 H 64.324 c 16.382,0 31.646,-8.812 39.835,-23 L 181.764,0 Z\" fill=\"#4dd8ff\" transform=\"matrix(1.333,0,0,-1.333,349.797,271.737)\"/><path d=\"M 0,0 90.883,157.413 H 272.647 L 195.044,22.999 C 186.853,8.812 171.589,0 155.206,0 Z\" fill=\"#0088cc\" transform=\"matrix(1.333,0,0,-1.333,228.62,532.663)\"/><path d=\"M 0,0 C -8.189,14.188 -8.189,31.815 0.002,46.002 L 77.605,180.416 168.488,23.001 77.605,-134.413 Z\" fill=\"#00c3ff\" transform=\"matrix(1.333,0,0,-1.333,80.942,327.926)\"/></g><g id=\"text\" fill=\"currentColor\"><path d=\"M 0,0 H -116.758 V -28.172 H -83.377 0 c 28.481,0 49.92,-10.106 49.92,-43.792 0,-33.991 -20.212,-44.404 -50.224,-44.71 h -83.073 -6.534 c -14.828,0 -26.847,-12.02 -26.847,-26.847 v -71.149 h 33.381 v 69.823 h 82.769 c 45.932,0 84.213,22.66 84.213,72.883 C 83.605,-23.273 48.998,0 0,0\" transform=\"matrix(1.333,0,0,-1.333,1657.659,148.441)\"/><path d=\"M 0,0 H 95.263 V -28.785 H 60.661 -0.613 c -44.711,0 -72.883,-35.218 -72.883,-80.233 0,-45.018 28.785,-77.479 72.883,-77.479 h 61.274 34.602 v -28.479 H 0 c -63.697,0 -106.573,46.241 -106.877,107.488 C -106.877,-46.241 -63.393,0 0,0\" transform=\"matrix(1.333,0,0,-1.333,2341.873,148.032)\"/><path d=\"M 0,0 H -79.658 V -28.785 H 151.629 V 0 Z\" transform=\"matrix(1.333,0,0,-1.333,1085.02,396.287)\"/><path d=\"m 0,0 v -27.868 h 79.658 83.134 V 0 H 79.658 Z\" transform=\"matrix(1.333,0,0,-1.333,978.809,273.382)\"/><path d=\"m 734.107,305.464 h 231.287 v 28.785 H 734.107 Z\" transform=\"matrix(1.333,0,0,-1.333,0,594.516)\"/><path d=\"m 1475.135,119.887 h 33.381 V 334.25 h -33.381 z\" transform=\"matrix(1.333,0,0,-1.333,0,594.516)\"/><rect x=\"2650\" y=\"140\" width=\"8\" height=\"320\" opacity=\"0.3\"/><text x=\"2850\" y=\"405\" font-family=\"system-ui,-apple-system,sans-serif\" font-size=\"285\" font-weight=\"300\">Flowstate</text></g></svg>`\n\n/** GitHub octocat icon (scales to parent size via width/height styles) */\nexport const GITHUB_SVG = `<svg aria-hidden=\"true\" viewBox=\"0 0 16 16\" style=\"height:20px;width:20px;fill:var(--fs-muted,#94a3b8)\"><path d=\"M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z\"/></svg>`\n\n/** Sun icon for light-mode toggle */\nexport const SUN_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"width:18px;height:18px\"><circle cx=\"12\" cy=\"12\" r=\"5\"/><line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\"/><line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\"/><line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\"/><line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\"/><line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\"/><line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\"/></svg>`\n\n/** Moon icon for dark-mode toggle */\nexport const MOON_SVG = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"width:18px;height:18px\"><path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\"/></svg>`\n","// SPDX-License-Identifier: Apache-2.0\n// Copyright 2026 Epic Digital Interactive Media LLC\n\nimport { GITHUB_SVG, ICON_SVG, LOGO_SVG, MOON_SVG, SUN_SVG } from './brand'\nimport { BRAND_CSS } from './styles'\n\nexport interface PageShellOptions {\n /** Document <title> */\n title: string\n /** HTML content placed inside <main> .fs-card */\n body: string\n /** Extra CSS appended after BRAND_CSS */\n extraCss?: string\n /** Extra JS appended before </body> */\n extraJs?: string\n /** Hide the theme toggle button (default: false) */\n hideThemeToggle?: boolean\n /** Hide the full footer, show only copyright (default: false) */\n compactFooter?: boolean\n}\n\n/**\n * Renders a full self-contained HTML page with Epic FlowState branding.\n *\n * Includes header (logo + nav), centered card, footer, and light/dark toggle.\n * All CSS is inline, all SVGs are inline. No external dependencies.\n */\nexport function pageShell(options: PageShellOptions): string {\n const year = new Date().getFullYear()\n const themeToggle = options.hideThemeToggle\n ? ''\n : `<button class=\"fs-theme-toggle\" id=\"fs-theme-toggle\" aria-label=\"Toggle theme\" title=\"Toggle light/dark mode\">\n <span class=\"sun\">${SUN_SVG}</span>\n <span class=\"moon\">${MOON_SVG}</span>\n </button>`\n\n const footerContent = options.compactFooter\n ? `<div class=\"fs-footer-bottom\" style=\"border:none;padding-top:0;margin-top:0\">\n <div class=\"fs-footer-bottom-left\">\n ${ICON_SVG}\n <p>&copy; ${year} Epic Digital Interactive Media LLC</p>\n </div>\n <a href=\"https://github.com/epicdm/epic-flowstate\" aria-label=\"GitHub\">${GITHUB_SVG}</a>\n </div>`\n : `<div class=\"fs-footer-grid\">\n <div class=\"fs-footer-col\"><h3>Services</h3><ul>\n <li><a href=\"https://marketplace.epicflowstate.ai\">Marketplace</a></li>\n <li><a href=\"https://cloud.epicflowstate.ai\">Cloud Dashboard</a></li>\n <li><a href=\"https://docs.epicflowstate.ai\">Documentation</a></li>\n <li><a href=\"https://agents.epicflowstate.ai\">Agent Directory</a></li>\n <li><a href=\"https://dojo.epicflowstate.ai\">Dojo</a></li>\n <li><a href=\"https://compliance.epicflowstate.ai\">Compliance</a></li>\n </ul></div>\n <div class=\"fs-footer-col\"><h3>Resources</h3><ul>\n <li><a href=\"https://epicflowstate.ai/blog\">Blog</a></li>\n <li><a href=\"https://docs.epicflowstate.ai/api\">API Reference</a></li>\n <li><a href=\"https://epicflowstate.ai/status\">Status</a></li>\n <li><a href=\"https://epicflowstate.ai/changelog\">Changelog</a></li>\n </ul></div>\n <div class=\"fs-footer-col\"><h3>Company</h3><ul>\n <li><a href=\"https://epicflowstate.ai/about\">About</a></li>\n <li><a href=\"https://epicflowstate.ai/contact\">Contact</a></li>\n <li><a href=\"https://epicflowstate.ai/partners\">Partners</a></li>\n </ul></div>\n <div class=\"fs-footer-col\"><h3>Legal</h3><ul>\n <li><a href=\"https://epicflowstate.ai/privacy\">Privacy Policy</a></li>\n <li><a href=\"https://epicflowstate.ai/terms\">Terms of Service</a></li>\n <li><a href=\"https://epicflowstate.ai/cookies\">Cookie Policy</a></li>\n </ul></div>\n </div>\n <div class=\"fs-footer-bottom\">\n <div class=\"fs-footer-bottom-left\">\n ${ICON_SVG}\n <p>&copy; ${year} Epic Digital Interactive Media LLC</p>\n </div>\n <a href=\"https://github.com/epicdm/epic-flowstate\" aria-label=\"GitHub\">${GITHUB_SVG}</a>\n </div>`\n\n const themeJs = options.hideThemeToggle\n ? ''\n : `<script>\n(function(){\n var btn=document.getElementById('fs-theme-toggle');\n if(!btn)return;\n var stored=localStorage.getItem('fs-theme');\n if(stored)document.documentElement.setAttribute('data-theme',stored);\n btn.addEventListener('click',function(){\n var current=document.documentElement.getAttribute('data-theme');\n var isDark=current==='dark'||(!current&&window.matchMedia('(prefers-color-scheme:dark)').matches);\n var next=isDark?'light':'dark';\n document.documentElement.setAttribute('data-theme',next);\n localStorage.setItem('fs-theme',next);\n });\n})();\n</script>`\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>${escapeHtml(options.title)}</title>\n<style>${BRAND_CSS}${options.extraCss ?? ''}</style>\n<script>\n(function(){var t=localStorage.getItem('fs-theme');if(t)document.documentElement.setAttribute('data-theme',t)})();\n</script>\n</head>\n<body>\n<header class=\"fs-header\">\n <div class=\"fs-header-left\">\n ${LOGO_SVG}\n <a class=\"fs-nav-link\" href=\"https://id.epicflowstate.ai\">Identity</a>\n </div>\n <div class=\"fs-header-right\">\n ${themeToggle}\n <a href=\"https://github.com/epicdm/epic-flowstate\" aria-label=\"GitHub\">\n <svg aria-hidden=\"true\" viewBox=\"0 0 16 16\" style=\"height:24px;width:24px;fill:var(--fs-muted,#94a3b8)\"><path d=\"M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z\"/></svg>\n </a>\n </div>\n</header>\n<main class=\"fs-main\">\n <div class=\"fs-card\">\n ${options.body}\n </div>\n</main>\n<footer class=\"fs-footer\">\n ${footerContent}\n</footer>\n${themeJs}\n${options.extraJs ?? ''}\n</body>\n</html>`\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nexport { escapeHtml }\n","// SPDX-License-Identifier: Apache-2.0\n// Copyright 2026 Epic Digital Interactive Media LLC\n\nimport { escapeHtml, pageShell } from './shell'\n\n/**\n * OAuth callback success page (for CLI loopback server).\n */\nexport function callbackSuccessPage(): string {\n return pageShell({\n title: 'FlowState CLI \\u2013 Login Successful',\n body: `\n <div class=\"fs-status-icon success\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--fs-success)\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n </div>\n <h1>Login Successful</h1>\n <p style=\"text-align:center\">You have been authenticated with FlowState CLI.</p>\n <p class=\"fs-action\">You may close this window and return to your terminal.</p>`,\n })\n}\n\n/**\n * OAuth callback error page (for CLI loopback server).\n */\nexport function callbackErrorPage(message: string): string {\n return pageShell({\n title: 'FlowState CLI \\u2013 Login Failed',\n body: `\n <div class=\"fs-status-icon error\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--fs-error)\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/>\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\n </svg>\n </div>\n <h1>Login Failed</h1>\n <p style=\"text-align:center\">${escapeHtml(message)}</p>\n <p class=\"fs-action\">Close this window and try again from your terminal.</p>`,\n })\n}\n\n/**\n * OAuth authorization / login page (for auth server).\n *\n * Two-step flow: email entry, then verification code.\n * Params are embedded as JSON to prevent XSS.\n */\nexport function authorizePage(params: {\n clientId: string\n clientName: string\n redirectUri: string\n codeChallenge: string\n codeChallengeMethod: string\n scope: string\n state?: string | undefined\n}): string {\n const safeParams = JSON.stringify({\n clientId: params.clientId,\n redirectUri: params.redirectUri,\n codeChallenge: params.codeChallenge,\n codeChallengeMethod: params.codeChallengeMethod,\n state: params.state ?? '',\n scope: params.scope,\n })\n\n return pageShell({\n title: 'FlowState \\u2013 Sign In',\n body: `\n <h1>Sign in to FlowState</h1>\n <p class=\"fs-subtitle\">Verify your email to continue</p>\n\n <div class=\"fs-client-info\">\n <strong>${escapeHtml(params.clientName || params.clientId)}</strong> wants to access your account\n </div>\n\n <div id=\"email-section\">\n <form id=\"email-form\" class=\"fs-form\">\n <div>\n <label for=\"email\">Email address</label>\n <input type=\"email\" id=\"email\" name=\"email\" required placeholder=\"you@example.com\">\n </div>\n <button type=\"submit\" id=\"email-btn\" class=\"fs-btn\">Send verification code</button>\n <p class=\"fs-error-text\" id=\"email-error\"></p>\n </form>\n </div>\n\n <div id=\"verify-section\" style=\"display:none\">\n <form id=\"verify-form\" class=\"fs-form\">\n <p class=\"fs-success-text\">Check your email for the verification code</p>\n <div>\n <label for=\"code\">Verification code</label>\n <input type=\"text\" id=\"code\" name=\"code\" required placeholder=\"123456\" maxlength=\"6\" pattern=\"[0-9]{6}\" inputmode=\"numeric\">\n </div>\n <button type=\"submit\" id=\"verify-btn\" class=\"fs-btn\">Sign in</button>\n <p class=\"fs-error-text\" id=\"verify-error\"></p>\n <div class=\"fs-back-link\">\n <a href=\"#\" id=\"back-link\">Use a different email</a>\n </div>\n </form>\n </div>`,\n extraJs: `<script>\nvar oauthParams = ${safeParams};\nvar userEmail = '';\n\ndocument.getElementById('email-form').addEventListener('submit', function(e) {\n e.preventDefault();\n var email = document.getElementById('email').value;\n var btn = document.getElementById('email-btn');\n var error = document.getElementById('email-error');\n\n btn.disabled = true;\n btn.textContent = 'Sending...';\n error.textContent = '';\n userEmail = email;\n\n fetch('/auth/send-code', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email })\n }).then(function(res) {\n if (res.ok) {\n document.getElementById('email-section').style.display = 'none';\n document.getElementById('verify-section').style.display = 'block';\n } else {\n return res.json().then(function(data) {\n error.textContent = data.error || 'Failed to send code';\n btn.disabled = false;\n btn.textContent = 'Send verification code';\n });\n }\n }).catch(function() {\n error.textContent = 'Network error. Please try again.';\n btn.disabled = false;\n btn.textContent = 'Send verification code';\n });\n});\n\ndocument.getElementById('verify-form').addEventListener('submit', function(e) {\n e.preventDefault();\n var code = document.getElementById('code').value;\n var btn = document.getElementById('verify-btn');\n var error = document.getElementById('verify-error');\n\n btn.disabled = true;\n btn.textContent = 'Signing in...';\n error.textContent = '';\n\n var form = document.createElement('form');\n form.method = 'POST';\n form.action = '/auth/authorize';\n\n var fields = {\n client_id: oauthParams.clientId,\n redirect_uri: oauthParams.redirectUri,\n code_challenge: oauthParams.codeChallenge,\n code_challenge_method: oauthParams.codeChallengeMethod,\n state: oauthParams.state,\n scope: oauthParams.scope,\n email: userEmail,\n code: code\n };\n\n for (var key in fields) {\n var input = document.createElement('input');\n input.type = 'hidden';\n input.name = key;\n input.value = fields[key] || '';\n form.appendChild(input);\n }\n\n document.body.appendChild(form);\n form.submit();\n});\n\ndocument.getElementById('back-link').addEventListener('click', function(e) {\n e.preventDefault();\n document.getElementById('email-section').style.display = 'block';\n document.getElementById('verify-section').style.display = 'none';\n document.getElementById('code').value = '';\n document.getElementById('verify-error').textContent = '';\n});\n</script>`,\n })\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@epicdm/flowstate-auth-ui",
3
+ "version": "1.0.0",
4
+ "description": "Shared HTML templates and styles for FlowState auth flows",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch",
21
+ "typecheck": "tsc --noEmit"
22
+ },
23
+ "devDependencies": {
24
+ "tsup": "^8.4.0",
25
+ "typescript": "^5.8.2"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/epicdm/epic-flowstate.git",
33
+ "directory": "packages/flowstate-auth-ui"
34
+ },
35
+ "license": "Apache-2.0",
36
+ "author": "Epic Digital Interactive Media LLC"
37
+ }