@authrim/setup 0.1.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/README.md +303 -0
- package/dist/__tests__/config.test.d.ts +5 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +115 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/keys.test.d.ts +5 -0
- package/dist/__tests__/keys.test.d.ts.map +1 -0
- package/dist/__tests__/keys.test.js +87 -0
- package/dist/__tests__/keys.test.js.map +1 -0
- package/dist/__tests__/naming.test.d.ts +5 -0
- package/dist/__tests__/naming.test.d.ts.map +1 -0
- package/dist/__tests__/naming.test.js +84 -0
- package/dist/__tests__/naming.test.js.map +1 -0
- package/dist/cli/commands/config.d.ts +13 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +231 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/deploy.d.ts +21 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -0
- package/dist/cli/commands/deploy.js +304 -0
- package/dist/cli/commands/deploy.js.map +1 -0
- package/dist/cli/commands/init.d.ts +14 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +1248 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/core/admin.d.ts +64 -0
- package/dist/core/admin.d.ts.map +1 -0
- package/dist/core/admin.js +247 -0
- package/dist/core/admin.js.map +1 -0
- package/dist/core/cloudflare.d.ts +157 -0
- package/dist/core/cloudflare.d.ts.map +1 -0
- package/dist/core/cloudflare.js +452 -0
- package/dist/core/cloudflare.js.map +1 -0
- package/dist/core/config.d.ts +891 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +208 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/deploy.d.ts +81 -0
- package/dist/core/deploy.d.ts.map +1 -0
- package/dist/core/deploy.js +389 -0
- package/dist/core/deploy.js.map +1 -0
- package/dist/core/keys.d.ts +111 -0
- package/dist/core/keys.d.ts.map +1 -0
- package/dist/core/keys.js +287 -0
- package/dist/core/keys.js.map +1 -0
- package/dist/core/lock.d.ts +220 -0
- package/dist/core/lock.d.ts.map +1 -0
- package/dist/core/lock.js +230 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/naming.d.ts +151 -0
- package/dist/core/naming.d.ts.map +1 -0
- package/dist/core/naming.js +209 -0
- package/dist/core/naming.js.map +1 -0
- package/dist/core/source.d.ts +68 -0
- package/dist/core/source.d.ts.map +1 -0
- package/dist/core/source.js +285 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/wrangler.d.ts +87 -0
- package/dist/core/wrangler.d.ts.map +1 -0
- package/dist/core/wrangler.js +398 -0
- package/dist/core/wrangler.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/web/api.d.ts +21 -0
- package/dist/web/api.d.ts.map +1 -0
- package/dist/web/api.js +423 -0
- package/dist/web/api.js.map +1 -0
- package/dist/web/server.d.ts +12 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +112 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/ui.d.ts +7 -0
- package/dist/web/ui.d.ts.map +1 -0
- package/dist/web/ui.js +765 -0
- package/dist/web/ui.js.map +1 -0
- package/package.json +61 -0
package/dist/web/ui.js
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML Template for Authrim Setup Web UI
|
|
3
|
+
*
|
|
4
|
+
* A simple, self-contained UI for the setup wizard.
|
|
5
|
+
*/
|
|
6
|
+
export function getHtmlTemplate(sessionToken) {
|
|
7
|
+
// Escape token for safe embedding in JavaScript
|
|
8
|
+
const safeToken = sessionToken ? sessionToken.replace(/['"\\]/g, '') : '';
|
|
9
|
+
return `<!DOCTYPE html>
|
|
10
|
+
<html lang="en">
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="UTF-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
14
|
+
<title>Authrim Setup</title>
|
|
15
|
+
<style>
|
|
16
|
+
:root {
|
|
17
|
+
--primary: #2563eb;
|
|
18
|
+
--primary-dark: #1d4ed8;
|
|
19
|
+
--success: #10b981;
|
|
20
|
+
--error: #ef4444;
|
|
21
|
+
--warning: #f59e0b;
|
|
22
|
+
--bg: #f8fafc;
|
|
23
|
+
--card-bg: #ffffff;
|
|
24
|
+
--text: #1e293b;
|
|
25
|
+
--text-muted: #64748b;
|
|
26
|
+
--border: #e2e8f0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
* {
|
|
30
|
+
margin: 0;
|
|
31
|
+
padding: 0;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
37
|
+
background: var(--bg);
|
|
38
|
+
color: var(--text);
|
|
39
|
+
line-height: 1.6;
|
|
40
|
+
min-height: 100vh;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.container {
|
|
44
|
+
max-width: 800px;
|
|
45
|
+
margin: 0 auto;
|
|
46
|
+
padding: 2rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
header {
|
|
50
|
+
text-align: center;
|
|
51
|
+
margin-bottom: 2rem;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
h1 {
|
|
55
|
+
font-size: 2rem;
|
|
56
|
+
color: var(--primary);
|
|
57
|
+
margin-bottom: 0.5rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.subtitle {
|
|
61
|
+
color: var(--text-muted);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.card {
|
|
65
|
+
background: var(--card-bg);
|
|
66
|
+
border-radius: 12px;
|
|
67
|
+
padding: 1.5rem;
|
|
68
|
+
margin-bottom: 1.5rem;
|
|
69
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.card-title {
|
|
73
|
+
font-size: 1.25rem;
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
margin-bottom: 1rem;
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 0.5rem;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.status-badge {
|
|
82
|
+
font-size: 0.75rem;
|
|
83
|
+
padding: 0.25rem 0.5rem;
|
|
84
|
+
border-radius: 9999px;
|
|
85
|
+
font-weight: 500;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.status-pending { background: var(--border); color: var(--text-muted); }
|
|
89
|
+
.status-running { background: #dbeafe; color: var(--primary); }
|
|
90
|
+
.status-success { background: #d1fae5; color: var(--success); }
|
|
91
|
+
.status-error { background: #fee2e2; color: var(--error); }
|
|
92
|
+
|
|
93
|
+
.form-group {
|
|
94
|
+
margin-bottom: 1rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
label {
|
|
98
|
+
display: block;
|
|
99
|
+
font-weight: 500;
|
|
100
|
+
margin-bottom: 0.5rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
input[type="text"],
|
|
104
|
+
input[type="password"],
|
|
105
|
+
select {
|
|
106
|
+
width: 100%;
|
|
107
|
+
padding: 0.75rem;
|
|
108
|
+
border: 1px solid var(--border);
|
|
109
|
+
border-radius: 8px;
|
|
110
|
+
font-size: 1rem;
|
|
111
|
+
transition: border-color 0.2s;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
input:focus,
|
|
115
|
+
select:focus {
|
|
116
|
+
outline: none;
|
|
117
|
+
border-color: var(--primary);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.checkbox-group {
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-wrap: wrap;
|
|
123
|
+
gap: 1rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.checkbox-item {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
gap: 0.5rem;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
button {
|
|
133
|
+
padding: 0.75rem 1.5rem;
|
|
134
|
+
border-radius: 8px;
|
|
135
|
+
font-size: 1rem;
|
|
136
|
+
font-weight: 500;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
transition: all 0.2s;
|
|
139
|
+
border: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.btn-primary {
|
|
143
|
+
background: var(--primary);
|
|
144
|
+
color: white;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.btn-primary:hover:not(:disabled) {
|
|
148
|
+
background: var(--primary-dark);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.btn-primary:disabled {
|
|
152
|
+
opacity: 0.6;
|
|
153
|
+
cursor: not-allowed;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.btn-secondary {
|
|
157
|
+
background: var(--border);
|
|
158
|
+
color: var(--text);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.btn-secondary:hover {
|
|
162
|
+
background: #cbd5e1;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.button-group {
|
|
166
|
+
display: flex;
|
|
167
|
+
gap: 1rem;
|
|
168
|
+
margin-top: 1.5rem;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.progress-log {
|
|
172
|
+
background: #1e293b;
|
|
173
|
+
border-radius: 8px;
|
|
174
|
+
padding: 1rem;
|
|
175
|
+
max-height: 300px;
|
|
176
|
+
overflow-y: auto;
|
|
177
|
+
font-family: 'Monaco', 'Menlo', monospace;
|
|
178
|
+
font-size: 0.875rem;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.progress-log pre {
|
|
182
|
+
color: #e2e8f0;
|
|
183
|
+
white-space: pre-wrap;
|
|
184
|
+
word-break: break-word;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.step-indicator {
|
|
188
|
+
display: flex;
|
|
189
|
+
justify-content: center;
|
|
190
|
+
gap: 0.5rem;
|
|
191
|
+
margin-bottom: 2rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.step {
|
|
195
|
+
width: 40px;
|
|
196
|
+
height: 40px;
|
|
197
|
+
border-radius: 50%;
|
|
198
|
+
display: flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
justify-content: center;
|
|
201
|
+
font-weight: 600;
|
|
202
|
+
font-size: 0.875rem;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.step-active {
|
|
206
|
+
background: var(--primary);
|
|
207
|
+
color: white;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.step-complete {
|
|
211
|
+
background: var(--success);
|
|
212
|
+
color: white;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.step-pending {
|
|
216
|
+
background: var(--border);
|
|
217
|
+
color: var(--text-muted);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.step-connector {
|
|
221
|
+
width: 40px;
|
|
222
|
+
height: 2px;
|
|
223
|
+
background: var(--border);
|
|
224
|
+
align-self: center;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.alert {
|
|
228
|
+
padding: 1rem;
|
|
229
|
+
border-radius: 8px;
|
|
230
|
+
margin-bottom: 1rem;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.alert-success { background: #d1fae5; color: #065f46; }
|
|
234
|
+
.alert-error { background: #fee2e2; color: #991b1b; }
|
|
235
|
+
.alert-warning { background: #fef3c7; color: #92400e; }
|
|
236
|
+
.alert-info { background: #dbeafe; color: #1e40af; }
|
|
237
|
+
|
|
238
|
+
.url-display {
|
|
239
|
+
background: var(--bg);
|
|
240
|
+
padding: 1rem;
|
|
241
|
+
border-radius: 8px;
|
|
242
|
+
margin-top: 1rem;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.url-item {
|
|
246
|
+
display: flex;
|
|
247
|
+
gap: 0.5rem;
|
|
248
|
+
margin-bottom: 0.5rem;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.url-label {
|
|
252
|
+
font-weight: 500;
|
|
253
|
+
min-width: 100px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.url-value {
|
|
257
|
+
color: var(--primary);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.hidden { display: none; }
|
|
261
|
+
</style>
|
|
262
|
+
</head>
|
|
263
|
+
<body>
|
|
264
|
+
<div class="container">
|
|
265
|
+
<header>
|
|
266
|
+
<h1>🔐 Authrim Setup</h1>
|
|
267
|
+
<p class="subtitle">OIDC Provider on Cloudflare Workers</p>
|
|
268
|
+
</header>
|
|
269
|
+
|
|
270
|
+
<div class="step-indicator">
|
|
271
|
+
<div class="step step-active" id="step-1">1</div>
|
|
272
|
+
<div class="step-connector"></div>
|
|
273
|
+
<div class="step step-pending" id="step-2">2</div>
|
|
274
|
+
<div class="step-connector"></div>
|
|
275
|
+
<div class="step step-pending" id="step-3">3</div>
|
|
276
|
+
<div class="step-connector"></div>
|
|
277
|
+
<div class="step step-pending" id="step-4">4</div>
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
<!-- Step 1: Prerequisites -->
|
|
281
|
+
<div id="section-prerequisites" class="card">
|
|
282
|
+
<h2 class="card-title">
|
|
283
|
+
Prerequisites
|
|
284
|
+
<span class="status-badge status-running" id="prereq-status">Checking...</span>
|
|
285
|
+
</h2>
|
|
286
|
+
<div id="prereq-content">
|
|
287
|
+
<p>Checking system requirements...</p>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<!-- Step 2: Configuration -->
|
|
292
|
+
<div id="section-config" class="card hidden">
|
|
293
|
+
<h2 class="card-title">Configuration</h2>
|
|
294
|
+
|
|
295
|
+
<div class="form-group">
|
|
296
|
+
<label for="env">Environment</label>
|
|
297
|
+
<select id="env">
|
|
298
|
+
<option value="prod">Production (prod)</option>
|
|
299
|
+
<option value="staging">Staging</option>
|
|
300
|
+
<option value="dev">Development (dev)</option>
|
|
301
|
+
</select>
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
<div class="form-group">
|
|
305
|
+
<label for="domain">Custom Domain (optional)</label>
|
|
306
|
+
<input type="text" id="domain" placeholder="auth.example.com">
|
|
307
|
+
<small style="color: var(--text-muted)">Leave empty to use workers.dev / pages.dev</small>
|
|
308
|
+
</div>
|
|
309
|
+
|
|
310
|
+
<h3 style="margin: 1.5rem 0 1rem; font-size: 1rem;">Components</h3>
|
|
311
|
+
<div class="checkbox-group">
|
|
312
|
+
<label class="checkbox-item">
|
|
313
|
+
<input type="checkbox" id="comp-api" checked disabled>
|
|
314
|
+
API (required)
|
|
315
|
+
</label>
|
|
316
|
+
<label class="checkbox-item">
|
|
317
|
+
<input type="checkbox" id="comp-login-ui" checked>
|
|
318
|
+
Login UI
|
|
319
|
+
</label>
|
|
320
|
+
<label class="checkbox-item">
|
|
321
|
+
<input type="checkbox" id="comp-admin-ui" checked>
|
|
322
|
+
Admin UI
|
|
323
|
+
</label>
|
|
324
|
+
<label class="checkbox-item">
|
|
325
|
+
<input type="checkbox" id="comp-saml">
|
|
326
|
+
SAML IdP
|
|
327
|
+
</label>
|
|
328
|
+
<label class="checkbox-item">
|
|
329
|
+
<input type="checkbox" id="comp-vc">
|
|
330
|
+
Verifiable Credentials
|
|
331
|
+
</label>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<div class="button-group">
|
|
335
|
+
<button class="btn-primary" id="btn-configure">Continue</button>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<!-- Step 3: Provisioning -->
|
|
340
|
+
<div id="section-provision" class="card hidden">
|
|
341
|
+
<h2 class="card-title">
|
|
342
|
+
Resource Provisioning
|
|
343
|
+
<span class="status-badge status-pending" id="provision-status">Ready</span>
|
|
344
|
+
</h2>
|
|
345
|
+
|
|
346
|
+
<p style="margin-bottom: 1rem;">The following resources will be created:</p>
|
|
347
|
+
<ul style="margin-left: 1.5rem; margin-bottom: 1rem;">
|
|
348
|
+
<li>2 D1 Databases (core, PII)</li>
|
|
349
|
+
<li>8 KV Namespaces</li>
|
|
350
|
+
<li>RSA Key Pair for JWT signing</li>
|
|
351
|
+
</ul>
|
|
352
|
+
|
|
353
|
+
<div class="progress-log hidden" id="provision-log">
|
|
354
|
+
<pre id="provision-output"></pre>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
<div class="button-group">
|
|
358
|
+
<button class="btn-secondary" id="btn-back-config">Back</button>
|
|
359
|
+
<button class="btn-primary" id="btn-provision">Create Resources</button>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
|
|
363
|
+
<!-- Step 4: Deployment -->
|
|
364
|
+
<div id="section-deploy" class="card hidden">
|
|
365
|
+
<h2 class="card-title">
|
|
366
|
+
Deployment
|
|
367
|
+
<span class="status-badge status-pending" id="deploy-status">Ready</span>
|
|
368
|
+
</h2>
|
|
369
|
+
|
|
370
|
+
<p style="margin-bottom: 1rem;">Ready to deploy Authrim workers to Cloudflare.</p>
|
|
371
|
+
|
|
372
|
+
<div class="progress-log hidden" id="deploy-log">
|
|
373
|
+
<pre id="deploy-output"></pre>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<div class="button-group">
|
|
377
|
+
<button class="btn-secondary" id="btn-back-provision">Back</button>
|
|
378
|
+
<button class="btn-primary" id="btn-deploy">Deploy</button>
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<!-- Complete -->
|
|
383
|
+
<div id="section-complete" class="card hidden">
|
|
384
|
+
<h2 class="card-title" style="color: var(--success);">
|
|
385
|
+
Setup Complete!
|
|
386
|
+
</h2>
|
|
387
|
+
|
|
388
|
+
<p>Authrim has been successfully deployed.</p>
|
|
389
|
+
|
|
390
|
+
<div class="url-display" id="urls">
|
|
391
|
+
<!-- URLs will be inserted here -->
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
<div class="alert alert-info" style="margin-top: 1rem;">
|
|
395
|
+
<strong>Next Steps:</strong>
|
|
396
|
+
<ol style="margin-left: 1.5rem; margin-top: 0.5rem;">
|
|
397
|
+
<li>Visit the Admin UI to create your first client</li>
|
|
398
|
+
<li>Configure your application to use the OIDC endpoints</li>
|
|
399
|
+
</ol>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
<script>
|
|
405
|
+
// Session token for API authentication (embedded by server)
|
|
406
|
+
const SESSION_TOKEN = '${safeToken}';
|
|
407
|
+
|
|
408
|
+
// State
|
|
409
|
+
let currentStep = 1;
|
|
410
|
+
let config = {};
|
|
411
|
+
|
|
412
|
+
// Elements
|
|
413
|
+
const steps = {
|
|
414
|
+
1: document.getElementById('step-1'),
|
|
415
|
+
2: document.getElementById('step-2'),
|
|
416
|
+
3: document.getElementById('step-3'),
|
|
417
|
+
4: document.getElementById('step-4'),
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const sections = {
|
|
421
|
+
prerequisites: document.getElementById('section-prerequisites'),
|
|
422
|
+
config: document.getElementById('section-config'),
|
|
423
|
+
provision: document.getElementById('section-provision'),
|
|
424
|
+
deploy: document.getElementById('section-deploy'),
|
|
425
|
+
complete: document.getElementById('section-complete'),
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// API helpers (with session token authentication)
|
|
429
|
+
async function api(endpoint, options = {}) {
|
|
430
|
+
const response = await fetch('/api' + endpoint, {
|
|
431
|
+
headers: {
|
|
432
|
+
'Content-Type': 'application/json',
|
|
433
|
+
'X-Session-Token': SESSION_TOKEN,
|
|
434
|
+
},
|
|
435
|
+
...options,
|
|
436
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
437
|
+
});
|
|
438
|
+
return response.json();
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Step navigation
|
|
442
|
+
function setStep(step) {
|
|
443
|
+
currentStep = step;
|
|
444
|
+
for (let i = 1; i <= 4; i++) {
|
|
445
|
+
const el = steps[i];
|
|
446
|
+
el.className = 'step ' + (i < step ? 'step-complete' : i === step ? 'step-active' : 'step-pending');
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function showSection(name) {
|
|
451
|
+
Object.values(sections).forEach(s => s.classList.add('hidden'));
|
|
452
|
+
sections[name].classList.remove('hidden');
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Safe DOM element creation helpers
|
|
456
|
+
function createAlert(type, content) {
|
|
457
|
+
const div = document.createElement('div');
|
|
458
|
+
div.className = 'alert alert-' + type;
|
|
459
|
+
if (typeof content === 'string') {
|
|
460
|
+
div.textContent = content;
|
|
461
|
+
} else {
|
|
462
|
+
div.appendChild(content);
|
|
463
|
+
}
|
|
464
|
+
return div;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function createUrlItem(label, url) {
|
|
468
|
+
const div = document.createElement('div');
|
|
469
|
+
div.className = 'url-item';
|
|
470
|
+
|
|
471
|
+
const labelSpan = document.createElement('span');
|
|
472
|
+
labelSpan.className = 'url-label';
|
|
473
|
+
labelSpan.textContent = label;
|
|
474
|
+
|
|
475
|
+
const link = document.createElement('a');
|
|
476
|
+
link.href = url;
|
|
477
|
+
link.target = '_blank';
|
|
478
|
+
link.className = 'url-value';
|
|
479
|
+
link.textContent = url;
|
|
480
|
+
|
|
481
|
+
div.appendChild(labelSpan);
|
|
482
|
+
div.appendChild(link);
|
|
483
|
+
return div;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Check prerequisites
|
|
487
|
+
async function checkPrerequisites() {
|
|
488
|
+
const prereqStatus = document.getElementById('prereq-status');
|
|
489
|
+
const prereqContent = document.getElementById('prereq-content');
|
|
490
|
+
|
|
491
|
+
try {
|
|
492
|
+
const result = await api('/prerequisites');
|
|
493
|
+
|
|
494
|
+
// Clear existing content
|
|
495
|
+
prereqContent.textContent = '';
|
|
496
|
+
|
|
497
|
+
if (!result.wranglerInstalled) {
|
|
498
|
+
prereqStatus.textContent = 'Error';
|
|
499
|
+
prereqStatus.className = 'status-badge status-error';
|
|
500
|
+
|
|
501
|
+
const alertDiv = document.createElement('div');
|
|
502
|
+
alertDiv.className = 'alert alert-error';
|
|
503
|
+
|
|
504
|
+
const title = document.createElement('strong');
|
|
505
|
+
title.textContent = 'Wrangler not installed';
|
|
506
|
+
alertDiv.appendChild(title);
|
|
507
|
+
|
|
508
|
+
const para = document.createElement('p');
|
|
509
|
+
para.textContent = 'Please install wrangler first:';
|
|
510
|
+
alertDiv.appendChild(para);
|
|
511
|
+
|
|
512
|
+
const code = document.createElement('code');
|
|
513
|
+
code.style.display = 'block';
|
|
514
|
+
code.style.marginTop = '0.5rem';
|
|
515
|
+
code.textContent = 'npm install -g wrangler';
|
|
516
|
+
alertDiv.appendChild(code);
|
|
517
|
+
|
|
518
|
+
prereqContent.appendChild(alertDiv);
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (!result.auth.isLoggedIn) {
|
|
523
|
+
prereqStatus.textContent = 'Login Required';
|
|
524
|
+
prereqStatus.className = 'status-badge status-warning';
|
|
525
|
+
|
|
526
|
+
const alertDiv = document.createElement('div');
|
|
527
|
+
alertDiv.className = 'alert alert-warning';
|
|
528
|
+
|
|
529
|
+
const title = document.createElement('strong');
|
|
530
|
+
title.textContent = 'Not logged in to Cloudflare';
|
|
531
|
+
alertDiv.appendChild(title);
|
|
532
|
+
|
|
533
|
+
const para1 = document.createElement('p');
|
|
534
|
+
para1.textContent = 'Please run this command in your terminal:';
|
|
535
|
+
alertDiv.appendChild(para1);
|
|
536
|
+
|
|
537
|
+
const code = document.createElement('code');
|
|
538
|
+
code.style.display = 'block';
|
|
539
|
+
code.style.marginTop = '0.5rem';
|
|
540
|
+
code.textContent = 'wrangler login';
|
|
541
|
+
alertDiv.appendChild(code);
|
|
542
|
+
|
|
543
|
+
const para2 = document.createElement('p');
|
|
544
|
+
para2.style.marginTop = '0.5rem';
|
|
545
|
+
para2.textContent = 'Then refresh this page.';
|
|
546
|
+
alertDiv.appendChild(para2);
|
|
547
|
+
|
|
548
|
+
prereqContent.appendChild(alertDiv);
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
prereqStatus.textContent = 'Ready';
|
|
553
|
+
prereqStatus.className = 'status-badge status-success';
|
|
554
|
+
|
|
555
|
+
const alertDiv = document.createElement('div');
|
|
556
|
+
alertDiv.className = 'alert alert-success';
|
|
557
|
+
|
|
558
|
+
const p1 = document.createElement('p');
|
|
559
|
+
p1.textContent = 'Wrangler installed';
|
|
560
|
+
alertDiv.appendChild(p1);
|
|
561
|
+
|
|
562
|
+
const p2 = document.createElement('p');
|
|
563
|
+
p2.textContent = 'Logged in as ' + (result.auth.email || 'Unknown');
|
|
564
|
+
alertDiv.appendChild(p2);
|
|
565
|
+
|
|
566
|
+
prereqContent.appendChild(alertDiv);
|
|
567
|
+
|
|
568
|
+
const buttonGroup = document.createElement('div');
|
|
569
|
+
buttonGroup.className = 'button-group';
|
|
570
|
+
|
|
571
|
+
const btn = document.createElement('button');
|
|
572
|
+
btn.className = 'btn-primary';
|
|
573
|
+
btn.textContent = 'Start Setup';
|
|
574
|
+
btn.addEventListener('click', startSetup);
|
|
575
|
+
buttonGroup.appendChild(btn);
|
|
576
|
+
|
|
577
|
+
prereqContent.appendChild(buttonGroup);
|
|
578
|
+
|
|
579
|
+
return true;
|
|
580
|
+
} catch (error) {
|
|
581
|
+
prereqStatus.textContent = 'Error';
|
|
582
|
+
prereqStatus.className = 'status-badge status-error';
|
|
583
|
+
prereqContent.textContent = '';
|
|
584
|
+
prereqContent.appendChild(createAlert('error', 'Error checking prerequisites: ' + error.message));
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Start setup
|
|
590
|
+
function startSetup() {
|
|
591
|
+
setStep(2);
|
|
592
|
+
showSection('config');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Configure
|
|
596
|
+
document.getElementById('btn-configure').addEventListener('click', async () => {
|
|
597
|
+
const env = document.getElementById('env').value;
|
|
598
|
+
const domain = document.getElementById('domain').value;
|
|
599
|
+
|
|
600
|
+
config = {
|
|
601
|
+
env,
|
|
602
|
+
domain: domain || null,
|
|
603
|
+
components: {
|
|
604
|
+
api: true,
|
|
605
|
+
loginUi: document.getElementById('comp-login-ui').checked,
|
|
606
|
+
adminUi: document.getElementById('comp-admin-ui').checked,
|
|
607
|
+
saml: document.getElementById('comp-saml').checked,
|
|
608
|
+
vc: document.getElementById('comp-vc').checked,
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// Create default config
|
|
613
|
+
await api('/config/default', {
|
|
614
|
+
method: 'POST',
|
|
615
|
+
body: { env, domain },
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
setStep(3);
|
|
619
|
+
showSection('provision');
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
document.getElementById('btn-back-config').addEventListener('click', () => {
|
|
623
|
+
setStep(2);
|
|
624
|
+
showSection('config');
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Provision
|
|
628
|
+
document.getElementById('btn-provision').addEventListener('click', async () => {
|
|
629
|
+
const btn = document.getElementById('btn-provision');
|
|
630
|
+
const status = document.getElementById('provision-status');
|
|
631
|
+
const log = document.getElementById('provision-log');
|
|
632
|
+
const output = document.getElementById('provision-output');
|
|
633
|
+
|
|
634
|
+
btn.disabled = true;
|
|
635
|
+
status.textContent = 'Running...';
|
|
636
|
+
status.className = 'status-badge status-running';
|
|
637
|
+
log.classList.remove('hidden');
|
|
638
|
+
output.textContent = '';
|
|
639
|
+
|
|
640
|
+
try {
|
|
641
|
+
// Generate keys
|
|
642
|
+
output.textContent += 'Generating cryptographic keys...\\n';
|
|
643
|
+
await api('/keys/generate', {
|
|
644
|
+
method: 'POST',
|
|
645
|
+
body: { keyId: config.env + '-key-' + Date.now() },
|
|
646
|
+
});
|
|
647
|
+
output.textContent += 'Keys generated\\n\\n';
|
|
648
|
+
|
|
649
|
+
// Provision resources
|
|
650
|
+
output.textContent += 'Provisioning Cloudflare resources...\\n';
|
|
651
|
+
const result = await api('/provision', {
|
|
652
|
+
method: 'POST',
|
|
653
|
+
body: { env: config.env },
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
if (result.success) {
|
|
657
|
+
output.textContent += '\\nProvisioning complete!\\n';
|
|
658
|
+
status.textContent = 'Complete';
|
|
659
|
+
status.className = 'status-badge status-success';
|
|
660
|
+
|
|
661
|
+
setStep(4);
|
|
662
|
+
setTimeout(() => showSection('deploy'), 1000);
|
|
663
|
+
} else {
|
|
664
|
+
throw new Error(result.error);
|
|
665
|
+
}
|
|
666
|
+
} catch (error) {
|
|
667
|
+
output.textContent += '\\nError: ' + error.message + '\\n';
|
|
668
|
+
status.textContent = 'Error';
|
|
669
|
+
status.className = 'status-badge status-error';
|
|
670
|
+
btn.disabled = false;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
document.getElementById('btn-back-provision').addEventListener('click', () => {
|
|
675
|
+
setStep(3);
|
|
676
|
+
showSection('provision');
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// Deploy
|
|
680
|
+
document.getElementById('btn-deploy').addEventListener('click', async () => {
|
|
681
|
+
const btn = document.getElementById('btn-deploy');
|
|
682
|
+
const status = document.getElementById('deploy-status');
|
|
683
|
+
const log = document.getElementById('deploy-log');
|
|
684
|
+
const output = document.getElementById('deploy-output');
|
|
685
|
+
|
|
686
|
+
btn.disabled = true;
|
|
687
|
+
status.textContent = 'Deploying...';
|
|
688
|
+
status.className = 'status-badge status-running';
|
|
689
|
+
log.classList.remove('hidden');
|
|
690
|
+
output.textContent = 'Starting deployment...\\n\\n';
|
|
691
|
+
|
|
692
|
+
try {
|
|
693
|
+
// Generate wrangler configs first
|
|
694
|
+
output.textContent += 'Generating wrangler.toml files...\\n';
|
|
695
|
+
await api('/wrangler/generate', {
|
|
696
|
+
method: 'POST',
|
|
697
|
+
body: { env: config.env },
|
|
698
|
+
});
|
|
699
|
+
output.textContent += 'Config files generated\\n\\n';
|
|
700
|
+
|
|
701
|
+
// Start deployment
|
|
702
|
+
output.textContent += 'Deploying workers...\\n';
|
|
703
|
+
|
|
704
|
+
// Poll for status updates
|
|
705
|
+
const pollInterval = setInterval(async () => {
|
|
706
|
+
const statusResult = await api('/deploy/status');
|
|
707
|
+
if (statusResult.progress.length > 0) {
|
|
708
|
+
output.textContent = statusResult.progress.join('\\n') + '\\n';
|
|
709
|
+
}
|
|
710
|
+
}, 1000);
|
|
711
|
+
|
|
712
|
+
const result = await api('/deploy', {
|
|
713
|
+
method: 'POST',
|
|
714
|
+
body: {
|
|
715
|
+
env: config.env,
|
|
716
|
+
dryRun: false,
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
clearInterval(pollInterval);
|
|
721
|
+
|
|
722
|
+
if (result.success) {
|
|
723
|
+
output.textContent += '\\nDeployment complete!\\n';
|
|
724
|
+
status.textContent = 'Complete';
|
|
725
|
+
status.className = 'status-badge status-success';
|
|
726
|
+
|
|
727
|
+
// Show completion
|
|
728
|
+
showComplete();
|
|
729
|
+
} else {
|
|
730
|
+
throw new Error(result.error || 'Deployment failed');
|
|
731
|
+
}
|
|
732
|
+
} catch (error) {
|
|
733
|
+
output.textContent += '\\nError: ' + error.message + '\\n';
|
|
734
|
+
status.textContent = 'Error';
|
|
735
|
+
status.className = 'status-badge status-error';
|
|
736
|
+
btn.disabled = false;
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
// Show completion
|
|
741
|
+
function showComplete() {
|
|
742
|
+
const urlsEl = document.getElementById('urls');
|
|
743
|
+
const env = config.env;
|
|
744
|
+
const domain = config.domain;
|
|
745
|
+
|
|
746
|
+
const apiUrl = domain ? 'https://' + domain : 'https://' + env + '-ar-router.workers.dev';
|
|
747
|
+
const loginUrl = domain ? 'https://' + domain + '/login' : 'https://' + env + '-ar-ui.pages.dev';
|
|
748
|
+
const adminUrl = domain ? 'https://' + domain + '/admin' : 'https://' + env + '-ar-ui.pages.dev/admin';
|
|
749
|
+
|
|
750
|
+
// Clear and rebuild URLs section safely
|
|
751
|
+
urlsEl.textContent = '';
|
|
752
|
+
urlsEl.appendChild(createUrlItem('API (Issuer):', apiUrl));
|
|
753
|
+
urlsEl.appendChild(createUrlItem('Login UI:', loginUrl));
|
|
754
|
+
urlsEl.appendChild(createUrlItem('Admin UI:', adminUrl));
|
|
755
|
+
|
|
756
|
+
showSection('complete');
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Initialize
|
|
760
|
+
checkPrerequisites();
|
|
761
|
+
</script>
|
|
762
|
+
</body>
|
|
763
|
+
</html>`;
|
|
764
|
+
}
|
|
765
|
+
//# sourceMappingURL=ui.js.map
|