ninja-terminals 2.1.4 → 2.1.5
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/package.json +1 -1
- package/public/app.js +79 -0
- package/public/index.html +12 -1
- package/public/style.css +2 -0
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -62,6 +62,26 @@ const auth = {
|
|
|
62
62
|
return data;
|
|
63
63
|
},
|
|
64
64
|
|
|
65
|
+
async register(username, email, password) {
|
|
66
|
+
const res = await fetch(`${AUTH_API}/auth/register`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: { 'Content-Type': 'application/json' },
|
|
69
|
+
body: JSON.stringify({ username, email, password }),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
const err = await res.json().catch(() => ({}));
|
|
74
|
+
throw new Error(err.message || 'Registration failed');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const data = await res.json();
|
|
78
|
+
this.token = data.token || data.accessToken;
|
|
79
|
+
localStorage.setItem(TOKEN_KEY, this.token);
|
|
80
|
+
|
|
81
|
+
await this.validateTier();
|
|
82
|
+
return data;
|
|
83
|
+
},
|
|
84
|
+
|
|
65
85
|
async activateLicense(key) {
|
|
66
86
|
const res = await fetch(`${AUTH_API}/ninja/activate-license`, {
|
|
67
87
|
method: 'POST',
|
|
@@ -143,10 +163,45 @@ function hideAuthOverlay() {
|
|
|
143
163
|
|
|
144
164
|
function setupAuthForms() {
|
|
145
165
|
const loginForm = document.getElementById('login-form');
|
|
166
|
+
const registerForm = document.getElementById('register-form');
|
|
146
167
|
const licenseForm = document.getElementById('license-form');
|
|
147
168
|
const loginError = document.getElementById('login-error');
|
|
169
|
+
const registerError = document.getElementById('register-error');
|
|
148
170
|
const logoutBtn = document.getElementById('logout-btn');
|
|
171
|
+
const showRegisterLink = document.getElementById('show-register');
|
|
172
|
+
const authToggleText = document.getElementById('auth-toggle-text');
|
|
173
|
+
|
|
174
|
+
// Toggle between login and register
|
|
175
|
+
let showingRegister = false;
|
|
176
|
+
|
|
177
|
+
function toggleAuthMode() {
|
|
178
|
+
showingRegister = !showingRegister;
|
|
179
|
+
if (showingRegister) {
|
|
180
|
+
loginForm.classList.add('hidden');
|
|
181
|
+
registerForm.classList.remove('hidden');
|
|
182
|
+
authToggleText.innerHTML = 'Already have an account? <a href="#" id="show-register">Sign in</a>';
|
|
183
|
+
document.getElementById('register-username').focus();
|
|
184
|
+
} else {
|
|
185
|
+
registerForm.classList.add('hidden');
|
|
186
|
+
loginForm.classList.remove('hidden');
|
|
187
|
+
authToggleText.innerHTML = 'Don\'t have an account? <a href="#" id="show-register">Sign up</a>';
|
|
188
|
+
document.getElementById('login-email').focus();
|
|
189
|
+
}
|
|
190
|
+
// Re-attach click handler to new link
|
|
191
|
+
document.getElementById('show-register').addEventListener('click', (e) => {
|
|
192
|
+
e.preventDefault();
|
|
193
|
+
toggleAuthMode();
|
|
194
|
+
});
|
|
195
|
+
loginError.textContent = '';
|
|
196
|
+
registerError.textContent = '';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
showRegisterLink.addEventListener('click', (e) => {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
toggleAuthMode();
|
|
202
|
+
});
|
|
149
203
|
|
|
204
|
+
// Login form
|
|
150
205
|
loginForm.addEventListener('submit', async (e) => {
|
|
151
206
|
e.preventDefault();
|
|
152
207
|
loginError.textContent = '';
|
|
@@ -163,6 +218,30 @@ function setupAuthForms() {
|
|
|
163
218
|
}
|
|
164
219
|
});
|
|
165
220
|
|
|
221
|
+
// Register form
|
|
222
|
+
registerForm.addEventListener('submit', async (e) => {
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
registerError.textContent = '';
|
|
225
|
+
|
|
226
|
+
const username = document.getElementById('register-username').value.trim();
|
|
227
|
+
const email = document.getElementById('register-email').value.trim();
|
|
228
|
+
const password = document.getElementById('register-password').value;
|
|
229
|
+
|
|
230
|
+
if (password.length < 8) {
|
|
231
|
+
registerError.textContent = 'Password must be at least 8 characters';
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
await auth.register(username, email, password);
|
|
237
|
+
hideAuthOverlay();
|
|
238
|
+
startApp();
|
|
239
|
+
} catch (err) {
|
|
240
|
+
registerError.textContent = err.message;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// License form
|
|
166
245
|
licenseForm.addEventListener('submit', async (e) => {
|
|
167
246
|
e.preventDefault();
|
|
168
247
|
loginError.textContent = '';
|
package/public/index.html
CHANGED
|
@@ -38,18 +38,29 @@
|
|
|
38
38
|
<div class="auth-card-inner">
|
|
39
39
|
<h1 class="logo-text">NINJA TERMINALS</h1>
|
|
40
40
|
<p class="auth-subtitle">Multi-Agent Claude Code Orchestrator</p>
|
|
41
|
+
<!-- Login Form -->
|
|
41
42
|
<form id="login-form">
|
|
42
43
|
<input type="text" id="login-email" placeholder="Email or username" required autocomplete="username">
|
|
43
44
|
<input type="password" id="login-password" placeholder="Password" required autocomplete="current-password">
|
|
44
45
|
<button type="submit" class="auth-btn">Sign In</button>
|
|
45
46
|
<p class="auth-error" id="login-error"></p>
|
|
46
47
|
</form>
|
|
48
|
+
|
|
49
|
+
<!-- Register Form (hidden by default) -->
|
|
50
|
+
<form id="register-form" class="hidden">
|
|
51
|
+
<input type="text" id="register-username" placeholder="Username" required autocomplete="username">
|
|
52
|
+
<input type="email" id="register-email" placeholder="Email" required autocomplete="email">
|
|
53
|
+
<input type="password" id="register-password" placeholder="Password (min 8 chars)" required autocomplete="new-password" minlength="8">
|
|
54
|
+
<button type="submit" class="auth-btn">Create Account</button>
|
|
55
|
+
<p class="auth-error" id="register-error"></p>
|
|
56
|
+
</form>
|
|
57
|
+
|
|
47
58
|
<div class="auth-divider"><span>or</span></div>
|
|
48
59
|
<form id="license-form">
|
|
49
60
|
<input type="text" id="license-key" placeholder="Enter license key" autocomplete="off">
|
|
50
61
|
<button type="submit" class="auth-btn auth-btn-secondary">Activate License</button>
|
|
51
62
|
</form>
|
|
52
|
-
<p class="auth-footer">Don't have an account? <a href="
|
|
63
|
+
<p class="auth-footer" id="auth-toggle-text">Don't have an account? <a href="#" id="show-register">Sign up</a></p>
|
|
53
64
|
</div>
|
|
54
65
|
</div>
|
|
55
66
|
</div>
|