@singlebase/elements 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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/authui.cjs +2 -0
  4. package/dist/authui.cjs.map +1 -0
  5. package/dist/authui.d.ts +22 -0
  6. package/dist/authui.js +24 -0
  7. package/dist/authui.js.map +1 -0
  8. package/dist/controllers/auth-controller.d.ts +17 -0
  9. package/dist/controllers/event-bridge.d.ts +27 -0
  10. package/dist/controllers/settings-controller.d.ts +18 -0
  11. package/dist/display-8HEcKYR4.js +3444 -0
  12. package/dist/display-8HEcKYR4.js.map +1 -0
  13. package/dist/display-CLDNNZQy.cjs +976 -0
  14. package/dist/display-CLDNNZQy.cjs.map +1 -0
  15. package/dist/elements/account-screen.d.ts +99 -0
  16. package/dist/elements/auth-screen.d.ts +215 -0
  17. package/dist/elements/base.d.ts +69 -0
  18. package/dist/elements/buttons.d.ts +45 -0
  19. package/dist/elements/display.d.ts +51 -0
  20. package/dist/elements/form-base.d.ts +23 -0
  21. package/dist/elements/guard.d.ts +65 -0
  22. package/dist/elements/uploader.d.ts +225 -0
  23. package/dist/index.cjs +2 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.d.ts +7 -0
  26. package/dist/index.js +30 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/messages.d.ts +147 -0
  29. package/dist/singlebase-elements.min.js +7616 -0
  30. package/dist/singlebase-elements.min.js.map +1 -0
  31. package/dist/standalone.d.ts +2 -0
  32. package/dist/styles/shared.d.ts +8 -0
  33. package/dist/styles/tokens.d.ts +44 -0
  34. package/dist/upload-messages.d.ts +45 -0
  35. package/dist/uploader-D-Da1trc.js +2290 -0
  36. package/dist/uploader-D-Da1trc.js.map +1 -0
  37. package/dist/uploader-eFYKpk8b.cjs +1390 -0
  38. package/dist/uploader-eFYKpk8b.cjs.map +1 -0
  39. package/dist/uploader.cjs +2 -0
  40. package/dist/uploader.cjs.map +1 -0
  41. package/dist/uploader.d.ts +10 -0
  42. package/dist/uploader.js +9 -0
  43. package/dist/uploader.js.map +1 -0
  44. package/dist/utils/files.d.ts +38 -0
  45. package/dist/utils/inspect.d.ts +23 -0
  46. package/dist/utils/profile.d.ts +9 -0
  47. package/dist/utils/redirect.d.ts +15 -0
  48. package/package.json +76 -0
@@ -0,0 +1,3444 @@
1
+ var ts = Object.defineProperty;
2
+ var Te = (r) => {
3
+ throw TypeError(r);
4
+ };
5
+ var es = (r, t, e) => t in r ? ts(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
6
+ var b = (r, t, e) => es(r, typeof t != "symbol" ? t + "" : t, e), Ue = (r, t, e) => t.has(r) || Te("Cannot " + e);
7
+ var n = (r, t, e) => (Ue(r, t, "read from private field"), e ? e.call(r) : t.get(r)), o = (r, t, e) => t.has(r) ? Te("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(r) : t.set(r, e), l = (r, t, e, s) => (Ue(r, t, "write to private field"), s ? s.call(r, e) : t.set(r, e), e);
8
+ import { LitElement as ss, html as a, nothing as d, css as je } from "lit";
9
+ import { property as p, state as m, customElement as fe } from "lit/decorators.js";
10
+ import { ifDefined as k } from "lit/directives/if-defined.js";
11
+ import { SinglebaseAuthError as ye, mapErrorToHint as is, createFilesUploadApi as as, resolveScreen as rs } from "@singlebase/singlebase-sdk";
12
+ import { t as ns, s as os, r as ls } from "./uploader-D-Da1trc.js";
13
+ import { getDefaultClient as hs, AUTHUI_PROP_KEYS as ds, authUIAttributeFor as cs, matchesPredicate as us, validatePredicate as ps, getPath as Le } from "@singlebase/core";
14
+ class gs {
15
+ constructor(t) {
16
+ b(this, "host");
17
+ b(this, "client", null);
18
+ b(this, "unsubscribe", null);
19
+ b(this, "state", { status: "loading", session: null, user: null });
20
+ this.host = t, t.addController(this);
21
+ }
22
+ bind(t) {
23
+ var e;
24
+ t !== this.client && ((e = this.unsubscribe) == null || e.call(this), this.unsubscribe = null, this.client = t, t && (this.state = t.getState(), this.unsubscribe = t.subscribe((s) => {
25
+ this.state = s, this.host.requestUpdate();
26
+ }), this.host.requestUpdate()));
27
+ }
28
+ hostDisconnected() {
29
+ var t;
30
+ (t = this.unsubscribe) == null || t.call(this), this.unsubscribe = null;
31
+ }
32
+ }
33
+ const Ae = {
34
+ signInTitle: "Sign in",
35
+ signUpTitle: "Create your account",
36
+ forgotTitle: "Reset your password",
37
+ verifyTitle: "Enter your code",
38
+ otpTitle: "Sign in with a code",
39
+ newPassTitle: "Choose a new password",
40
+ inviteTitle: "You have been invited",
41
+ signInSubEmailAndOauth: "Use your email or a connected provider.",
42
+ signInSubEmailOnly: "Use your email address and password.",
43
+ signInSubOauthOnly: "Continue with a connected provider.",
44
+ signUpSub: "Free to start. No card required.",
45
+ forgotSub: "We will email you a six-digit code to confirm it is you.",
46
+ otpSub: "No password needed — we will email you a six-digit code.",
47
+ inviteSub: "Set up your account to continue.",
48
+ signInCta: "Sign in",
49
+ signUpCta: "Create account",
50
+ forgotCta: "Send code",
51
+ verifyCta: "Verify code",
52
+ otpCta: "Email me a code",
53
+ newPassCta: "Save password",
54
+ inviteCta: "Create account",
55
+ continueCta: "Continue",
56
+ backCta: "Back",
57
+ emailMethodTitle: "Email",
58
+ emailMethodTitleSignUp: "Email and password",
59
+ emailMethodMeta: "Password or one-time code",
60
+ emailMethodMetaSignUp: "Create with an address",
61
+ emailMethodMetaOtp: "One-time code",
62
+ oauthMethodTitle: "Single sign-on",
63
+ oauthMethodMeta: "Google, GitHub, and more",
64
+ fullNameLabel: "Full name",
65
+ fullNamePlaceholder: "Ada Lovelace",
66
+ emailLabel: "Email",
67
+ emailPlaceholder: "you@company.com",
68
+ passwordLabel: "Password",
69
+ passwordPlaceholder: "••••••••",
70
+ newPasswordLabel: "New password",
71
+ newPasswordPlaceholder: "At least 10 characters",
72
+ confirmPasswordLabel: "Confirm password",
73
+ confirmPasswordPlaceholder: "Repeat it",
74
+ currentPasswordLabel: "Current password",
75
+ firstNameLabel: "First name",
76
+ firstNamePlaceholder: "Ada",
77
+ lastNameLabel: "Last name",
78
+ lastNamePlaceholder: "Lovelace",
79
+ phoneLabel: "Phone number",
80
+ phonePlaceholder: "+1 (555) 000-0000",
81
+ invitedEmailLabel: "Invited email",
82
+ forgotLink: "Forgot?",
83
+ otpInsteadLink: "Email me a one-time code instead",
84
+ footTextSignIn: "New here?",
85
+ footActionSignIn: "Create an account",
86
+ footTextSignUp: "Already have an account?",
87
+ footActionSignUp: "Sign in",
88
+ resendQuestion: "Did not get it?",
89
+ resendCta: "Resend code",
90
+ oauthPrimaryLabel: "Continue with Google",
91
+ oauthContinueWith: "Continue with",
92
+ blockedTitleDisabled: "Sign-in is turned off",
93
+ blockedTitleUnavailable: "Sign-in unavailable",
94
+ blockedBodyDisabled: "Authentication is currently disabled for this application.",
95
+ blockedBodyUnavailable: "No sign-in methods are enabled for this application.",
96
+ blockedHint: "Contact the site owner if you think this is a mistake.",
97
+ signOutCta: "Sign out",
98
+ addPhotoLink: "Add photo",
99
+ changePhotoLink: "Change",
100
+ photoUploading: "Uploading…",
101
+ photoUpdated: "Photo updated",
102
+ editingLabel: "Editing",
103
+ uploadPhotoCta: "Upload photo",
104
+ replacePhotoCta: "Replace photo",
105
+ photoHint: "PNG or JPG, up to 2 MB.",
106
+ doneCta: "Done",
107
+ cancelCta: "Cancel",
108
+ editAccountCta: "Edit account",
109
+ saveChangesCta: "Save changes",
110
+ emailChangeHint: "We will send a verification link to the new address.",
111
+ passwordSectionTitle: "Password",
112
+ passwordChangedHint: "Last changed three months ago.",
113
+ changePasswordCta: "Change password",
114
+ updatePasswordCta: "Update password",
115
+ twoFaTitle: "Two-factor authentication",
116
+ twoFaHintOff: "Add a second step when signing in.",
117
+ twoFaHintOn: "Enabled with an authenticator app.",
118
+ twoFaScanHint: "Scan with your authenticator app, then enter the 6-digit code.",
119
+ connectedTitle: "Connected accounts",
120
+ connectedHint: "Sign in with any provider you connect here.",
121
+ addAnotherLabel: "Add another",
122
+ disconnectCta: "Disconnect",
123
+ notConnectedLabel: "Not connected",
124
+ deleteAccountCta: "Delete account",
125
+ deleteAccountConfirmCta: "Permanently delete account",
126
+ deletePanelBody: "This removes your profile, sessions and connected providers. It cannot be undone.",
127
+ deleteConfirmLabel: "Type DELETE to confirm",
128
+ deleteConfirmPlaceholder: "DELETE",
129
+ savedNote: "Saved",
130
+ passwordUpdatedNote: "Password updated",
131
+ changeEmailTitle: "Email",
132
+ newEmailLabel: "New email",
133
+ changeEmailCta: "Send verification code",
134
+ changeUsernameTitle: "Username",
135
+ newUsernameLabel: "New username",
136
+ changeUsernameCta: "Send verification code",
137
+ genericErrorMessage: "Something went wrong. Please try again.",
138
+ rateLimitedMessage: "Too many attempts. Try again in 5 minutes or reset your password.",
139
+ codeSentNeutral: "If an eligible account exists, a code has been sent.",
140
+ invalidEmailError: "Enter a valid email address.",
141
+ requiredError: "This cannot be empty.",
142
+ passwordMinError: "Use at least 10 characters.",
143
+ passwordMatchError: "Both passwords must match.",
144
+ codeIncompleteError: "Enter all six digits.",
145
+ invalidPhoneError: "Enter a valid phone number.",
146
+ notYetSupported: "Not yet supported",
147
+ alreadySignedInTitle: "You are already signed in",
148
+ alreadySignedInSub: "Continue where you left off, or sign out to use another account.",
149
+ alreadySignedInSubPrefix: "Signed in as",
150
+ continueHint: "Continuing takes you to your account.",
151
+ consentPrefix: "By continuing you agree to our",
152
+ consentJoin: "and",
153
+ termsLabel: "Terms",
154
+ privacyLabel: "Privacy Policy",
155
+ emailUnchangedError: "That is already your email address.",
156
+ emailUpdatedNote: "Email updated",
157
+ changeEmailCtaShort: "Change email",
158
+ changeEmailHint: "We will send a code to your current address to confirm it is you.",
159
+ changeEmailConfirmHint: "Enter the code we sent, and your email becomes",
160
+ changeEmailElsewhereHint: "Your email is changed below, with a verification step.",
161
+ confirmChangeCta: "Confirm change",
162
+ codeLabel: "Verification code",
163
+ brandingLabel: "Auth by Singlebase",
164
+ linkRequiresSignIn: "Sign in first, then link a provider.",
165
+ oauthCallbackTitle: "Finishing sign-in",
166
+ oauthCallbackSub: "One moment while we complete your sign-in.",
167
+ oauthDenied: "Sign-in was cancelled or denied."
168
+ };
169
+ function ms(r) {
170
+ return r ? { ...Ae, ...r } : Ae;
171
+ }
172
+ var bs = Object.defineProperty, fs = Object.getOwnPropertyDescriptor, ve = (r, t, e, s) => {
173
+ for (var i = fs(t, e), h = r.length - 1, c; h >= 0; h--)
174
+ (c = r[h]) && (i = c(t, e, i) || i);
175
+ return i && bs(t, e, i), i;
176
+ }, x, T, U, L, A;
177
+ class $ extends ss {
178
+ constructor() {
179
+ super(...arguments);
180
+ o(this, x, null);
181
+ o(this, T, {});
182
+ o(this, U);
183
+ o(this, L);
184
+ o(this, A);
185
+ b(this, "auth", new gs(this));
186
+ /** Config keys already applied, so a later render does not fight the host. */
187
+ b(this, "appliedConfig", /* @__PURE__ */ new Set());
188
+ }
189
+ get client() {
190
+ return n(this, x);
191
+ }
192
+ set client(e) {
193
+ l(this, x, e);
194
+ }
195
+ get messages() {
196
+ return n(this, T);
197
+ }
198
+ set messages(e) {
199
+ l(this, T, e);
200
+ }
201
+ get theme() {
202
+ return n(this, U);
203
+ }
204
+ set theme(e) {
205
+ l(this, U, e);
206
+ }
207
+ get density() {
208
+ return n(this, L);
209
+ }
210
+ set density(e) {
211
+ l(this, L, e);
212
+ }
213
+ get fieldStyle() {
214
+ return n(this, A);
215
+ }
216
+ set fieldStyle(e) {
217
+ l(this, A, e);
218
+ }
219
+ /**
220
+ * Resolution order: an explicit `.client`, then the page's default
221
+ * SinglebaseClient()'s auth.
222
+ *
223
+ * That fallback is what lets several widgets sit on one page — a header
224
+ * sign-in, a modal, an account panel — and share one session with no
225
+ * wiring, since SinglebaseClient() is cached per project. A page talking to
226
+ * two projects sets `.client` on the widgets belonging to the second.
227
+ *
228
+ * Reading `.auth` is also what *constructs* auth: a page that only drops
229
+ * in a widget initializes it with no bootstrap code at all.
230
+ */
231
+ get resolvedClient() {
232
+ var e;
233
+ return this.client ? this.client : ((e = hs()) == null ? void 0 : e.auth) ?? null;
234
+ }
235
+ /** Page-wide UI config from SinglebaseClient({ authui }), if there is one. */
236
+ get uiConfig() {
237
+ var e;
238
+ return ((e = this.resolvedClient) == null ? void 0 : e.authui) ?? null;
239
+ }
240
+ /**
241
+ * Config messages sit *under* the element's own, so a page-wide translation
242
+ * can be overridden per widget without repeating the whole bag.
243
+ */
244
+ get msg() {
245
+ var s;
246
+ const e = (s = this.uiConfig) == null ? void 0 : s.messages;
247
+ return ms(e ? { ...e, ...this.messages } : this.messages);
248
+ }
249
+ /**
250
+ * Copies the page-wide config onto this element.
251
+ *
252
+ * An attribute present in markup always wins — that is the whole precedence
253
+ * rule, and it is checked per key rather than wholesale, so a widget can
254
+ * override one thing and inherit the rest. Keys the element does not have
255
+ * are skipped, which is how one config can serve every singlebase-authui-*
256
+ * element without any of them knowing about the others.
257
+ */
258
+ applyUIConfig() {
259
+ const e = this.uiConfig;
260
+ if (e) {
261
+ for (const s of ds) {
262
+ const i = e[s];
263
+ i !== void 0 && s in this && (this.hasAttribute(cs(s)) || this.appliedConfig.has(s) || (this.appliedConfig.add(s), this[s] = i));
264
+ }
265
+ for (const [s, i] of Object.entries(e.tokens ?? {}))
266
+ s.startsWith("--") && (this.style.getPropertyValue(s) || this.style.setProperty(s, i));
267
+ }
268
+ }
269
+ // ── public API mirrored from the client, for host/SPA code ──
270
+ isAuthenticated() {
271
+ var e;
272
+ return ((e = this.resolvedClient) == null ? void 0 : e.isAuthenticated()) ?? !1;
273
+ }
274
+ getUser() {
275
+ var e;
276
+ return ((e = this.resolvedClient) == null ? void 0 : e.getUser()) ?? null;
277
+ }
278
+ async refreshSession() {
279
+ var e;
280
+ return (e = this.resolvedClient) == null ? void 0 : e.refreshSession();
281
+ }
282
+ async logout() {
283
+ var e;
284
+ await ((e = this.resolvedClient) == null ? void 0 : e.logout());
285
+ }
286
+ willUpdate(e) {
287
+ super.willUpdate(e), this.auth.bind(this.resolvedClient), this.applyUIConfig();
288
+ }
289
+ }
290
+ x = new WeakMap(), T = new WeakMap(), U = new WeakMap(), L = new WeakMap(), A = new WeakMap(), b($, "styles", [ns, os]);
291
+ ve([
292
+ p({ attribute: !1 })
293
+ ], $.prototype, "client");
294
+ ve([
295
+ p({ attribute: !1 })
296
+ ], $.prototype, "messages");
297
+ ve([
298
+ p({ reflect: !0 })
299
+ ], $.prototype, "theme");
300
+ ve([
301
+ p({ reflect: !0 })
302
+ ], $.prototype, "density");
303
+ ve([
304
+ p({ reflect: !0, attribute: "field-style" })
305
+ ], $.prototype, "fieldStyle");
306
+ class Se {
307
+ constructor(t) {
308
+ b(this, "host");
309
+ b(this, "client", null);
310
+ b(this, "cache", /* @__PURE__ */ new WeakMap());
311
+ b(this, "settings", null);
312
+ b(this, "error", null);
313
+ this.host = t, t.addController(this);
314
+ }
315
+ hostConnected() {
316
+ }
317
+ load(t, e) {
318
+ if (e) {
319
+ this.settings = e;
320
+ return;
321
+ }
322
+ if (!t || t === this.client) return;
323
+ this.client = t;
324
+ let s = this.cache.get(t);
325
+ s || (s = t.getSettings(), this.cache.set(t, s)), s.then((i) => {
326
+ this.settings = i, this.error = null, this.host.requestUpdate();
327
+ }).catch((i) => {
328
+ this.error = i, this.host.requestUpdate();
329
+ });
330
+ }
331
+ }
332
+ const vs = [
333
+ "load",
334
+ "success",
335
+ "error",
336
+ "signin",
337
+ "signup",
338
+ "signout",
339
+ "session",
340
+ "account-updated",
341
+ "password-change",
342
+ "email-change",
343
+ "username-change",
344
+ "expired",
345
+ "navigate",
346
+ "goto"
347
+ ], ws = {
348
+ load: "auth:ready",
349
+ signin: "auth:signin",
350
+ signup: "auth:signup",
351
+ session: "auth:session",
352
+ "account-updated": "auth:profile-update",
353
+ signout: "auth:signout",
354
+ error: "auth:error",
355
+ navigate: "auth:navigate"
356
+ };
357
+ function Me(r) {
358
+ return "on" + r.replace(/(^|-)([a-z])/g, (t, e, s) => s.toUpperCase());
359
+ }
360
+ class $s {
361
+ constructor(t) {
362
+ b(this, "unsubscribes", []);
363
+ b(this, "client", null);
364
+ this.host = t, t.addController(this);
365
+ }
366
+ bind(t) {
367
+ t !== this.client && (this.release(), this.client = t, t && (this.unsubscribes = vs.map(
368
+ (e) => t.on(e, (s) => this.publish(e, s))
369
+ )));
370
+ }
371
+ publish(t, e) {
372
+ const s = this.host[Me(t)];
373
+ if (typeof s == "function")
374
+ try {
375
+ s.call(this.host, e);
376
+ } catch (c) {
377
+ console.error(`[singlebase] ${Me(t)} threw:`, c);
378
+ }
379
+ const i = { detail: e, bubbles: !0, composed: !0 };
380
+ this.host.dispatchEvent(new CustomEvent(`singlebase-${t}`, i));
381
+ const h = ws[t];
382
+ h && this.host.dispatchEvent(new CustomEvent(h, i));
383
+ }
384
+ release() {
385
+ this.unsubscribes.forEach((t) => t()), this.unsubscribes = [];
386
+ }
387
+ hostDisconnected() {
388
+ this.release(), this.client = null;
389
+ }
390
+ }
391
+ var ys = Object.defineProperty, Es = Object.getOwnPropertyDescriptor, Ce = (r, t, e, s) => {
392
+ for (var i = Es(t, e), h = r.length - 1, c; h >= 0; h--)
393
+ (c = r[h]) && (i = c(t, e, i) || i);
394
+ return i && ys(t, e, i), i;
395
+ }, M, N, I;
396
+ class we extends $ {
397
+ constructor() {
398
+ super(...arguments);
399
+ o(this, M, "idle");
400
+ o(this, N, "");
401
+ o(this, I, "");
402
+ b(this, "abortController", null);
403
+ }
404
+ get phase() {
405
+ return n(this, M);
406
+ }
407
+ set phase(e) {
408
+ l(this, M, e);
409
+ }
410
+ get formError() {
411
+ return n(this, N);
412
+ }
413
+ set formError(e) {
414
+ l(this, N, e);
415
+ }
416
+ get noticeMessage() {
417
+ return n(this, I);
418
+ }
419
+ set noticeMessage(e) {
420
+ l(this, I, e);
421
+ }
422
+ disconnectedCallback() {
423
+ var e;
424
+ super.disconnectedCallback(), (e = this.abortController) == null || e.abort();
425
+ }
426
+ get signal() {
427
+ var e;
428
+ return (e = this.abortController) == null || e.abort(), this.abortController = new AbortController(), this.abortController.signal;
429
+ }
430
+ /** Runs task, tracking idle→submitting→success/error and mapping errors to a message. */
431
+ async run(e) {
432
+ this.phase = "submitting", this.formError = "";
433
+ try {
434
+ await e(), this.phase = "success";
435
+ } catch (s) {
436
+ if (this.isAbortError(s)) return;
437
+ this.phase = "error", this.formError = this.describeError(s);
438
+ }
439
+ }
440
+ isAbortError(e) {
441
+ return e instanceof DOMException && e.name === "AbortError";
442
+ }
443
+ describeError(e) {
444
+ if (e instanceof ye) {
445
+ const s = is(e.code);
446
+ return s === "disable_retry_show_rate_limited" ? this.msg.rateLimitedMessage : s === "generic_credentials_message" ? this.msg.genericErrorMessage : this.msg.genericErrorMessage;
447
+ }
448
+ return this.msg.genericErrorMessage;
449
+ }
450
+ get submitting() {
451
+ return this.phase === "submitting";
452
+ }
453
+ /** aria-live region for async status — spec requires one per form. */
454
+ renderStatus() {
455
+ return a`
456
+ <div
457
+ role="status"
458
+ aria-live="polite"
459
+ style="position:absolute;width:1px;height:1px;overflow:hidden;"
460
+ >
461
+ ${this.phase === "submitting" ? "Submitting…" : ""}
462
+ ${this.phase === "success" ? "Done." : ""}
463
+ </div>
464
+ ${this.formError ? a`<p class="banner" role="alert">${this.formError}</p>` : null}
465
+ ${this.noticeMessage ? a`<p class="notice" role="status">${this.noticeMessage}</p>` : null}
466
+ `;
467
+ }
468
+ }
469
+ M = new WeakMap(), N = new WeakMap(), I = new WeakMap();
470
+ Ce([
471
+ m()
472
+ ], we.prototype, "phase");
473
+ Ce([
474
+ m()
475
+ ], we.prototype, "formError");
476
+ Ce([
477
+ m()
478
+ ], we.prototype, "noticeMessage");
479
+ function qe(r) {
480
+ return [r == null ? void 0 : r.first_name, r == null ? void 0 : r.last_name].filter(Boolean).join(" ").trim();
481
+ }
482
+ function Ge(r) {
483
+ const t = qe(r);
484
+ if (t)
485
+ return t.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase();
486
+ const e = (r == null ? void 0 : r.email) ?? "";
487
+ return e ? e[0].toUpperCase() : "·";
488
+ }
489
+ var Ss = Object.defineProperty, Cs = Object.getOwnPropertyDescriptor, v = (r, t, e, s) => {
490
+ for (var i = s > 1 ? void 0 : s ? Cs(t, e) : t, h = r.length - 1, c; h >= 0; h--)
491
+ (c = r[h]) && (i = (s ? c(t, e, i) : c(i)) || i);
492
+ return s && i && Ss(t, e, i), i;
493
+ };
494
+ const Ps = { profile_photo: !0 }, ks = ".jpg,.jpeg,.png,.webp,image/jpeg,image/png,image/webp";
495
+ var F, D, B, R, H, j, q, G, V, K, Y, W, z, J, Q, X, Z, tt, et, st, it, at, rt, nt, ot, lt, Fe;
496
+ let f = (Fe = class extends we {
497
+ constructor() {
498
+ super(...arguments);
499
+ o(this, F, "");
500
+ o(this, D, "");
501
+ o(this, B, null);
502
+ o(this, R, "singlebase-oauth-nonce");
503
+ o(this, H, "");
504
+ o(this, j, "");
505
+ o(this, q, !1);
506
+ o(this, G, "");
507
+ o(this, V, "");
508
+ o(this, K, "");
509
+ o(this, Y, "");
510
+ o(this, W, "");
511
+ o(this, z, 0);
512
+ o(this, J, "");
513
+ o(this, Q, "");
514
+ o(this, X, "");
515
+ o(this, Z, "");
516
+ o(this, tt, "");
517
+ o(this, et, "request");
518
+ o(this, st, "");
519
+ o(this, it, "");
520
+ o(this, at, "");
521
+ o(this, rt, "");
522
+ o(this, nt, "");
523
+ o(this, ot, "");
524
+ o(this, lt, "");
525
+ b(this, "settingsCtl", new Se(this));
526
+ b(this, "flashTimer");
527
+ b(this, "uidBase", `sb-acct-${Math.random().toString(36).slice(2, 8)}`);
528
+ // ── profile photo ─────────────────────────────────────────
529
+ b(this, "uploadClientFor", null);
530
+ b(this, "uploadClientCache", null);
531
+ b(this, "onChoosePhoto", () => {
532
+ var t;
533
+ this.formError = "", (t = this.renderRoot.querySelector("singlebase-uploader")) == null || t.open();
534
+ });
535
+ b(this, "onPhotoSelected", () => {
536
+ this.photoBusy = !0, this.toast = "";
537
+ });
538
+ /** The server has set the photo; read the account back to get its URL. */
539
+ b(this, "onPhotoUploaded", async (t) => {
540
+ var i;
541
+ const { completed: e, failed: s } = t.detail;
542
+ try {
543
+ e.length ? (await ((i = this.resolvedClient) == null ? void 0 : i.getAccount()), this.photoFailed = "", this.toast = this.msg.photoUpdated) : s.length && (this.formError = s[0].error || this.msg.genericErrorMessage);
544
+ } catch (h) {
545
+ this.formError = this.describeError(h);
546
+ } finally {
547
+ this.photoBusy = !1;
548
+ }
549
+ });
550
+ b(this, "onPhotoProblem", (t) => {
551
+ this.photoBusy = !1, this.formError = t.detail.message;
552
+ });
553
+ }
554
+ get logoText() {
555
+ return n(this, F);
556
+ }
557
+ set logoText(t) {
558
+ l(this, F, t);
559
+ }
560
+ get logoUrl() {
561
+ return n(this, D);
562
+ }
563
+ set logoUrl(t) {
564
+ l(this, D, t);
565
+ }
566
+ get settings() {
567
+ return n(this, B);
568
+ }
569
+ set settings(t) {
570
+ l(this, B, t);
571
+ }
572
+ get nonceStorageKey() {
573
+ return n(this, R);
574
+ }
575
+ set nonceStorageKey(t) {
576
+ l(this, R, t);
577
+ }
578
+ get editMode() {
579
+ return n(this, H);
580
+ }
581
+ set editMode(t) {
582
+ l(this, H, t);
583
+ }
584
+ get toast() {
585
+ return n(this, j);
586
+ }
587
+ set toast(t) {
588
+ l(this, j, t);
589
+ }
590
+ get photoBusy() {
591
+ return n(this, q);
592
+ }
593
+ set photoBusy(t) {
594
+ l(this, q, t);
595
+ }
596
+ get photoFailed() {
597
+ return n(this, G);
598
+ }
599
+ set photoFailed(t) {
600
+ l(this, G, t);
601
+ }
602
+ get profileSaved() {
603
+ return n(this, V);
604
+ }
605
+ set profileSaved(t) {
606
+ l(this, V, t);
607
+ }
608
+ get passSaved() {
609
+ return n(this, K);
610
+ }
611
+ set passSaved(t) {
612
+ l(this, K, t);
613
+ }
614
+ get profileError() {
615
+ return n(this, Y);
616
+ }
617
+ set profileError(t) {
618
+ l(this, Y, t);
619
+ }
620
+ get newPassError() {
621
+ return n(this, W);
622
+ }
623
+ set newPassError(t) {
624
+ l(this, W, t);
625
+ }
626
+ get deleteStage() {
627
+ return n(this, z);
628
+ }
629
+ set deleteStage(t) {
630
+ l(this, z, t);
631
+ }
632
+ get confirmText() {
633
+ return n(this, J);
634
+ }
635
+ set confirmText(t) {
636
+ l(this, J, t);
637
+ }
638
+ get dFirst() {
639
+ return n(this, Q);
640
+ }
641
+ set dFirst(t) {
642
+ l(this, Q, t);
643
+ }
644
+ get dLast() {
645
+ return n(this, X);
646
+ }
647
+ set dLast(t) {
648
+ l(this, X, t);
649
+ }
650
+ get dPhone() {
651
+ return n(this, Z);
652
+ }
653
+ set dPhone(t) {
654
+ l(this, Z, t);
655
+ }
656
+ get dEmail() {
657
+ return n(this, tt);
658
+ }
659
+ set dEmail(t) {
660
+ l(this, tt, t);
661
+ }
662
+ get emailStep() {
663
+ return n(this, et);
664
+ }
665
+ set emailStep(t) {
666
+ l(this, et, t);
667
+ }
668
+ get dNewEmail() {
669
+ return n(this, st);
670
+ }
671
+ set dNewEmail(t) {
672
+ l(this, st, t);
673
+ }
674
+ get emailCode() {
675
+ return n(this, it);
676
+ }
677
+ set emailCode(t) {
678
+ l(this, it, t);
679
+ }
680
+ get emailError() {
681
+ return n(this, at);
682
+ }
683
+ set emailError(t) {
684
+ l(this, at, t);
685
+ }
686
+ get emailSaved() {
687
+ return n(this, rt);
688
+ }
689
+ set emailSaved(t) {
690
+ l(this, rt, t);
691
+ }
692
+ get curPass() {
693
+ return n(this, nt);
694
+ }
695
+ set curPass(t) {
696
+ l(this, nt, t);
697
+ }
698
+ get newPass() {
699
+ return n(this, ot);
700
+ }
701
+ set newPass(t) {
702
+ l(this, ot, t);
703
+ }
704
+ get confirmPass() {
705
+ return n(this, lt);
706
+ }
707
+ set confirmPass(t) {
708
+ l(this, lt, t);
709
+ }
710
+ uid(t) {
711
+ return `${this.uidBase}-${t}`;
712
+ }
713
+ willUpdate(t) {
714
+ super.willUpdate(t), this.settingsCtl.load(this.resolvedClient, this.settings);
715
+ }
716
+ disconnectedCallback() {
717
+ super.disconnectedCallback(), clearTimeout(this.flashTimer);
718
+ }
719
+ flash(t, e) {
720
+ this[t] = e, clearTimeout(this.flashTimer), this.flashTimer = setTimeout(() => {
721
+ this[t] = "";
722
+ }, 2600);
723
+ }
724
+ /** Matches the guest screens: image when given one, else the text label. */
725
+ renderLogo() {
726
+ return this.logoUrl ? a`<img
727
+ part="logo"
728
+ src=${this.logoUrl}
729
+ alt=${this.logoText}
730
+ style="display:block;align-self:flex-start;height:var(--sb-logo-height,20px);width:auto;max-width:100%"
731
+ />` : this.logoText ? a`<div class="logo-dot" part="logo">${this.logoText}</div>` : d;
732
+ }
733
+ get user() {
734
+ const t = this.auth.state;
735
+ return t.status === "authenticated" ? t.user : null;
736
+ }
737
+ get fullName() {
738
+ return qe(this.user);
739
+ }
740
+ get initials() {
741
+ return Ge(this.user);
742
+ }
743
+ /**
744
+ * The upload API bound to the same dispatcher as this widget's auth client,
745
+ * so the photo goes to the same project with the same bearer — including on
746
+ * a page where this widget was given its own `.client`.
747
+ */
748
+ get uploadClient() {
749
+ const t = this.resolvedClient;
750
+ return t ? (this.uploadClientFor !== t && (this.uploadClientFor = t, this.uploadClientCache = { files: as(t.dispatcher) }), this.uploadClientCache) : null;
751
+ }
752
+ startProfileEdit() {
753
+ const t = this.user;
754
+ t && (this.dFirst = t.first_name ?? "", this.dLast = t.last_name ?? "", this.dPhone = t.phone ?? "", this.dEmail = t.email, this.profileError = "", this.profileSaved = "", this.passSaved = "", this.toast = "", this.editMode = "profile");
755
+ }
756
+ async onSaveProfile() {
757
+ const t = this.resolvedClient;
758
+ if (t) {
759
+ if (!this.dFirst.trim() || !this.dLast.trim()) {
760
+ this.profileError = "First and last name cannot be empty.";
761
+ return;
762
+ }
763
+ if (this.dPhone.replace(/\D/g, "").length < 7) {
764
+ this.profileError = this.msg.invalidPhoneError;
765
+ return;
766
+ }
767
+ await this.run(async () => {
768
+ await t.updateAccount(
769
+ { first_name: this.dFirst, last_name: this.dLast, phone: this.dPhone },
770
+ this.signal
771
+ ), this.editMode = "", this.flash("profileSaved", this.msg.savedNote);
772
+ });
773
+ }
774
+ }
775
+ startPassEdit() {
776
+ this.curPass = "", this.newPass = "", this.confirmPass = "", this.newPassError = "", this.passSaved = "", this.profileSaved = "", this.toast = "", this.editMode = "password";
777
+ }
778
+ async onChangePass() {
779
+ const t = this.resolvedClient;
780
+ if (t) {
781
+ if (!this.curPass) {
782
+ this.newPassError = "Enter your current password.";
783
+ return;
784
+ }
785
+ if (this.newPass.length < 10) {
786
+ this.newPassError = this.msg.passwordMinError;
787
+ return;
788
+ }
789
+ if (this.newPass !== this.confirmPass) {
790
+ this.newPassError = this.msg.passwordMatchError;
791
+ return;
792
+ }
793
+ await this.run(async () => {
794
+ await t.changePassword({ password: this.newPass }, this.signal), this.editMode = "", this.curPass = "", this.newPass = "", this.confirmPass = "", this.flash("passSaved", this.msg.passwordUpdatedNote);
795
+ });
796
+ }
797
+ }
798
+ // ── email change ─────────────────────────────────────────
799
+ startEmailEdit() {
800
+ this.emailStep = "request", this.dNewEmail = "", this.emailCode = "", this.emailError = "", this.emailSaved = "", this.toast = "", this.editMode = "email";
801
+ }
802
+ /**
803
+ * Step one: ask for a code. The code goes to the address on file, not to
804
+ * the new one — that is what proves the person asking already controls the
805
+ * account rather than merely knowing an address.
806
+ */
807
+ async onRequestEmailCode() {
808
+ const t = this.resolvedClient;
809
+ if (!(!t || !this.user)) {
810
+ if (!this.dNewEmail.includes("@")) {
811
+ this.emailError = this.msg.invalidEmailError;
812
+ return;
813
+ }
814
+ if (this.dNewEmail.toLowerCase() === this.user.email.toLowerCase()) {
815
+ this.emailError = this.msg.emailUnchangedError;
816
+ return;
817
+ }
818
+ await this.run(async () => {
819
+ await t.requestCode({ email: this.user.email, purpose: "email_change" }, this.signal), this.emailStep = "confirm", this.emailError = "";
820
+ });
821
+ }
822
+ }
823
+ /** Step two: confirm the code together with the new address. */
824
+ async onConfirmEmailChange() {
825
+ const t = this.resolvedClient;
826
+ if (!(!t || !this.user)) {
827
+ if (this.emailCode.length < 6) {
828
+ this.emailError = this.msg.codeIncompleteError;
829
+ return;
830
+ }
831
+ await this.run(async () => {
832
+ await t.changeEmail(
833
+ { email: this.user.email, code: this.emailCode, new_email: this.dNewEmail },
834
+ this.signal
835
+ ), this.editMode = "", this.emailCode = "", this.dNewEmail = "", this.flash("emailSaved", this.msg.emailUpdatedNote);
836
+ });
837
+ }
838
+ }
839
+ renderEmailSection() {
840
+ var s;
841
+ const t = this.editMode !== "email", e = this.editMode !== "" && this.editMode !== "email";
842
+ return a`
843
+ <div class="rule"></div>
844
+ <div class="section">
845
+ <h3 class="sec-title">${this.msg.changeEmailTitle}</h3>
846
+ ${t ? a`
847
+ <div class="between">
848
+ <p class="hint">${((s = this.user) == null ? void 0 : s.email) ?? ""}</p>
849
+ <div class="btn-row-end">
850
+ ${this.emailSaved ? a`<span role="status" class="saved-note">${this.emailSaved}</span>` : d}
851
+ <button
852
+ type="button"
853
+ class="edit-link"
854
+ ?disabled=${e}
855
+ @click=${this.startEmailEdit}
856
+ >
857
+ ${this.msg.changeEmailCtaShort}
858
+ </button>
859
+ </div>
860
+ </div>
861
+ ` : this.emailStep === "request" ? a`
862
+ <div class="edit-card">
863
+ <div class="field">
864
+ <label for=${this.uid("newemail")}>${this.msg.newEmailLabel}</label>
865
+ <input
866
+ id=${this.uid("newemail")}
867
+ type="email"
868
+ part="input"
869
+ .value=${this.dNewEmail}
870
+ placeholder=${this.msg.emailPlaceholder}
871
+ aria-invalid=${this.emailError ? "true" : "false"}
872
+ ?disabled=${this.submitting}
873
+ @input=${(i) => {
874
+ this.dNewEmail = i.target.value, this.emailError = "";
875
+ }}
876
+ />
877
+ <p class="hint">${this.msg.changeEmailHint}</p>
878
+ </div>
879
+ ${this.emailError ? a`<p class="err">${this.emailError}</p>` : d}
880
+ <div class="edit-actions">
881
+ <button
882
+ type="button"
883
+ class="primary-sm"
884
+ ?disabled=${this.submitting}
885
+ @click=${this.onRequestEmailCode}
886
+ >
887
+ ${this.submitting ? a`<span class="spinner"></span>` : d}
888
+ <span>${this.msg.changeEmailCta}</span>
889
+ </button>
890
+ <button
891
+ type="button"
892
+ class="ghost-sm"
893
+ @click=${() => {
894
+ this.editMode = "", this.emailError = "";
895
+ }}
896
+ >
897
+ ${this.msg.cancelCta}
898
+ </button>
899
+ </div>
900
+ </div>
901
+ ` : a`
902
+ <div class="edit-card">
903
+ <p class="hint">${this.msg.codeSentNeutral}</p>
904
+ <div class="field">
905
+ <label for=${this.uid("emailcode")}>${this.msg.codeLabel}</label>
906
+ <input
907
+ id=${this.uid("emailcode")}
908
+ type="text"
909
+ inputmode="numeric"
910
+ autocomplete="one-time-code"
911
+ part="input"
912
+ .value=${this.emailCode}
913
+ placeholder="000000"
914
+ aria-invalid=${this.emailError ? "true" : "false"}
915
+ ?disabled=${this.submitting}
916
+ @input=${(i) => {
917
+ this.emailCode = i.target.value.replace(/\D/g, "").slice(0, 6), this.emailError = "";
918
+ }}
919
+ />
920
+ <p class="hint">${this.msg.changeEmailConfirmHint} ${this.dNewEmail}</p>
921
+ </div>
922
+ ${this.emailError ? a`<p class="err">${this.emailError}</p>` : d}
923
+ <div class="edit-actions">
924
+ <button
925
+ type="button"
926
+ class="primary-sm"
927
+ ?disabled=${this.submitting}
928
+ @click=${this.onConfirmEmailChange}
929
+ >
930
+ ${this.submitting ? a`<span class="spinner"></span>` : d}
931
+ <span>${this.msg.confirmChangeCta}</span>
932
+ </button>
933
+ <button
934
+ type="button"
935
+ class="ghost-sm"
936
+ @click=${() => {
937
+ this.editMode = "", this.emailError = "";
938
+ }}
939
+ >
940
+ ${this.msg.cancelCta}
941
+ </button>
942
+ </div>
943
+ </div>
944
+ `}
945
+ </div>
946
+ `;
947
+ }
948
+ async onSignOut() {
949
+ const t = this.resolvedClient;
950
+ t && await this.run(async () => {
951
+ await t.signOut();
952
+ });
953
+ }
954
+ async onConnectProvider(t) {
955
+ const e = this.resolvedClient, s = this.auth.state;
956
+ !e || s.status !== "authenticated" || await this.run(async () => {
957
+ var c;
958
+ const i = await e.createOAuthNonce(this.signal);
959
+ (c = globalThis.sessionStorage) == null || c.setItem(this.nonceStorageKey, i);
960
+ const { oauth_redirect_url: h } = await e.startOAuth(
961
+ {
962
+ provider: t,
963
+ nonce: i,
964
+ intent: "link",
965
+ id_token: s.session.id_token,
966
+ refresh_token: s.session.refresh_token
967
+ },
968
+ this.signal
969
+ );
970
+ globalThis.location.assign(h);
971
+ });
972
+ }
973
+ get availableProviders() {
974
+ const t = this.settings ?? this.settingsCtl.settings;
975
+ if (!t || !t.oauth_settings.enabled) return [];
976
+ const e = {
977
+ google: "G",
978
+ github: "GH",
979
+ linkedin: "in",
980
+ facebook: "f"
981
+ };
982
+ return Object.entries(t.oauth_providers).filter(([, s]) => s.enabled).map(([s, i]) => ({
983
+ id: s,
984
+ name: i.provider_name,
985
+ mark: e[s] ?? i.provider_name.slice(0, 2)
986
+ }));
987
+ }
988
+ // ── sections ──────────────────────────────────────────────
989
+ renderIdentity() {
990
+ const t = this.user, e = this.editMode !== "" && this.editMode !== "avatar", s = t != null && t.profile_photo && t.profile_photo !== this.photoFailed ? t.profile_photo : "";
991
+ return a`
992
+ <div class="acct-nav">
993
+ <div class="acct-who">
994
+ <div class="avatar-col">
995
+ <div class="avatar ${s ? "has-photo" : ""}" part="avatar">
996
+ ${s ? a`<img
997
+ src=${s}
998
+ alt=""
999
+ part="avatar-image"
1000
+ @error=${() => this.photoFailed = s}
1001
+ />` : this.initials}
1002
+ </div>
1003
+ <button
1004
+ type="button"
1005
+ class="edit-link"
1006
+ style="font-size:12px"
1007
+ ?disabled=${this.photoBusy || e}
1008
+ @click=${this.onChoosePhoto}
1009
+ >
1010
+ ${this.photoBusy ? this.msg.photoUploading : t != null && t.profile_photo ? this.msg.changePhotoLink : this.msg.addPhotoLink}
1011
+ </button>
1012
+ <singlebase-uploader
1013
+ style="display:none"
1014
+ view="button"
1015
+ max-files="1"
1016
+ branding="false"
1017
+ accept=${ks}
1018
+ .client=${this.uploadClient}
1019
+ .options=${Ps}
1020
+ @singlebase-upload-selected=${this.onPhotoSelected}
1021
+ @singlebase-upload-complete=${this.onPhotoUploaded}
1022
+ @singlebase-upload-error=${this.onPhotoProblem}
1023
+ @singlebase-upload-rejected=${this.onPhotoProblem}
1024
+ ></singlebase-uploader>
1025
+ </div>
1026
+ <div class="acct-who-text">
1027
+ <div class="acct-name">${this.fullName || "—"}</div>
1028
+ <div class="acct-email">${(t == null ? void 0 : t.email) ?? ""}</div>
1029
+ </div>
1030
+ </div>
1031
+ <button type="button" class="link-sm" ?disabled=${this.submitting} @click=${this.onSignOut}>
1032
+ ${this.msg.signOutCta}
1033
+ </button>
1034
+ </div>
1035
+ `;
1036
+ }
1037
+ renderProfileSection() {
1038
+ const t = this.user;
1039
+ if (!t) return d;
1040
+ const e = this.editMode !== "profile", s = this.editMode !== "" && this.editMode !== "profile", i = [
1041
+ [this.msg.firstNameLabel, t.first_name || "—"],
1042
+ [this.msg.lastNameLabel, t.last_name || "—"],
1043
+ [this.msg.phoneLabel, t.phone || "—"],
1044
+ [this.msg.emailLabel, t.email || "—"]
1045
+ ];
1046
+ return a`
1047
+ <div class="section">
1048
+ ${e ? a`
1049
+ <div class="sum-list">
1050
+ ${i.map(
1051
+ ([h, c]) => a`
1052
+ <div class="sum-row">
1053
+ <span class="sum-label">${h}</span>
1054
+ <span class="sum-value">${c}</span>
1055
+ </div>
1056
+ `
1057
+ )}
1058
+ </div>
1059
+ <div class="btn-row-end">
1060
+ ${this.profileSaved ? a`<span role="status" class="saved-note">${this.profileSaved}</span>` : d}
1061
+ <button
1062
+ type="button"
1063
+ class="edit-link"
1064
+ ?disabled=${s}
1065
+ @click=${this.startProfileEdit}
1066
+ >
1067
+ ${this.msg.editAccountCta}
1068
+ </button>
1069
+ </div>
1070
+ ` : a`
1071
+ <div class="edit-card">
1072
+ <div class="two-up">
1073
+ <div class="field">
1074
+ <label for=${this.uid("first")}>${this.msg.firstNameLabel}</label>
1075
+ <input
1076
+ id=${this.uid("first")}
1077
+ type="text"
1078
+ part="input"
1079
+ .value=${this.dFirst}
1080
+ placeholder=${this.msg.firstNamePlaceholder}
1081
+ ?disabled=${this.submitting}
1082
+ @input=${(h) => {
1083
+ this.dFirst = h.target.value, this.profileError = "";
1084
+ }}
1085
+ />
1086
+ </div>
1087
+ <div class="field">
1088
+ <label for=${this.uid("last")}>${this.msg.lastNameLabel}</label>
1089
+ <input
1090
+ id=${this.uid("last")}
1091
+ type="text"
1092
+ part="input"
1093
+ .value=${this.dLast}
1094
+ placeholder=${this.msg.lastNamePlaceholder}
1095
+ ?disabled=${this.submitting}
1096
+ @input=${(h) => {
1097
+ this.dLast = h.target.value, this.profileError = "";
1098
+ }}
1099
+ />
1100
+ </div>
1101
+ </div>
1102
+ <div class="field">
1103
+ <label for=${this.uid("phone")}>${this.msg.phoneLabel}</label>
1104
+ <input
1105
+ id=${this.uid("phone")}
1106
+ type="tel"
1107
+ part="input"
1108
+ .value=${this.dPhone}
1109
+ placeholder=${this.msg.phonePlaceholder}
1110
+ ?disabled=${this.submitting}
1111
+ @input=${(h) => {
1112
+ this.dPhone = h.target.value, this.profileError = "";
1113
+ }}
1114
+ />
1115
+ </div>
1116
+ <div class="field">
1117
+ <label for=${this.uid("email")}>${this.msg.emailLabel}</label>
1118
+ <input
1119
+ id=${this.uid("email")}
1120
+ type="email"
1121
+ part="input"
1122
+ .value=${this.dEmail}
1123
+ disabled
1124
+ title=${this.msg.notYetSupported}
1125
+ />
1126
+ <p class="hint">${this.msg.changeEmailElsewhereHint}</p>
1127
+ </div>
1128
+ ${this.profileError ? a`<p class="err">${this.profileError}</p>` : d}
1129
+ <div class="edit-actions">
1130
+ <button
1131
+ type="button"
1132
+ class="primary-sm"
1133
+ ?disabled=${this.submitting}
1134
+ @click=${this.onSaveProfile}
1135
+ >
1136
+ ${this.submitting ? a`<span class="spinner"></span>` : d}
1137
+ <span>${this.msg.saveChangesCta}</span>
1138
+ </button>
1139
+ <button
1140
+ type="button"
1141
+ class="ghost-sm"
1142
+ @click=${() => {
1143
+ this.editMode = "", this.profileError = "";
1144
+ }}
1145
+ >
1146
+ ${this.msg.cancelCta}
1147
+ </button>
1148
+ </div>
1149
+ </div>
1150
+ `}
1151
+ </div>
1152
+ `;
1153
+ }
1154
+ renderPasswordSection() {
1155
+ const t = this.editMode !== "password", e = this.editMode !== "" && this.editMode !== "password";
1156
+ return a`
1157
+ <div class="rule"></div>
1158
+ <div class="section">
1159
+ <h3 class="sec-title">${this.msg.passwordSectionTitle}</h3>
1160
+ ${t ? a`
1161
+ <div class="between">
1162
+ <p class="hint">${this.msg.passwordChangedHint}</p>
1163
+ <div class="btn-row-end">
1164
+ ${this.passSaved ? a`<span role="status" class="saved-note">${this.passSaved}</span>` : d}
1165
+ <button
1166
+ type="button"
1167
+ class="edit-link"
1168
+ ?disabled=${e}
1169
+ @click=${this.startPassEdit}
1170
+ >
1171
+ ${this.msg.changePasswordCta}
1172
+ </button>
1173
+ </div>
1174
+ </div>
1175
+ ` : a`
1176
+ <div class="edit-card">
1177
+ <div class="field">
1178
+ <label for=${this.uid("curpass")}>${this.msg.currentPasswordLabel}</label>
1179
+ <input
1180
+ id=${this.uid("curpass")}
1181
+ type="password"
1182
+ part="input"
1183
+ .value=${this.curPass}
1184
+ placeholder=${this.msg.passwordPlaceholder}
1185
+ ?disabled=${this.submitting}
1186
+ @input=${(s) => {
1187
+ this.curPass = s.target.value, this.newPassError = "";
1188
+ }}
1189
+ />
1190
+ </div>
1191
+ <div class="field">
1192
+ <label for=${this.uid("newpass")}>${this.msg.newPasswordLabel}</label>
1193
+ <input
1194
+ id=${this.uid("newpass")}
1195
+ type="password"
1196
+ part="input"
1197
+ .value=${this.newPass}
1198
+ placeholder=${this.msg.newPasswordPlaceholder}
1199
+ aria-invalid=${this.newPassError ? "true" : "false"}
1200
+ ?disabled=${this.submitting}
1201
+ @input=${(s) => {
1202
+ this.newPass = s.target.value, this.newPassError = "";
1203
+ }}
1204
+ />
1205
+ </div>
1206
+ <div class="field">
1207
+ <label for=${this.uid("confirmpass")}>Confirm new password</label>
1208
+ <input
1209
+ id=${this.uid("confirmpass")}
1210
+ type="password"
1211
+ part="input"
1212
+ .value=${this.confirmPass}
1213
+ placeholder=${this.msg.confirmPasswordPlaceholder}
1214
+ aria-invalid=${this.newPassError ? "true" : "false"}
1215
+ ?disabled=${this.submitting}
1216
+ @input=${(s) => {
1217
+ this.confirmPass = s.target.value, this.newPassError = "";
1218
+ }}
1219
+ />
1220
+ ${this.newPassError ? a`<p class="err">${this.newPassError}</p>` : d}
1221
+ </div>
1222
+ <div class="edit-actions">
1223
+ <button
1224
+ type="button"
1225
+ class="primary-sm"
1226
+ ?disabled=${this.submitting}
1227
+ @click=${this.onChangePass}
1228
+ >
1229
+ ${this.submitting ? a`<span class="spinner"></span>` : d}
1230
+ <span>${this.msg.updatePasswordCta}</span>
1231
+ </button>
1232
+ <button type="button" class="ghost-sm" @click=${() => this.editMode = ""}>
1233
+ ${this.msg.cancelCta}
1234
+ </button>
1235
+ </div>
1236
+ </div>
1237
+ `}
1238
+ </div>
1239
+ `;
1240
+ }
1241
+ /** Layout preserved from the mock; no enrolment operation exists yet. */
1242
+ renderTwoFactorSection() {
1243
+ return a`
1244
+ <div class="rule"></div>
1245
+ <div class="section">
1246
+ <div class="between">
1247
+ <div>
1248
+ <h3 class="sec-title">${this.msg.twoFaTitle}</h3>
1249
+ <p class="hint">${this.msg.twoFaHintOff}</p>
1250
+ </div>
1251
+ <button
1252
+ type="button"
1253
+ class="switch"
1254
+ aria-pressed="false"
1255
+ aria-label=${`${this.msg.twoFaTitle} (${this.msg.notYetSupported})`}
1256
+ disabled
1257
+ title=${this.msg.notYetSupported}
1258
+ >
1259
+ <span class="knob"></span>
1260
+ </button>
1261
+ </div>
1262
+ <p class="disabled-note">
1263
+ ${this.msg.notYetSupported} — enrolling a second factor is not part of the current API.
1264
+ </p>
1265
+ </div>
1266
+ `;
1267
+ }
1268
+ renderConnectedSection() {
1269
+ const t = this.availableProviders;
1270
+ return t.length === 0 ? d : a`
1271
+ <div class="rule"></div>
1272
+ <div class="section">
1273
+ <h3 class="sec-title">${this.msg.connectedTitle}</h3>
1274
+ <p class="hint">${this.msg.connectedHint}</p>
1275
+ <span class="sub-label">${this.msg.addAnotherLabel}</span>
1276
+ <div class="tile-grid">
1277
+ ${t.map(
1278
+ (e) => a`
1279
+ <button
1280
+ type="button"
1281
+ class="tile"
1282
+ aria-label=${`Connect ${e.name}`}
1283
+ ?disabled=${this.submitting}
1284
+ @click=${() => this.onConnectProvider(e.id)}
1285
+ >
1286
+ <span class="tile-mark">${e.mark}</span>
1287
+ <span class="tile-name">${e.name}</span>
1288
+ <span class="tile-plus">+</span>
1289
+ </button>
1290
+ `
1291
+ )}
1292
+ </div>
1293
+ <p class="disabled-note">
1294
+ ${this.msg.notYetSupported} — listing or disconnecting linked providers is not part of the
1295
+ current API.
1296
+ </p>
1297
+ </div>
1298
+ `;
1299
+ }
1300
+ renderDangerSection() {
1301
+ return a`
1302
+ <div class="rule"></div>
1303
+ <div class="section">
1304
+ ${this.deleteStage === 0 ? a`<button
1305
+ type="button"
1306
+ class="danger-link"
1307
+ disabled
1308
+ title=${this.msg.notYetSupported}
1309
+ >
1310
+ ${this.msg.deleteAccountCta}
1311
+ </button>` : d}
1312
+ <p class="disabled-note">
1313
+ ${this.msg.notYetSupported} — account deletion is not part of the current API.
1314
+ </p>
1315
+ </div>
1316
+ `;
1317
+ }
1318
+ render() {
1319
+ return this.user ? a`
1320
+ <div class="acct-root">
1321
+ ${this.renderLogo()} ${this.renderIdentity()}
1322
+ <div class="acct-body">
1323
+ ${this.toast ? a`<div class="notice" role="status">${this.toast}</div>` : d}
1324
+ ${this.formError ? a`<div class="banner" role="alert">${this.formError}</div>` : d}
1325
+ ${this.renderProfileSection()} ${this.renderEmailSection()}
1326
+ ${this.renderPasswordSection()}
1327
+ ${d}
1328
+ ${this.renderConnectedSection()}
1329
+ ${d}
1330
+ </div>
1331
+ </div>
1332
+ ` : a`<p class="disabled-note">Not signed in.</p>`;
1333
+ }
1334
+ }, F = new WeakMap(), D = new WeakMap(), B = new WeakMap(), R = new WeakMap(), H = new WeakMap(), j = new WeakMap(), q = new WeakMap(), G = new WeakMap(), V = new WeakMap(), K = new WeakMap(), Y = new WeakMap(), W = new WeakMap(), z = new WeakMap(), J = new WeakMap(), Q = new WeakMap(), X = new WeakMap(), Z = new WeakMap(), tt = new WeakMap(), et = new WeakMap(), st = new WeakMap(), it = new WeakMap(), at = new WeakMap(), rt = new WeakMap(), nt = new WeakMap(), ot = new WeakMap(), lt = new WeakMap(), Fe);
1335
+ v([
1336
+ p({ attribute: "logo-text" })
1337
+ ], f.prototype, "logoText", 1);
1338
+ v([
1339
+ p({ attribute: "logo-url" })
1340
+ ], f.prototype, "logoUrl", 1);
1341
+ v([
1342
+ p({ attribute: !1 })
1343
+ ], f.prototype, "settings", 1);
1344
+ v([
1345
+ p({ attribute: "nonce-storage-key" })
1346
+ ], f.prototype, "nonceStorageKey", 1);
1347
+ v([
1348
+ m()
1349
+ ], f.prototype, "editMode", 1);
1350
+ v([
1351
+ m()
1352
+ ], f.prototype, "toast", 1);
1353
+ v([
1354
+ m()
1355
+ ], f.prototype, "photoBusy", 1);
1356
+ v([
1357
+ m()
1358
+ ], f.prototype, "photoFailed", 1);
1359
+ v([
1360
+ m()
1361
+ ], f.prototype, "profileSaved", 1);
1362
+ v([
1363
+ m()
1364
+ ], f.prototype, "passSaved", 1);
1365
+ v([
1366
+ m()
1367
+ ], f.prototype, "profileError", 1);
1368
+ v([
1369
+ m()
1370
+ ], f.prototype, "newPassError", 1);
1371
+ v([
1372
+ m()
1373
+ ], f.prototype, "deleteStage", 1);
1374
+ v([
1375
+ m()
1376
+ ], f.prototype, "confirmText", 1);
1377
+ v([
1378
+ m()
1379
+ ], f.prototype, "dFirst", 1);
1380
+ v([
1381
+ m()
1382
+ ], f.prototype, "dLast", 1);
1383
+ v([
1384
+ m()
1385
+ ], f.prototype, "dPhone", 1);
1386
+ v([
1387
+ m()
1388
+ ], f.prototype, "dEmail", 1);
1389
+ v([
1390
+ m()
1391
+ ], f.prototype, "emailStep", 1);
1392
+ v([
1393
+ m()
1394
+ ], f.prototype, "dNewEmail", 1);
1395
+ v([
1396
+ m()
1397
+ ], f.prototype, "emailCode", 1);
1398
+ v([
1399
+ m()
1400
+ ], f.prototype, "emailError", 1);
1401
+ v([
1402
+ m()
1403
+ ], f.prototype, "emailSaved", 1);
1404
+ v([
1405
+ m()
1406
+ ], f.prototype, "curPass", 1);
1407
+ v([
1408
+ m()
1409
+ ], f.prototype, "newPass", 1);
1410
+ v([
1411
+ m()
1412
+ ], f.prototype, "confirmPass", 1);
1413
+ f = v([
1414
+ fe("singlebase-authui-account")
1415
+ ], f);
1416
+ var _s = Object.defineProperty, Os = Object.getOwnPropertyDescriptor, C = (r, t, e, s) => {
1417
+ for (var i = s > 1 ? void 0 : s ? Os(t, e) : t, h = r.length - 1, c; h >= 0; h--)
1418
+ (c = r[h]) && (i = (s ? c(t, e, i) : c(i)) || i);
1419
+ return s && i && _s(t, e, i), i;
1420
+ }, ht, dt, ct, ut, pt, gt, mt, De;
1421
+ let E = (De = class extends we {
1422
+ constructor() {
1423
+ super(...arguments);
1424
+ o(this, ht, "signout");
1425
+ o(this, dt, "signin");
1426
+ o(this, ct, "");
1427
+ o(this, ut, "");
1428
+ o(this, pt, !1);
1429
+ o(this, gt, null);
1430
+ o(this, mt, "singlebase-oauth-nonce");
1431
+ b(this, "settingsCtl", new Se(this));
1432
+ }
1433
+ get type() {
1434
+ return n(this, ht);
1435
+ }
1436
+ set type(t) {
1437
+ l(this, ht, t);
1438
+ }
1439
+ get intent() {
1440
+ return n(this, dt);
1441
+ }
1442
+ set intent(t) {
1443
+ l(this, dt, t);
1444
+ }
1445
+ get provider() {
1446
+ return n(this, ct);
1447
+ }
1448
+ set provider(t) {
1449
+ l(this, ct, t);
1450
+ }
1451
+ get providerName() {
1452
+ return n(this, ut);
1453
+ }
1454
+ set providerName(t) {
1455
+ l(this, ut, t);
1456
+ }
1457
+ get embedded() {
1458
+ return n(this, pt);
1459
+ }
1460
+ set embedded(t) {
1461
+ l(this, pt, t);
1462
+ }
1463
+ get settings() {
1464
+ return n(this, gt);
1465
+ }
1466
+ set settings(t) {
1467
+ l(this, gt, t);
1468
+ }
1469
+ get nonceStorageKey() {
1470
+ return n(this, mt);
1471
+ }
1472
+ set nonceStorageKey(t) {
1473
+ l(this, mt, t);
1474
+ }
1475
+ willUpdate(t) {
1476
+ super.willUpdate(t), this.type === "oauth" && this.settingsCtl.load(this.resolvedClient, this.settings);
1477
+ }
1478
+ get effectiveSettings() {
1479
+ return this.settings ?? this.settingsCtl.settings;
1480
+ }
1481
+ // ── oauth ────────────────────────────────────────────────
1482
+ get providers() {
1483
+ const t = this.effectiveSettings;
1484
+ if (!t || !t.oauth_settings.enabled) return [];
1485
+ if (!(this.intent === "signup" ? t.oauth_settings.allow_signup : t.oauth_settings.allow_signin) && this.intent !== "link") return [];
1486
+ const s = {
1487
+ google: "G",
1488
+ github: "GH",
1489
+ linkedin: "in",
1490
+ facebook: "f"
1491
+ };
1492
+ return Object.entries(t.oauth_providers).filter(([, i]) => i.enabled).map(([i, h]) => ({
1493
+ id: i,
1494
+ name: h.provider_name,
1495
+ mark: s[i] ?? h.provider_name.slice(0, 2)
1496
+ }));
1497
+ }
1498
+ /** Shared by the oauth and link flows: nonce, start, redirect. */
1499
+ async startOAuth(t, e, s = !1) {
1500
+ const i = this.resolvedClient;
1501
+ if (!i) return;
1502
+ let h, c;
1503
+ if (s) {
1504
+ const w = this.auth.state;
1505
+ if (w.status !== "authenticated") {
1506
+ this.formError = this.msg.linkRequiresSignIn, this.phase = "error";
1507
+ return;
1508
+ }
1509
+ h = w.session.id_token, c = w.session.refresh_token;
1510
+ }
1511
+ await this.run(async () => {
1512
+ var $e;
1513
+ const w = await i.createOAuthNonce(this.signal);
1514
+ ($e = globalThis.sessionStorage) == null || $e.setItem(this.nonceStorageKey, w);
1515
+ const { oauth_redirect_url: y } = await i.startOAuth(
1516
+ {
1517
+ provider: t,
1518
+ nonce: w,
1519
+ intent: e,
1520
+ ...s ? { id_token: h, refresh_token: c } : {}
1521
+ },
1522
+ this.signal
1523
+ );
1524
+ globalThis.location.assign(y);
1525
+ });
1526
+ }
1527
+ renderOAuth() {
1528
+ const t = this.providers;
1529
+ if (t.length === 0) return d;
1530
+ const [e, ...s] = t;
1531
+ return a`
1532
+ <div class="stack">
1533
+ ${this.formError ? a`<div class="banner" part="banner" role="alert">${this.formError}</div>` : d}
1534
+
1535
+ <button
1536
+ type="button"
1537
+ class="oauth-primary"
1538
+ part="oauth-button"
1539
+ ?disabled=${this.submitting}
1540
+ @click=${() => this.startOAuth(e.id, this.intent)}
1541
+ >
1542
+ <span class="g-mark">${e.mark}</span>
1543
+ <span>${this.msg.oauthContinueWith} ${e.name}</span>
1544
+ </button>
1545
+
1546
+ ${s.length ? a`
1547
+ <div class="icon-row">
1548
+ ${s.map(
1549
+ (i) => a`
1550
+ <button
1551
+ type="button"
1552
+ class="icon-btn"
1553
+ part="oauth-button"
1554
+ aria-label=${`${this.msg.oauthContinueWith} ${i.name}`}
1555
+ title=${`${this.msg.oauthContinueWith} ${i.name}`}
1556
+ ?disabled=${this.submitting}
1557
+ @click=${() => this.startOAuth(i.id, this.intent)}
1558
+ >
1559
+ <span class="tile-mark">${i.mark}</span>
1560
+ </button>
1561
+ `
1562
+ )}
1563
+ </div>
1564
+ ` : d}
1565
+ </div>
1566
+ `;
1567
+ }
1568
+ // ── link ─────────────────────────────────────────────────
1569
+ renderLink() {
1570
+ return a`
1571
+ <div class="stack">
1572
+ ${this.renderStatus()}
1573
+ <button
1574
+ type="button"
1575
+ class="secondary"
1576
+ part="oauth-button"
1577
+ ?disabled=${this.submitting}
1578
+ @click=${() => this.startOAuth(this.provider, "link", !0)}
1579
+ >
1580
+ ${this.submitting ? a`<span class="spinner"></span>` : d}
1581
+ <span>${this.msg.oauthContinueWith} ${this.providerName || this.provider}</span>
1582
+ </button>
1583
+ </div>
1584
+ `;
1585
+ }
1586
+ // ── signout ──────────────────────────────────────────────
1587
+ async onSignOut() {
1588
+ const t = this.resolvedClient;
1589
+ t && await this.run(async () => {
1590
+ await t.signOut();
1591
+ });
1592
+ }
1593
+ renderSignOut() {
1594
+ return this.embedded ? a`<button
1595
+ type="button"
1596
+ class="link-sm"
1597
+ part="button-signout"
1598
+ ?disabled=${this.submitting}
1599
+ @click=${this.onSignOut}
1600
+ >
1601
+ ${this.msg.signOutCta}
1602
+ </button>` : a`
1603
+ <div class="stack">
1604
+ ${this.formError ? a`<p class="banner" role="alert">${this.formError}</p>` : d}
1605
+ <button
1606
+ type="button"
1607
+ class="link-sm"
1608
+ part="button-signout"
1609
+ ?disabled=${this.submitting}
1610
+ @click=${this.onSignOut}
1611
+ >
1612
+ ${this.msg.signOutCta}
1613
+ </button>
1614
+ </div>
1615
+ `;
1616
+ }
1617
+ render() {
1618
+ return this.type === "oauth" ? this.renderOAuth() : this.type === "link" ? this.renderLink() : this.renderSignOut();
1619
+ }
1620
+ }, ht = new WeakMap(), dt = new WeakMap(), ct = new WeakMap(), ut = new WeakMap(), pt = new WeakMap(), gt = new WeakMap(), mt = new WeakMap(), De);
1621
+ C([
1622
+ p()
1623
+ ], E.prototype, "type", 1);
1624
+ C([
1625
+ p()
1626
+ ], E.prototype, "intent", 1);
1627
+ C([
1628
+ p()
1629
+ ], E.prototype, "provider", 1);
1630
+ C([
1631
+ p({ attribute: "provider-name" })
1632
+ ], E.prototype, "providerName", 1);
1633
+ C([
1634
+ p({ type: Boolean })
1635
+ ], E.prototype, "embedded", 1);
1636
+ C([
1637
+ p({ attribute: !1 })
1638
+ ], E.prototype, "settings", 1);
1639
+ C([
1640
+ p({ attribute: "nonce-storage-key" })
1641
+ ], E.prototype, "nonceStorageKey", 1);
1642
+ E = C([
1643
+ fe("singlebase-authui-buttons")
1644
+ ], E);
1645
+ var Ve = Object.defineProperty, xs = Object.getOwnPropertyDescriptor, Ts = (r, t, e) => t in r ? Ve(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e, g = (r, t, e, s) => {
1646
+ for (var i = s > 1 ? void 0 : s ? xs(t, e) : t, h = r.length - 1, c; h >= 0; h--)
1647
+ (c = r[h]) && (i = (s ? c(t, e, i) : c(i)) || i);
1648
+ return s && i && Ve(t, e, i), i;
1649
+ }, Us = (r, t, e) => Ts(r, t + "", e);
1650
+ const Ke = [
1651
+ "signin",
1652
+ "signup",
1653
+ "forgot",
1654
+ "verify",
1655
+ "otp",
1656
+ "newpass",
1657
+ "invite"
1658
+ ], Ye = ["account"], Ls = [...Ke, ...Ye, "oauth-callback"];
1659
+ function Ne(r) {
1660
+ return Ke.includes(r);
1661
+ }
1662
+ function As(r) {
1663
+ return Ye.includes(r);
1664
+ }
1665
+ function Ie(r) {
1666
+ return Ls.includes(r);
1667
+ }
1668
+ const P = {
1669
+ // An absent attribute must mean "default" (true), not false. Lit calls
1670
+ // fromAttribute(null) when an attribute is *removed*, so returning false
1671
+ // there would make removing `allow-oauth="false"` leave the flag off
1672
+ // forever instead of restoring the default.
1673
+ fromAttribute: (r) => r === null ? !0 : r !== "false",
1674
+ toAttribute: (r) => r ? null : "false"
1675
+ };
1676
+ var bt, ft, vt, wt, $t, yt, Et, St, Ct, Pt, kt, _t, Ot, xt, Tt, Ut, Lt, At, Mt, Nt, It, Ft, Dt, Bt, Rt, Ht, jt, qt, Gt, Vt, Kt, Yt, Wt, zt, Jt, Qt, Xt, Zt, te, ee, se, ie, ae, re, ne, oe, le, Be;
1677
+ let u = (Be = class extends $ {
1678
+ constructor() {
1679
+ super(...arguments);
1680
+ o(this, bt, "signin");
1681
+ o(this, ft, "");
1682
+ o(this, vt, !1);
1683
+ o(this, wt, null);
1684
+ o(this, $t, !0);
1685
+ o(this, yt, !0);
1686
+ o(this, Et, !0);
1687
+ o(this, St, !0);
1688
+ o(this, Ct, !0);
1689
+ o(this, Pt, !0);
1690
+ o(this, kt, "card");
1691
+ o(this, _t, "bottom");
1692
+ o(this, Ot, !1);
1693
+ o(this, xt, "");
1694
+ o(this, Tt, "");
1695
+ o(this, Ut, "");
1696
+ o(this, Lt, "");
1697
+ o(this, At, "");
1698
+ o(this, Mt, !0);
1699
+ o(this, Nt, "");
1700
+ o(this, It, "");
1701
+ o(this, Ft, "");
1702
+ o(this, Dt, "singlebase-oauth-nonce");
1703
+ o(this, Bt, "");
1704
+ o(this, Rt, "");
1705
+ o(this, Ht, "");
1706
+ o(this, jt, 0);
1707
+ o(this, qt, "");
1708
+ o(this, Gt, "");
1709
+ o(this, Vt, "");
1710
+ o(this, Kt, "");
1711
+ o(this, Yt, "");
1712
+ o(this, Wt, "");
1713
+ o(this, zt, "");
1714
+ o(this, Jt, "");
1715
+ o(this, Qt, "");
1716
+ o(this, Xt, ["", "", "", "", "", ""]);
1717
+ o(this, Zt, "signin_code");
1718
+ o(this, te, !1);
1719
+ o(this, ee, "");
1720
+ o(this, se, "");
1721
+ o(this, ie, "");
1722
+ o(this, ae, "");
1723
+ o(this, re, "");
1724
+ o(this, ne, 0);
1725
+ o(this, oe, !1);
1726
+ b(this, "settingsCtl", new Se(this));
1727
+ b(this, "bridge", new $s(this));
1728
+ b(this, "uidBase", `sb-${Math.random().toString(36).slice(2, 8)}`);
1729
+ b(this, "gotoUnsubscribe");
1730
+ b(this, "gotoClient", null);
1731
+ o(this, le, !1);
1732
+ b(this, "abortController", null);
1733
+ b(this, "onContinue", () => {
1734
+ this.followRedirect() || (this.dispatchEvent(
1735
+ new CustomEvent("singlebase-continue", {
1736
+ detail: { user: this.getUser() },
1737
+ bubbles: !0,
1738
+ composed: !0
1739
+ })
1740
+ ), this.goto("account"));
1741
+ });
1742
+ b(this, "onInterstitialSignOut", async () => {
1743
+ var t;
1744
+ await ((t = this.resolvedClient) == null ? void 0 : t.logout()), this.goto("signin");
1745
+ });
1746
+ }
1747
+ get initialScreen() {
1748
+ return n(this, bt);
1749
+ }
1750
+ set initialScreen(t) {
1751
+ l(this, bt, t);
1752
+ }
1753
+ get screen() {
1754
+ return n(this, ft);
1755
+ }
1756
+ set screen(t) {
1757
+ l(this, ft, t);
1758
+ }
1759
+ get noAccountView() {
1760
+ return n(this, vt);
1761
+ }
1762
+ set noAccountView(t) {
1763
+ l(this, vt, t);
1764
+ }
1765
+ get settings() {
1766
+ return n(this, wt);
1767
+ }
1768
+ set settings(t) {
1769
+ l(this, wt, t);
1770
+ }
1771
+ get authEnabled() {
1772
+ return n(this, $t);
1773
+ }
1774
+ set authEnabled(t) {
1775
+ l(this, $t, t);
1776
+ }
1777
+ get allowEmailSignin() {
1778
+ return n(this, yt);
1779
+ }
1780
+ set allowEmailSignin(t) {
1781
+ l(this, yt, t);
1782
+ }
1783
+ get allowEmailSignup() {
1784
+ return n(this, Et);
1785
+ }
1786
+ set allowEmailSignup(t) {
1787
+ l(this, Et, t);
1788
+ }
1789
+ get allowEmailOtp() {
1790
+ return n(this, St);
1791
+ }
1792
+ set allowEmailOtp(t) {
1793
+ l(this, St, t);
1794
+ }
1795
+ get allowOauth() {
1796
+ return n(this, Ct);
1797
+ }
1798
+ set allowOauth(t) {
1799
+ l(this, Ct, t);
1800
+ }
1801
+ get allowAccountCreation() {
1802
+ return n(this, Pt);
1803
+ }
1804
+ set allowAccountCreation(t) {
1805
+ l(this, Pt, t);
1806
+ }
1807
+ get layout() {
1808
+ return n(this, kt);
1809
+ }
1810
+ set layout(t) {
1811
+ l(this, kt, t);
1812
+ }
1813
+ get oauthPlacement() {
1814
+ return n(this, _t);
1815
+ }
1816
+ set oauthPlacement(t) {
1817
+ l(this, _t, t);
1818
+ }
1819
+ get stepped() {
1820
+ return n(this, Ot);
1821
+ }
1822
+ set stepped(t) {
1823
+ l(this, Ot, t);
1824
+ }
1825
+ get logoText() {
1826
+ return n(this, xt);
1827
+ }
1828
+ set logoText(t) {
1829
+ l(this, xt, t);
1830
+ }
1831
+ get logoUrl() {
1832
+ return n(this, Tt);
1833
+ }
1834
+ set logoUrl(t) {
1835
+ l(this, Tt, t);
1836
+ }
1837
+ get brandLine() {
1838
+ return n(this, Ut);
1839
+ }
1840
+ set brandLine(t) {
1841
+ l(this, Ut, t);
1842
+ }
1843
+ get brandFoot() {
1844
+ return n(this, Lt);
1845
+ }
1846
+ set brandFoot(t) {
1847
+ l(this, Lt, t);
1848
+ }
1849
+ get signInTitle() {
1850
+ return n(this, At);
1851
+ }
1852
+ set signInTitle(t) {
1853
+ l(this, At, t);
1854
+ }
1855
+ get branding() {
1856
+ return n(this, Mt);
1857
+ }
1858
+ set branding(t) {
1859
+ l(this, Mt, t);
1860
+ }
1861
+ get redirectUrl() {
1862
+ return n(this, Nt);
1863
+ }
1864
+ set redirectUrl(t) {
1865
+ l(this, Nt, t);
1866
+ }
1867
+ get tosUrl() {
1868
+ return n(this, It);
1869
+ }
1870
+ set tosUrl(t) {
1871
+ l(this, It, t);
1872
+ }
1873
+ get privacyUrl() {
1874
+ return n(this, Ft);
1875
+ }
1876
+ set privacyUrl(t) {
1877
+ l(this, Ft, t);
1878
+ }
1879
+ get nonceStorageKey() {
1880
+ return n(this, Dt);
1881
+ }
1882
+ set nonceStorageKey(t) {
1883
+ l(this, Dt, t);
1884
+ }
1885
+ get inviteEmail() {
1886
+ return n(this, Bt);
1887
+ }
1888
+ set inviteEmail(t) {
1889
+ l(this, Bt, t);
1890
+ }
1891
+ get inviteOrg() {
1892
+ return n(this, Rt);
1893
+ }
1894
+ set inviteOrg(t) {
1895
+ l(this, Rt, t);
1896
+ }
1897
+ get inviteCode() {
1898
+ return n(this, Ht);
1899
+ }
1900
+ set inviteCode(t) {
1901
+ l(this, Ht, t);
1902
+ }
1903
+ get step() {
1904
+ return n(this, jt);
1905
+ }
1906
+ set step(t) {
1907
+ l(this, jt, t);
1908
+ }
1909
+ get method() {
1910
+ return n(this, qt);
1911
+ }
1912
+ set method(t) {
1913
+ l(this, qt, t);
1914
+ }
1915
+ get email() {
1916
+ return n(this, Gt);
1917
+ }
1918
+ set email(t) {
1919
+ l(this, Gt, t);
1920
+ }
1921
+ get password() {
1922
+ return n(this, Vt);
1923
+ }
1924
+ set password(t) {
1925
+ l(this, Vt, t);
1926
+ }
1927
+ get name() {
1928
+ return n(this, Kt);
1929
+ }
1930
+ set name(t) {
1931
+ l(this, Kt, t);
1932
+ }
1933
+ get firstName() {
1934
+ return n(this, Yt);
1935
+ }
1936
+ set firstName(t) {
1937
+ l(this, Yt, t);
1938
+ }
1939
+ get lastName() {
1940
+ return n(this, Wt);
1941
+ }
1942
+ set lastName(t) {
1943
+ l(this, Wt, t);
1944
+ }
1945
+ get phone() {
1946
+ return n(this, zt);
1947
+ }
1948
+ set phone(t) {
1949
+ l(this, zt, t);
1950
+ }
1951
+ get newPass() {
1952
+ return n(this, Jt);
1953
+ }
1954
+ set newPass(t) {
1955
+ l(this, Jt, t);
1956
+ }
1957
+ get confirmPass() {
1958
+ return n(this, Qt);
1959
+ }
1960
+ set confirmPass(t) {
1961
+ l(this, Qt, t);
1962
+ }
1963
+ get code() {
1964
+ return n(this, Xt);
1965
+ }
1966
+ set code(t) {
1967
+ l(this, Xt, t);
1968
+ }
1969
+ get verifyNext() {
1970
+ return n(this, Zt);
1971
+ }
1972
+ set verifyNext(t) {
1973
+ l(this, Zt, t);
1974
+ }
1975
+ get loading() {
1976
+ return n(this, te);
1977
+ }
1978
+ set loading(t) {
1979
+ l(this, te, t);
1980
+ }
1981
+ get banner() {
1982
+ return n(this, ee);
1983
+ }
1984
+ set banner(t) {
1985
+ l(this, ee, t);
1986
+ }
1987
+ get notice() {
1988
+ return n(this, se);
1989
+ }
1990
+ set notice(t) {
1991
+ l(this, se, t);
1992
+ }
1993
+ get emailError() {
1994
+ return n(this, ie);
1995
+ }
1996
+ set emailError(t) {
1997
+ l(this, ie, t);
1998
+ }
1999
+ get passError() {
2000
+ return n(this, ae);
2001
+ }
2002
+ set passError(t) {
2003
+ l(this, ae, t);
2004
+ }
2005
+ get newPassError() {
2006
+ return n(this, re);
2007
+ }
2008
+ set newPassError(t) {
2009
+ l(this, re, t);
2010
+ }
2011
+ get attempts() {
2012
+ return n(this, ne);
2013
+ }
2014
+ set attempts(t) {
2015
+ l(this, ne, t);
2016
+ }
2017
+ get needsMfaCode() {
2018
+ return n(this, oe);
2019
+ }
2020
+ set needsMfaCode(t) {
2021
+ l(this, oe, t);
2022
+ }
2023
+ uid(t) {
2024
+ return `${this.uidBase}-${t}`;
2025
+ }
2026
+ willUpdate(t) {
2027
+ super.willUpdate(t), this.settingsCtl.load(this.resolvedClient, this.settings), this.bridge.bind(this.resolvedClient), this.bindGoto(this.resolvedClient);
2028
+ }
2029
+ disconnectedCallback() {
2030
+ var t, e;
2031
+ super.disconnectedCallback(), (t = this.gotoUnsubscribe) == null || t.call(this), this.gotoUnsubscribe = void 0, this.gotoClient = null, (e = this.abortController) == null || e.abort();
2032
+ }
2033
+ /**
2034
+ * Subscribes to auth.goto() so a host can drive every widget on the page
2035
+ * with one call. Bound here rather than in connectedCallback because the
2036
+ * app usually creates its SinglebaseAuth() instance *after* the widget
2037
+ * upgrades — at connect time there is often no client to subscribe to yet.
2038
+ */
2039
+ bindGoto(t) {
2040
+ var i;
2041
+ if (t === this.gotoClient || ((i = this.gotoUnsubscribe) == null || i.call(this), this.gotoUnsubscribe = void 0, this.gotoClient = t, !t)) return;
2042
+ const e = t.on("goto", ({ screen: h }) => {
2043
+ Ie(h) && this.goto(h);
2044
+ }), s = t.on("signin", () => {
2045
+ this.followRedirect();
2046
+ });
2047
+ this.gotoUnsubscribe = () => {
2048
+ e(), s();
2049
+ };
2050
+ }
2051
+ /** Shows a screen. The SPA-facing counterpart of the `screen` property. */
2052
+ goto(t) {
2053
+ this.screen !== t && (this.screen = t, this.step = 0, this.banner = "", this.notice = "", this.dispatchEvent(
2054
+ new CustomEvent("singlebase-screen-change", {
2055
+ detail: { screen: t },
2056
+ bubbles: !0,
2057
+ composed: !0
2058
+ })
2059
+ ));
2060
+ }
2061
+ // ── derived config: explicit props unless auth.settings says otherwise ──
2062
+ get cfg() {
2063
+ const t = this.settings ?? this.settingsCtl.settings;
2064
+ if (!t)
2065
+ return {
2066
+ authEnabled: this.authEnabled,
2067
+ allowEmailSignin: this.allowEmailSignin,
2068
+ allowEmailSignup: this.allowEmailSignup && this.allowAccountCreation,
2069
+ allowEmailOtp: this.allowEmailOtp,
2070
+ allowOauth: this.allowOauth,
2071
+ mfa: !1
2072
+ };
2073
+ const e = t.auth_settings, s = e.second_factor === "email_otp";
2074
+ return {
2075
+ authEnabled: t.enabled && e.enabled && this.authEnabled,
2076
+ allowEmailSignin: e.allow_signin && this.allowEmailSignin,
2077
+ allowEmailSignup: e.allow_signup && this.allowEmailSignup && this.allowAccountCreation,
2078
+ allowEmailOtp: this.allowEmailOtp && e.allow_signin && !s,
2079
+ allowOauth: t.oauth_settings.enabled && this.allowOauth,
2080
+ mfa: s
2081
+ };
2082
+ }
2083
+ /** The screen the host asked for, before any guarding is applied. */
2084
+ get requestedScreen() {
2085
+ const t = this.screen || this.initialScreen || "signin";
2086
+ return Ie(t) ? t : "signin";
2087
+ }
2088
+ /**
2089
+ * Resolves the screen actually rendered.
2090
+ *
2091
+ * This is the single place navigation is decided, so a protected screen
2092
+ * cannot be reached by setting an attribute, editing the URL, or calling
2093
+ * goto() — every route runs through the same auth check. The guest
2094
+ * fallbacks below additionally reflect what the project has enabled.
2095
+ */
2096
+ get activeScreen() {
2097
+ if (this.isOAuthCallback) return "oauth-callback";
2098
+ const t = this.auth.state.status === "authenticated", e = this.requestedScreen;
2099
+ if (As(e))
2100
+ return t ? e : "signin";
2101
+ if (t)
2102
+ return this.screen !== "" || this.initialScreen !== "signin" ? e : "account";
2103
+ const s = this.cfg;
2104
+ let i = e;
2105
+ return i === "signup" && !s.allowEmailSignup && (i = "signin"), (i === "forgot" || i === "newpass") && !s.allowEmailSignin && (i = "signin"), i === "otp" && !s.allowEmailOtp && (i = "signin"), i === "signin" && !s.allowEmailSignin && s.allowEmailOtp && (i = "otp"), i;
2106
+ }
2107
+ /** True when a signed-in user is sitting on a guest screen (spec: offer continue/sign out). */
2108
+ get showsSignedInInterstitial() {
2109
+ return this.auth.state.status === "authenticated" && Ne(this.activeScreen);
2110
+ }
2111
+ // ── redirect ──────────────────────────────────────────────
2112
+ /**
2113
+ * The post-login destination, or null when there is none.
2114
+ *
2115
+ * Only same-origin targets are accepted. A login widget that forwards to
2116
+ * an attacker-chosen host is a textbook open redirect, and the `redirect`
2117
+ * parameter it reads comes straight off the URL bar, so it is untrusted
2118
+ * input by definition.
2119
+ */
2120
+ get redirectTarget() {
2121
+ var t;
2122
+ return ls(
2123
+ this.redirectUrl || this.redirectParam,
2124
+ (t = globalThis.location) == null ? void 0 : t.href,
2125
+ (e) => console.warn(`[singlebase] ${e}`)
2126
+ );
2127
+ }
2128
+ get redirectParam() {
2129
+ var e;
2130
+ const t = new URLSearchParams(((e = globalThis.location) == null ? void 0 : e.search) ?? "");
2131
+ return t.get("redirect") ?? t.get("next") ?? "";
2132
+ }
2133
+ /** Navigates to the post-login destination if there is a safe one. */
2134
+ followRedirect() {
2135
+ var e;
2136
+ const t = this.redirectTarget;
2137
+ return t ? ((e = globalThis.location) == null || e.assign(t), !0) : !1;
2138
+ }
2139
+ get isOAuthCallback() {
2140
+ var e;
2141
+ const t = new URLSearchParams(((e = globalThis.location) == null ? void 0 : e.search) ?? "");
2142
+ return t.has("access_code") || t.has("error");
2143
+ }
2144
+ get callbackDone() {
2145
+ return n(this, le);
2146
+ }
2147
+ set callbackDone(t) {
2148
+ l(this, le, t);
2149
+ }
2150
+ /** Strips the provider's parameters so a reload cannot replay the exchange. */
2151
+ cleanCallbackUrl() {
2152
+ var s;
2153
+ const t = (s = globalThis.location) == null ? void 0 : s.href;
2154
+ if (!t || !globalThis.history) return;
2155
+ const e = new URL(t);
2156
+ e.searchParams.delete("access_code"), e.searchParams.delete("error"), globalThis.history.replaceState({}, "", e.toString());
2157
+ }
2158
+ /**
2159
+ * Completes the provider round trip. Runs once per landing: the URL is
2160
+ * cleaned immediately so a refresh cannot resend a single-use access code.
2161
+ */
2162
+ async handleOAuthCallback() {
2163
+ var c, w;
2164
+ if (this.callbackDone) return;
2165
+ this.callbackDone = !0;
2166
+ const t = new URLSearchParams(((c = globalThis.location) == null ? void 0 : c.search) ?? ""), e = t.get("access_code"), s = t.get("error"), i = this.resolvedClient;
2167
+ if (s) {
2168
+ this.cleanCallbackUrl(), this.banner = this.msg.oauthDenied;
2169
+ return;
2170
+ }
2171
+ if (!e || !i) return;
2172
+ const h = (w = globalThis.sessionStorage) == null ? void 0 : w.getItem(this.nonceStorageKey);
2173
+ if (this.cleanCallbackUrl(), !h) {
2174
+ this.banner = this.msg.genericErrorMessage;
2175
+ return;
2176
+ }
2177
+ await this.withLoading(async () => {
2178
+ var y;
2179
+ await i.completeOAuth({ access_code: e, nonce: h }, this.signal()), (y = globalThis.sessionStorage) == null || y.removeItem(this.nonceStorageKey);
2180
+ });
2181
+ }
2182
+ /** The small logo above a screen title: image when given one, else text. */
2183
+ renderLogo() {
2184
+ return this.logoUrl ? a`<img class="logo-img" part="logo" src=${this.logoUrl} alt=${this.logoText} />` : this.logoText ? a`<div class="logo-dot" part="logo">${this.logoText}</div>` : d;
2185
+ }
2186
+ /** The larger logo in the split layout's brand panel. */
2187
+ renderBrandMark() {
2188
+ return this.logoUrl ? a`<img class="brand-img" part="logo" src=${this.logoUrl} alt=${this.logoText} />` : this.logoText ? a`<div class="brand-mark" part="logo">${this.logoText}</div>` : d;
2189
+ }
2190
+ renderBranding() {
2191
+ return this.branding ? a`<div class="branding" part="branding">
2192
+ <a href="https://singlebase.cloud" target="_blank" rel="noopener noreferrer"
2193
+ >${this.msg.brandingLabel}</a
2194
+ >
2195
+ </div>` : d;
2196
+ }
2197
+ /** Every screen renders inside this, so the credit appears once and only once. */
2198
+ panel(t) {
2199
+ return a`<div class="panel">${t}${this.renderBranding()}</div>`;
2200
+ }
2201
+ renderOAuthCallback() {
2202
+ return a`
2203
+ <div class="stack">
2204
+ <div class="head">
2205
+ ${this.renderLogo()}
2206
+ <h2 class="title" part="title">${this.msg.oauthCallbackTitle}</h2>
2207
+ <p class="sub">${this.msg.oauthCallbackSub}</p>
2208
+ </div>
2209
+ ${this.banner ? a`<div class="banner" part="banner" role="alert">${this.banner}</div>` : a`<div class="stack" style="align-items:center;">
2210
+ <span class="spinner" part="spinner"></span>
2211
+ </div>`}
2212
+ ${this.banner ? a`<button type="button" class="ghost" @click=${() => this.goto("signin")}>
2213
+ <span>${this.msg.backCta}</span>
2214
+ </button>` : d}
2215
+ </div>
2216
+ `;
2217
+ }
2218
+ setScreen(t, e = {}) {
2219
+ const s = this.screen !== t;
2220
+ this.screen = t, this.banner = "", this.emailError = "", this.passError = "", Object.assign(this, e), s && this.dispatchEvent(
2221
+ new CustomEvent("singlebase-screen-change", {
2222
+ detail: { screen: t },
2223
+ bubbles: !0,
2224
+ composed: !0
2225
+ })
2226
+ );
2227
+ }
2228
+ // ── submit ────────────────────────────────────────────────
2229
+ async withLoading(t) {
2230
+ this.loading = !0, this.banner = "";
2231
+ try {
2232
+ await t();
2233
+ } catch (e) {
2234
+ this.banner = this.describeError(e);
2235
+ } finally {
2236
+ this.loading = !1;
2237
+ }
2238
+ }
2239
+ describeError(t) {
2240
+ if (t instanceof ye) {
2241
+ if (t.code === "AUTH_RATE_LIMITED") return this.msg.rateLimitedMessage;
2242
+ if (t.code === "INVALID_TOKEN") return "That code is not valid. Check it and try again.";
2243
+ }
2244
+ return this.msg.genericErrorMessage;
2245
+ }
2246
+ get codeValue() {
2247
+ return this.code.join("");
2248
+ }
2249
+ async onSubmit(t) {
2250
+ t == null || t.preventDefault();
2251
+ const e = this.resolvedClient;
2252
+ if (!e) return;
2253
+ const s = this.activeScreen;
2254
+ if (this.cfg, s === "forgot" || s === "otp") {
2255
+ if (!this.email.includes("@")) {
2256
+ this.emailError = this.msg.invalidEmailError;
2257
+ return;
2258
+ }
2259
+ const i = s === "forgot" ? "password_reset" : "signin";
2260
+ await this.withLoading(async () => {
2261
+ await e.requestCode({ email: this.email, purpose: i }, this.signal()), this.notice = this.msg.codeSentNeutral, this.screen = "verify", this.verifyNext = s === "forgot" ? "newpass" : "signin_code", this.code = ["", "", "", "", "", ""];
2262
+ });
2263
+ return;
2264
+ }
2265
+ if (s === "verify") {
2266
+ if (this.codeValue.length < 6) {
2267
+ this.banner = this.msg.codeIncompleteError;
2268
+ return;
2269
+ }
2270
+ if (this.verifyNext === "newpass") {
2271
+ this.setScreen("newpass", { notice: "" });
2272
+ return;
2273
+ }
2274
+ await this.withLoading(async () => {
2275
+ await e.signIn(
2276
+ { email: this.email, grant_type: "code", code: this.codeValue },
2277
+ this.signal()
2278
+ ), this.notice = "";
2279
+ });
2280
+ return;
2281
+ }
2282
+ if (s === "newpass") {
2283
+ if (this.newPass.length < 10) {
2284
+ this.newPassError = this.msg.passwordMinError;
2285
+ return;
2286
+ }
2287
+ if (this.newPass !== this.confirmPass) {
2288
+ this.newPassError = this.msg.passwordMatchError;
2289
+ return;
2290
+ }
2291
+ await this.withLoading(async () => {
2292
+ await e.resetPassword(
2293
+ { email: this.email, code: this.codeValue, new_password: this.newPass },
2294
+ this.signal()
2295
+ ), this.newPass = "", this.confirmPass = "";
2296
+ });
2297
+ return;
2298
+ }
2299
+ if (s === "invite") {
2300
+ if (!this.firstName.trim() || !this.lastName.trim()) {
2301
+ this.banner = "Enter your first and last name.";
2302
+ return;
2303
+ }
2304
+ if (this.phone.replace(/\D/g, "").length < 7) {
2305
+ this.banner = this.msg.invalidPhoneError;
2306
+ return;
2307
+ }
2308
+ if (this.password.length < 10) {
2309
+ this.passError = this.msg.passwordMinError;
2310
+ return;
2311
+ }
2312
+ const i = this.inviteCode || this.codeValue;
2313
+ if (i.length < 6) {
2314
+ this.banner = this.msg.codeIncompleteError;
2315
+ return;
2316
+ }
2317
+ await this.withLoading(async () => {
2318
+ await e.acceptInvite(
2319
+ {
2320
+ email: this.inviteEmail,
2321
+ grant_type: "code",
2322
+ purpose: "invite",
2323
+ code: i,
2324
+ password: this.password,
2325
+ phone: this.phone
2326
+ },
2327
+ this.signal()
2328
+ );
2329
+ });
2330
+ return;
2331
+ }
2332
+ if (this.stepped && (s === "signup" && this.step < 2 || s === "signin" && this.step < 1)) {
2333
+ if (!this.email.includes("@")) {
2334
+ this.emailError = this.msg.invalidEmailError;
2335
+ return;
2336
+ }
2337
+ this.step += 1;
2338
+ return;
2339
+ }
2340
+ if (!this.email.includes("@")) {
2341
+ this.emailError = this.msg.invalidEmailError;
2342
+ return;
2343
+ }
2344
+ if (s === "signup") {
2345
+ if (this.password.length < 8) {
2346
+ this.passError = "Password must be at least 8 characters.";
2347
+ return;
2348
+ }
2349
+ const [i, ...h] = this.name.trim().split(/\s+/);
2350
+ await this.withLoading(async () => {
2351
+ const c = await e.signUp(
2352
+ {
2353
+ email: this.email,
2354
+ password: this.password,
2355
+ first_name: i || this.name,
2356
+ last_name: h.join(" ") || "—"
2357
+ },
2358
+ this.signal()
2359
+ ), w = rs({
2360
+ next_action: c.next_action,
2361
+ next_operation: c.next_operation
2362
+ });
2363
+ this.setScreen("signin", {
2364
+ notice: "Account created. Sign in to continue.",
2365
+ step: 0,
2366
+ password: "",
2367
+ needsMfaCode: w === "signin_with_code"
2368
+ });
2369
+ });
2370
+ return;
2371
+ }
2372
+ if (this.password.length < 8) {
2373
+ this.attempts += 1, this.passError = "Password must be at least 8 characters.", this.banner = this.attempts >= 3 ? this.msg.rateLimitedMessage : "";
2374
+ return;
2375
+ }
2376
+ await this.withLoading(async () => {
2377
+ try {
2378
+ await e.signIn(
2379
+ {
2380
+ email: this.email,
2381
+ password: this.password,
2382
+ ...this.needsMfaCode ? { code: this.codeValue } : {}
2383
+ },
2384
+ this.signal()
2385
+ ), this.step = 0;
2386
+ } catch (i) {
2387
+ if (i instanceof ye && i.code === "CODE_REQUIRED") {
2388
+ this.needsMfaCode = !0, await e.requestCode({ email: this.email, purpose: "signin" }, this.signal()), this.notice = this.msg.codeSentNeutral;
2389
+ return;
2390
+ }
2391
+ if (i instanceof ye && i.code === "INVALID_CREDENTIALS") {
2392
+ this.attempts += 1, this.banner = this.attempts >= 3 ? this.msg.rateLimitedMessage : "That email and password do not match.";
2393
+ return;
2394
+ }
2395
+ throw i;
2396
+ }
2397
+ });
2398
+ }
2399
+ signal() {
2400
+ var t;
2401
+ return (t = this.abortController) == null || t.abort(), this.abortController = new AbortController(), this.abortController.signal;
2402
+ }
2403
+ onCodeInput(t, e) {
2404
+ var w;
2405
+ const i = e.target.value.replace(/\D/g, "");
2406
+ if (i.length > 1) {
2407
+ this.fillCode(t, i);
2408
+ return;
2409
+ }
2410
+ const h = i.slice(-1), c = this.code.slice();
2411
+ c[t] = h, this.code = c, this.banner = "", h && ((w = this.renderRoot.querySelectorAll(
2412
+ ".code-row input, .code-row-sm input"
2413
+ )[t + 1]) == null || w.focus());
2414
+ }
2415
+ onCodePaste(t, e) {
2416
+ var i;
2417
+ const s = (((i = e.clipboardData) == null ? void 0 : i.getData("text")) ?? "").replace(/\D/g, "");
2418
+ s && (e.preventDefault(), this.fillCode(t, s));
2419
+ }
2420
+ fillCode(t, e) {
2421
+ const s = this.code.slice();
2422
+ for (let h = 0; h < e.length && t + h < s.length; h += 1)
2423
+ s[t + h] = e[h];
2424
+ this.code = s, this.banner = "";
2425
+ const i = Math.min(t + e.length, s.length - 1);
2426
+ this.updateComplete.then(() => {
2427
+ var c;
2428
+ (c = this.renderRoot.querySelectorAll(
2429
+ ".code-row input, .code-row-sm input"
2430
+ )[i]) == null || c.focus();
2431
+ });
2432
+ }
2433
+ async onResend() {
2434
+ const t = this.resolvedClient;
2435
+ if (!t || this.loading) return;
2436
+ const e = this.verifyNext === "newpass" ? "password_reset" : "signin";
2437
+ await this.withLoading(async () => {
2438
+ await t.requestCode({ email: this.email, purpose: e }, this.signal()), this.notice = "New code sent.", this.code = ["", "", "", "", "", ""];
2439
+ });
2440
+ }
2441
+ goBack() {
2442
+ if (this.step > 0 && ["forgot", "verify", "otp", "newpass"].indexOf(this.activeScreen) < 0) {
2443
+ this.step -= 1, this.banner = "", this.notice = "";
2444
+ return;
2445
+ }
2446
+ this.setScreen("signin", { step: 0, notice: "", code: ["", "", "", "", "", ""] });
2447
+ }
2448
+ // ── copy helpers (mirror the mock's titles/subs/ctas maps) ──
2449
+ titleFor(t) {
2450
+ const e = this.msg;
2451
+ switch (t) {
2452
+ case "signup":
2453
+ return e.signUpTitle;
2454
+ case "forgot":
2455
+ return e.forgotTitle;
2456
+ case "verify":
2457
+ return e.verifyTitle;
2458
+ case "otp":
2459
+ return e.otpTitle;
2460
+ case "newpass":
2461
+ return e.newPassTitle;
2462
+ case "invite":
2463
+ return e.inviteTitle;
2464
+ default:
2465
+ return this.signInTitle || e.signInTitle;
2466
+ }
2467
+ }
2468
+ subFor(t) {
2469
+ const e = this.msg, s = this.cfg;
2470
+ switch (t) {
2471
+ case "signup":
2472
+ return e.signUpSub;
2473
+ case "forgot":
2474
+ return e.forgotSub;
2475
+ case "verify":
2476
+ return `We sent a 6-digit code to ${this.email || "your inbox"}. It expires in 10 minutes.`;
2477
+ case "otp":
2478
+ return e.otpSub;
2479
+ case "newpass":
2480
+ return `Your code is confirmed. Set a new password for ${this.email || "your account"}.`;
2481
+ case "invite":
2482
+ return `${this.inviteOrg || "Acme"} invited you to join. Set up your account to continue.`;
2483
+ default:
2484
+ return !s.allowEmailSignin && !s.allowEmailOtp ? e.signInSubOauthOnly : s.allowOauth ? e.signInSubEmailAndOauth : e.signInSubEmailOnly;
2485
+ }
2486
+ }
2487
+ ctaFor(t) {
2488
+ const e = this.msg;
2489
+ if (this.stepped && (t === "signup" && this.step < 2 || t === "signin" && this.step < 1))
2490
+ return e.continueCta;
2491
+ switch (t) {
2492
+ case "signup":
2493
+ return e.signUpCta;
2494
+ case "forgot":
2495
+ return e.forgotCta;
2496
+ case "verify":
2497
+ return e.verifyCta;
2498
+ case "otp":
2499
+ return e.otpCta;
2500
+ case "newpass":
2501
+ return e.newPassCta;
2502
+ case "invite":
2503
+ return e.inviteCta;
2504
+ default:
2505
+ return e.signInCta;
2506
+ }
2507
+ }
2508
+ stepPct() {
2509
+ if (!this.stepped) return 100;
2510
+ const t = this.activeScreen === "signup" ? 3 : 2;
2511
+ return Math.round((this.step + 1) / t * 100);
2512
+ }
2513
+ // ── render pieces ─────────────────────────────────────────
2514
+ renderPrimary(t) {
2515
+ return a`
2516
+ <button type="submit" class="primary" part="button-primary" ?disabled=${this.loading}>
2517
+ ${this.loading ? a`<span class="spinner" part="spinner"></span>` : d}
2518
+ <span>${t}</span>
2519
+ </button>
2520
+ `;
2521
+ }
2522
+ renderEmailField(t) {
2523
+ return a`
2524
+ <div class="field">
2525
+ <label for=${t}>${this.msg.emailLabel}</label>
2526
+ <input
2527
+ id=${t}
2528
+ type="email"
2529
+ part="input"
2530
+ .value=${this.email}
2531
+ placeholder=${this.msg.emailPlaceholder}
2532
+ aria-invalid=${this.emailError ? "true" : "false"}
2533
+ ?disabled=${this.loading}
2534
+ @input=${(e) => {
2535
+ this.email = e.target.value, this.emailError = "", this.banner = "";
2536
+ }}
2537
+ />
2538
+ ${this.emailError ? a`<p class="err">${this.emailError}</p>` : d}
2539
+ </div>
2540
+ `;
2541
+ }
2542
+ renderPasswordField(t, e) {
2543
+ return a`
2544
+ <div class="field">
2545
+ <div class="label-row">
2546
+ <label for=${t}>${this.msg.passwordLabel}</label>
2547
+ ${e ? a`<button
2548
+ type="button"
2549
+ class="link-sm"
2550
+ @click=${() => this.setScreen("forgot", { step: 0 })}
2551
+ >
2552
+ ${this.msg.forgotLink}
2553
+ </button>` : d}
2554
+ </div>
2555
+ <input
2556
+ id=${t}
2557
+ type="password"
2558
+ part="input"
2559
+ .value=${this.password}
2560
+ placeholder=${this.msg.passwordPlaceholder}
2561
+ aria-invalid=${this.passError ? "true" : "false"}
2562
+ ?disabled=${this.loading}
2563
+ @input=${(s) => {
2564
+ this.password = s.target.value, this.passError = "", this.banner = "";
2565
+ }}
2566
+ />
2567
+ ${this.passError ? a`<p class="err">${this.passError}</p>` : d}
2568
+ </div>
2569
+ `;
2570
+ }
2571
+ renderCodeRow(t = !1) {
2572
+ return a`
2573
+ <div class=${t ? "code-row-sm" : "code-row"} role="group" aria-label="Verification code">
2574
+ ${this.code.map(
2575
+ (e, s) => a`
2576
+ <input
2577
+ type="text"
2578
+ inputmode="numeric"
2579
+ maxlength="1"
2580
+ part="code-box"
2581
+ aria-label=${`Digit ${s + 1}`}
2582
+ autocomplete=${s === 0 ? "one-time-code" : "off"}
2583
+ .value=${e}
2584
+ ?disabled=${this.loading}
2585
+ @input=${(i) => this.onCodeInput(s, i)}
2586
+ @paste=${(i) => this.onCodePaste(s, i)}
2587
+ />
2588
+ `
2589
+ )}
2590
+ </div>
2591
+ `;
2592
+ }
2593
+ /** The email/password method accordion body for signin, signup and otp. */
2594
+ renderEmailMethodBody(t) {
2595
+ const e = this.cfg, s = this.stepped, i = t === "signup" && (!s || this.step === 0), h = t === "signup" && (!s || this.step === 1) || t === "signin" && (!s || this.step === 0) || t === "otp", c = t === "signup" && (!s || this.step === 2) || t === "signin" && (!s || this.step === 1), w = t === "signin" && e.allowEmailSignin && e.allowEmailOtp && (!s || this.step === 0);
2596
+ return a`
2597
+ ${i ? a`
2598
+ <div class="field">
2599
+ <label for=${this.uid("name")}>${this.msg.fullNameLabel}</label>
2600
+ <input
2601
+ id=${this.uid("name")}
2602
+ type="text"
2603
+ part="input"
2604
+ .value=${this.name}
2605
+ placeholder=${this.msg.fullNamePlaceholder}
2606
+ ?disabled=${this.loading}
2607
+ @input=${(y) => this.name = y.target.value}
2608
+ />
2609
+ </div>
2610
+ ` : d}
2611
+ ${h ? this.renderEmailField(this.uid("email")) : d}
2612
+ ${c ? this.renderPasswordField(this.uid("pass"), e.allowEmailSignin && t === "signin") : d}
2613
+ ${this.needsMfaCode && t === "signin" ? a`
2614
+ <div class="field">
2615
+ <span class="label">Verification code</span>
2616
+ ${this.renderCodeRow(!0)}
2617
+ </div>
2618
+ ` : d}
2619
+ ${this.renderPrimary(this.ctaFor(t))}
2620
+ ${w ? a`<button
2621
+ type="button"
2622
+ class="edit-link"
2623
+ @click=${() => this.setScreen("otp", { step: 0 })}
2624
+ >
2625
+ ${this.msg.otpInsteadLink}
2626
+ </button>` : d}
2627
+ `;
2628
+ }
2629
+ renderAccordion(t) {
2630
+ const e = this.cfg, s = t === "signin" && e.allowEmailSignin || t === "signup" && e.allowEmailSignup || t === "otp" && e.allowEmailOtp, i = e.allowOauth;
2631
+ if (!s && !i) return d;
2632
+ const h = s && i, c = s ? i && this.method || "email" : "oauth", w = c === "email", y = c === "oauth", $e = t === "signup" ? this.msg.emailMethodTitleSignUp : this.msg.emailMethodTitle, ze = t === "otp" ? this.msg.emailMethodMetaOtp : t === "signup" ? this.msg.emailMethodMetaSignUp : this.msg.emailMethodMeta, Pe = (Oe, Je, Qe, Xe, Ze, xe) => a`
2633
+ <div class="acc-item ${Oe ? "open" : ""} ${h ? "" : "bare"}" part="acc-item">
2634
+ ${h ? a`
2635
+ <button
2636
+ type="button"
2637
+ class="acc-head"
2638
+ aria-expanded=${Oe ? "true" : "false"}
2639
+ aria-controls=${this.uid(`acc-${xe}`)}
2640
+ @click=${Ze}
2641
+ >
2642
+ <span class="chev" aria-hidden="true">›</span>
2643
+ <span class="acc-title">${Je}</span>
2644
+ <span class="acc-meta">${Qe}</span>
2645
+ </button>
2646
+ ` : d}
2647
+ <div class="acc-body" id=${this.uid(`acc-${xe}`)}>
2648
+ <div class="acc-clip">
2649
+ <div class="acc-inner">${Xe}</div>
2650
+ </div>
2651
+ </div>
2652
+ </div>
2653
+ `, ke = s ? Pe(
2654
+ w,
2655
+ $e,
2656
+ ze,
2657
+ this.renderEmailMethodBody(t),
2658
+ () => this.method = w ? "" : "email",
2659
+ "email"
2660
+ ) : d, _e = i ? Pe(
2661
+ y,
2662
+ this.msg.oauthMethodTitle,
2663
+ this.msg.oauthMethodMeta,
2664
+ a`<singlebase-authui-buttons
2665
+ type="oauth"
2666
+ embedded
2667
+ theme=${k(this.theme)}
2668
+ density=${k(this.density)}
2669
+ field-style=${k(this.fieldStyle)}
2670
+ .client=${this.resolvedClient}
2671
+ .messages=${this.messages}
2672
+ .settings=${this.settings ?? this.settingsCtl.settings}
2673
+ intent=${t === "signup" ? "signup" : "signin"}
2674
+ ></singlebase-authui-buttons>`,
2675
+ () => this.method = y ? "" : "oauth",
2676
+ "oauth"
2677
+ ) : d;
2678
+ return a`
2679
+ <div class="acc-wrap">
2680
+ ${this.oauthPlacement === "top" ? a`${_e}${ke}` : a`${ke}${_e}`}
2681
+ </div>
2682
+ `;
2683
+ }
2684
+ renderScreenBody(t) {
2685
+ return this.cfg, ["signin", "signup", "otp"].indexOf(t) >= 0 ? this.renderAccordion(t) : t === "forgot" ? a`<div class="fields">${this.renderEmailField(this.uid("reset"))}</div>` : t === "verify" ? a`
2686
+ ${this.renderCodeRow()}
2687
+ <div class="resend-row">
2688
+ <span class="hint">${this.msg.resendQuestion}</span>
2689
+ <button type="button" class="link-sm" ?disabled=${this.loading} @click=${this.onResend}>
2690
+ ${this.msg.resendCta}
2691
+ </button>
2692
+ </div>
2693
+ ` : t === "newpass" ? a`
2694
+ <div class="fields">
2695
+ <div class="field">
2696
+ <label for=${this.uid("newpass")}>${this.msg.newPasswordLabel}</label>
2697
+ <input
2698
+ id=${this.uid("newpass")}
2699
+ type="password"
2700
+ part="input"
2701
+ .value=${this.newPass}
2702
+ placeholder=${this.msg.newPasswordPlaceholder}
2703
+ aria-invalid=${this.newPassError ? "true" : "false"}
2704
+ ?disabled=${this.loading}
2705
+ @input=${(s) => {
2706
+ this.newPass = s.target.value, this.newPassError = "";
2707
+ }}
2708
+ />
2709
+ </div>
2710
+ <div class="field">
2711
+ <label for=${this.uid("confirmpass")}>${this.msg.confirmPasswordLabel}</label>
2712
+ <input
2713
+ id=${this.uid("confirmpass")}
2714
+ type="password"
2715
+ part="input"
2716
+ .value=${this.confirmPass}
2717
+ placeholder=${this.msg.confirmPasswordPlaceholder}
2718
+ aria-invalid=${this.newPassError ? "true" : "false"}
2719
+ ?disabled=${this.loading}
2720
+ @input=${(s) => {
2721
+ this.confirmPass = s.target.value, this.newPassError = "";
2722
+ }}
2723
+ />
2724
+ ${this.newPassError ? a`<p class="err">${this.newPassError}</p>` : d}
2725
+ </div>
2726
+ </div>
2727
+ ` : t === "invite" ? a`
2728
+ <div class="fields">
2729
+ <div class="invite-box">
2730
+ <span class="invite-label">${this.msg.invitedEmailLabel}</span>
2731
+ <span class="invite-email">${this.inviteEmail}</span>
2732
+ </div>
2733
+ ${this.inviteCode ? d : a`<div class="field">
2734
+ <span class="label">Invite code</span>
2735
+ ${this.renderCodeRow(!0)}
2736
+ </div>`}
2737
+ <div class="two-up">
2738
+ <div class="field">
2739
+ <label for=${this.uid("first")}>${this.msg.firstNameLabel}</label>
2740
+ <input
2741
+ id=${this.uid("first")}
2742
+ type="text"
2743
+ part="input"
2744
+ .value=${this.firstName}
2745
+ placeholder=${this.msg.firstNamePlaceholder}
2746
+ ?disabled=${this.loading}
2747
+ @input=${(s) => this.firstName = s.target.value}
2748
+ />
2749
+ </div>
2750
+ <div class="field">
2751
+ <label for=${this.uid("last")}>${this.msg.lastNameLabel}</label>
2752
+ <input
2753
+ id=${this.uid("last")}
2754
+ type="text"
2755
+ part="input"
2756
+ .value=${this.lastName}
2757
+ placeholder=${this.msg.lastNamePlaceholder}
2758
+ ?disabled=${this.loading}
2759
+ @input=${(s) => this.lastName = s.target.value}
2760
+ />
2761
+ </div>
2762
+ </div>
2763
+ <div class="field">
2764
+ <label for=${this.uid("phone")}>${this.msg.phoneLabel}</label>
2765
+ <input
2766
+ id=${this.uid("phone")}
2767
+ type="tel"
2768
+ part="input"
2769
+ .value=${this.phone}
2770
+ placeholder=${this.msg.phonePlaceholder}
2771
+ ?disabled=${this.loading}
2772
+ @input=${(s) => this.phone = s.target.value}
2773
+ />
2774
+ </div>
2775
+ <div class="field">
2776
+ <label for=${this.uid("invitepass")}>${this.msg.passwordLabel}</label>
2777
+ <input
2778
+ id=${this.uid("invitepass")}
2779
+ type="password"
2780
+ part="input"
2781
+ .value=${this.password}
2782
+ placeholder=${this.msg.newPasswordPlaceholder}
2783
+ aria-invalid=${this.passError ? "true" : "false"}
2784
+ ?disabled=${this.loading}
2785
+ @input=${(s) => {
2786
+ this.password = s.target.value, this.passError = "";
2787
+ }}
2788
+ />
2789
+ ${this.passError ? a`<p class="err">${this.passError}</p>` : d}
2790
+ </div>
2791
+ </div>
2792
+ ` : d;
2793
+ }
2794
+ renderGuest(t) {
2795
+ const e = this.cfg, s = ["forgot", "verify", "newpass", "invite"].indexOf(t) >= 0, i = this.stepped && this.step > 0 || ["forgot", "verify", "otp", "newpass"].indexOf(t) >= 0, h = t === "signin" && e.allowEmailSignup || t === "signup" && e.allowEmailSignin, c = this.stepped && (t === "signin" || t === "signup");
2796
+ return a`
2797
+ <form class="stack" @submit=${this.onSubmit} novalidate>
2798
+ <div class="head">
2799
+ ${this.layout !== "split" ? this.renderLogo() : d}
2800
+ <h2 class="title" part="title">${this.titleFor(t)}</h2>
2801
+ <p class="sub">${this.subFor(t)}</p>
2802
+ </div>
2803
+
2804
+ ${c ? a`<div class="step-bar">
2805
+ <div class="step-fill" style="width:${this.stepPct()}%"></div>
2806
+ </div>` : d}
2807
+ ${this.banner ? a`<div class="banner" part="banner" role="alert">${this.banner}</div>` : d}
2808
+ ${this.notice ? a`<div class="notice" part="notice" role="status">${this.notice}</div>` : d}
2809
+ ${this.renderScreenBody(t)}
2810
+ ${s || i ? a`
2811
+ <div class="actions">
2812
+ ${s ? this.renderPrimary(this.ctaFor(t)) : d}
2813
+ ${i ? a`<button type="button" class="ghost" @click=${this.goBack}>
2814
+ ${this.msg.backCta}
2815
+ </button>` : d}
2816
+ </div>
2817
+ ` : d}
2818
+ ${h ? a`
2819
+ <p class="foot">
2820
+ <span
2821
+ >${t === "signup" ? this.msg.footTextSignUp : this.msg.footTextSignIn}</span
2822
+ >
2823
+ <button
2824
+ type="button"
2825
+ class="link"
2826
+ @click=${() => this.setScreen(t === "signup" ? "signin" : "signup", {
2827
+ step: 0,
2828
+ notice: ""
2829
+ })}
2830
+ >
2831
+ ${t === "signup" ? this.msg.footActionSignUp : this.msg.footActionSignIn}
2832
+ </button>
2833
+ </p>
2834
+ ` : d}
2835
+ ${this.renderConsent()}
2836
+
2837
+ <span class="sr-only" role="status" aria-live="polite">
2838
+ ${this.loading ? "Submitting…" : ""}
2839
+ </span>
2840
+ </form>
2841
+ `;
2842
+ }
2843
+ renderBlocked() {
2844
+ const e = !this.cfg.authEnabled;
2845
+ return a`
2846
+ <div class="stack">
2847
+ <div class="head">
2848
+ ${this.layout !== "split" ? this.renderLogo() : d}
2849
+ <h2 class="title" part="title">
2850
+ ${e ? this.msg.blockedTitleDisabled : this.msg.blockedTitleUnavailable}
2851
+ </h2>
2852
+ <p class="sub">
2853
+ ${e ? this.msg.blockedBodyDisabled : this.msg.blockedBodyUnavailable}
2854
+ </p>
2855
+ </div>
2856
+ <div class="notice" part="notice" role="status">${this.msg.blockedHint}</div>
2857
+ </div>
2858
+ `;
2859
+ }
2860
+ /**
2861
+ * Shown when a signed-in visitor lands on a guest screen. Rather than
2862
+ * presenting a sign-in form to someone already signed in, offer the two
2863
+ * things they could actually want: carry on, or switch accounts.
2864
+ */
2865
+ renderSignedIn() {
2866
+ const t = this.auth.state.status === "authenticated" ? this.auth.state.user : null, e = this.redirectTarget;
2867
+ return a`
2868
+ <div class="stack">
2869
+ <div class="head">
2870
+ ${this.renderLogo()}
2871
+ <h2 class="title" part="title">${this.msg.alreadySignedInTitle}</h2>
2872
+ <p class="sub">
2873
+ ${t != null && t.email ? `${this.msg.alreadySignedInSubPrefix} ${t.email}.` : this.msg.alreadySignedInSub}
2874
+ </p>
2875
+ </div>
2876
+
2877
+ <div class="actions">
2878
+ <button type="button" class="primary" part="button-primary" @click=${this.onContinue}>
2879
+ <span>${this.msg.continueCta}</span>
2880
+ </button>
2881
+ <button type="button" class="ghost" @click=${this.onInterstitialSignOut}>
2882
+ <span>${this.msg.signOutCta}</span>
2883
+ </button>
2884
+ </div>
2885
+
2886
+ ${e ? d : a`<p class="hint">${this.msg.continueHint}</p>`}
2887
+ </div>
2888
+ `;
2889
+ }
2890
+ /** The Terms/Privacy consent line, rendered only when the host supplies a link. */
2891
+ renderConsent() {
2892
+ if (!this.tosUrl && !this.privacyUrl) return d;
2893
+ const t = this.tosUrl ? a`<a class="link-sm" href=${this.tosUrl} target="_blank" rel="noopener noreferrer"
2894
+ >${this.msg.termsLabel}</a
2895
+ >` : d, e = this.privacyUrl ? a`<a class="link-sm" href=${this.privacyUrl} target="_blank" rel="noopener noreferrer"
2896
+ >${this.msg.privacyLabel}</a
2897
+ >` : d;
2898
+ return a`
2899
+ <p class="hint" part="consent">
2900
+ ${this.msg.consentPrefix}
2901
+ ${t}${this.tosUrl && this.privacyUrl ? a` ${this.msg.consentJoin} ` : d}${e}.
2902
+ </p>
2903
+ `;
2904
+ }
2905
+ render() {
2906
+ const t = this.activeScreen;
2907
+ if (t === "oauth-callback")
2908
+ return this.handleOAuthCallback(), this.panel(this.renderOAuthCallback());
2909
+ if (t === "account")
2910
+ return this.noAccountView ? d : this.panel(a`
2911
+ <singlebase-authui-account
2912
+ theme=${k(this.theme)}
2913
+ density=${k(this.density)}
2914
+ field-style=${k(this.fieldStyle)}
2915
+ .client=${this.resolvedClient}
2916
+ .messages=${this.messages}
2917
+ logo-text=${this.logoText}
2918
+ logo-url=${this.logoUrl}
2919
+ ></singlebase-authui-account>
2920
+ `);
2921
+ if (this.showsSignedInInterstitial)
2922
+ return this.noAccountView ? d : this.panel(this.renderSignedIn());
2923
+ const e = this.cfg, s = !e.allowEmailSignin && !e.allowEmailOtp && !e.allowOauth, i = !e.authEnabled || s && Ne(t);
2924
+ return a`
2925
+ ${this.layout === "split" ? a`
2926
+ <div class="brand-panel">
2927
+ ${this.renderBrandMark()}
2928
+ ${this.brandLine ? a`<div class="brand-copy">${this.brandLine}</div>` : d}
2929
+ ${this.brandFoot ? a`<div class="brand-foot">${this.brandFoot}</div>` : d}
2930
+ </div>
2931
+ ` : d}
2932
+ ${this.panel(i ? this.renderBlocked() : this.renderGuest(t))}
2933
+ `;
2934
+ }
2935
+ }, bt = new WeakMap(), ft = new WeakMap(), vt = new WeakMap(), wt = new WeakMap(), $t = new WeakMap(), yt = new WeakMap(), Et = new WeakMap(), St = new WeakMap(), Ct = new WeakMap(), Pt = new WeakMap(), kt = new WeakMap(), _t = new WeakMap(), Ot = new WeakMap(), xt = new WeakMap(), Tt = new WeakMap(), Ut = new WeakMap(), Lt = new WeakMap(), At = new WeakMap(), Mt = new WeakMap(), Nt = new WeakMap(), It = new WeakMap(), Ft = new WeakMap(), Dt = new WeakMap(), Bt = new WeakMap(), Rt = new WeakMap(), Ht = new WeakMap(), jt = new WeakMap(), qt = new WeakMap(), Gt = new WeakMap(), Vt = new WeakMap(), Kt = new WeakMap(), Yt = new WeakMap(), Wt = new WeakMap(), zt = new WeakMap(), Jt = new WeakMap(), Qt = new WeakMap(), Xt = new WeakMap(), Zt = new WeakMap(), te = new WeakMap(), ee = new WeakMap(), se = new WeakMap(), ie = new WeakMap(), ae = new WeakMap(), re = new WeakMap(), ne = new WeakMap(), oe = new WeakMap(), le = new WeakMap(), Be);
2936
+ Us(u, "styles", [
2937
+ ...$.styles,
2938
+ je`
2939
+ /* the mock's root */
2940
+ :host {
2941
+ display: flex;
2942
+ width: 100%;
2943
+ box-sizing: border-box;
2944
+ background: var(--sb-surface, #ffffff);
2945
+ color: var(--sb-ink, #16181a);
2946
+ border: 1px solid var(--sb-border, #e4e6e9);
2947
+ border-radius: calc(var(--sb-radius, 4px) + 4px);
2948
+ overflow: hidden;
2949
+ }
2950
+
2951
+ .brand-panel {
2952
+ flex: 0 0 40%;
2953
+ display: flex;
2954
+ flex-direction: column;
2955
+ justify-content: space-between;
2956
+ gap: 24px;
2957
+ padding: var(--sb-pad, 20px);
2958
+ background: var(--sb-surface-alt, #fafafa);
2959
+ border-right: 1px solid var(--sb-border, #e4e6e9);
2960
+ }
2961
+
2962
+ /* A flex column would stretch an image to full width and wreck its
2963
+ aspect ratio, so both logos opt out of the cross-axis stretch. */
2964
+ .logo-img {
2965
+ display: block;
2966
+ align-self: flex-start;
2967
+ height: var(--sb-logo-height, 20px);
2968
+ width: auto;
2969
+ max-width: 100%;
2970
+ margin-bottom: 6px;
2971
+ }
2972
+
2973
+ .brand-img {
2974
+ display: block;
2975
+ align-self: flex-start;
2976
+ height: var(--sb-brand-logo-height, 28px);
2977
+ width: auto;
2978
+ max-width: 100%;
2979
+ }
2980
+
2981
+ .brand-mark {
2982
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
2983
+ font-size: 13px;
2984
+ letter-spacing: 0.08em;
2985
+ text-transform: uppercase;
2986
+ color: var(--sb-ink, #16181a);
2987
+ }
2988
+
2989
+ .brand-copy {
2990
+ font-size: 20px;
2991
+ line-height: 1.35;
2992
+ letter-spacing: -0.01em;
2993
+ color: var(--sb-ink, #16181a);
2994
+ text-wrap: pretty;
2995
+ }
2996
+
2997
+ .brand-foot {
2998
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
2999
+ font-size: 11px;
3000
+ color: var(--sb-muted-ink, #61666c);
3001
+ }
3002
+
3003
+ .branding {
3004
+ margin-top: 18px;
3005
+ text-align: center;
3006
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
3007
+ font-size: 10.5px;
3008
+ letter-spacing: 0.06em;
3009
+ color: var(--sb-muted-ink, #61666c);
3010
+ }
3011
+
3012
+ .branding a {
3013
+ color: inherit;
3014
+ text-decoration: none;
3015
+ }
3016
+
3017
+ .branding a:hover {
3018
+ color: var(--sb-ink, #16181a);
3019
+ text-decoration: underline;
3020
+ text-underline-offset: 3px;
3021
+ }
3022
+
3023
+ /* the mock's panel */
3024
+ .panel {
3025
+ flex: 1;
3026
+ min-width: 0;
3027
+ padding: var(--sb-pad, 20px);
3028
+ }
3029
+
3030
+ @media (max-width: 520px) {
3031
+ :host {
3032
+ flex-direction: column;
3033
+ }
3034
+ .brand-panel {
3035
+ flex: 0 0 auto;
3036
+ border-right: none;
3037
+ border-bottom: 1px solid var(--sb-border, #e4e6e9);
3038
+ }
3039
+ }
3040
+ `
3041
+ ]);
3042
+ g([
3043
+ p({ attribute: "initial-screen" })
3044
+ ], u.prototype, "initialScreen", 1);
3045
+ g([
3046
+ p({ reflect: !0 })
3047
+ ], u.prototype, "screen", 1);
3048
+ g([
3049
+ p({ type: Boolean, attribute: "no-account-view" })
3050
+ ], u.prototype, "noAccountView", 1);
3051
+ g([
3052
+ p({ attribute: !1 })
3053
+ ], u.prototype, "settings", 1);
3054
+ g([
3055
+ p({ converter: P, attribute: "auth-enabled" })
3056
+ ], u.prototype, "authEnabled", 1);
3057
+ g([
3058
+ p({ converter: P, attribute: "allow-email-signin" })
3059
+ ], u.prototype, "allowEmailSignin", 1);
3060
+ g([
3061
+ p({ converter: P, attribute: "allow-email-signup" })
3062
+ ], u.prototype, "allowEmailSignup", 1);
3063
+ g([
3064
+ p({ converter: P, attribute: "allow-email-otp" })
3065
+ ], u.prototype, "allowEmailOtp", 1);
3066
+ g([
3067
+ p({ converter: P, attribute: "allow-oauth" })
3068
+ ], u.prototype, "allowOauth", 1);
3069
+ g([
3070
+ p({ converter: P, attribute: "allow-account-creation" })
3071
+ ], u.prototype, "allowAccountCreation", 1);
3072
+ g([
3073
+ p()
3074
+ ], u.prototype, "layout", 1);
3075
+ g([
3076
+ p({ attribute: "oauth-placement" })
3077
+ ], u.prototype, "oauthPlacement", 1);
3078
+ g([
3079
+ p({ type: Boolean })
3080
+ ], u.prototype, "stepped", 1);
3081
+ g([
3082
+ p({ attribute: "logo-text" })
3083
+ ], u.prototype, "logoText", 1);
3084
+ g([
3085
+ p({ attribute: "logo-url" })
3086
+ ], u.prototype, "logoUrl", 1);
3087
+ g([
3088
+ p({ attribute: "brand-line" })
3089
+ ], u.prototype, "brandLine", 1);
3090
+ g([
3091
+ p({ attribute: "brand-foot" })
3092
+ ], u.prototype, "brandFoot", 1);
3093
+ g([
3094
+ p({ attribute: "sign-in-title" })
3095
+ ], u.prototype, "signInTitle", 1);
3096
+ g([
3097
+ p({ converter: P, attribute: "branding" })
3098
+ ], u.prototype, "branding", 1);
3099
+ g([
3100
+ p({ attribute: "redirect-url" })
3101
+ ], u.prototype, "redirectUrl", 1);
3102
+ g([
3103
+ p({ attribute: "tos-url" })
3104
+ ], u.prototype, "tosUrl", 1);
3105
+ g([
3106
+ p({ attribute: "privacy-url" })
3107
+ ], u.prototype, "privacyUrl", 1);
3108
+ g([
3109
+ p({ attribute: "nonce-storage-key" })
3110
+ ], u.prototype, "nonceStorageKey", 1);
3111
+ g([
3112
+ p({ attribute: "invite-email" })
3113
+ ], u.prototype, "inviteEmail", 1);
3114
+ g([
3115
+ p({ attribute: "invite-org" })
3116
+ ], u.prototype, "inviteOrg", 1);
3117
+ g([
3118
+ p({ attribute: "invite-code" })
3119
+ ], u.prototype, "inviteCode", 1);
3120
+ g([
3121
+ m()
3122
+ ], u.prototype, "step", 1);
3123
+ g([
3124
+ m()
3125
+ ], u.prototype, "method", 1);
3126
+ g([
3127
+ m()
3128
+ ], u.prototype, "email", 1);
3129
+ g([
3130
+ m()
3131
+ ], u.prototype, "password", 1);
3132
+ g([
3133
+ m()
3134
+ ], u.prototype, "name", 1);
3135
+ g([
3136
+ m()
3137
+ ], u.prototype, "firstName", 1);
3138
+ g([
3139
+ m()
3140
+ ], u.prototype, "lastName", 1);
3141
+ g([
3142
+ m()
3143
+ ], u.prototype, "phone", 1);
3144
+ g([
3145
+ m()
3146
+ ], u.prototype, "newPass", 1);
3147
+ g([
3148
+ m()
3149
+ ], u.prototype, "confirmPass", 1);
3150
+ g([
3151
+ m()
3152
+ ], u.prototype, "code", 1);
3153
+ g([
3154
+ m()
3155
+ ], u.prototype, "verifyNext", 1);
3156
+ g([
3157
+ m()
3158
+ ], u.prototype, "loading", 1);
3159
+ g([
3160
+ m()
3161
+ ], u.prototype, "banner", 1);
3162
+ g([
3163
+ m()
3164
+ ], u.prototype, "notice", 1);
3165
+ g([
3166
+ m()
3167
+ ], u.prototype, "emailError", 1);
3168
+ g([
3169
+ m()
3170
+ ], u.prototype, "passError", 1);
3171
+ g([
3172
+ m()
3173
+ ], u.prototype, "newPassError", 1);
3174
+ g([
3175
+ m()
3176
+ ], u.prototype, "attempts", 1);
3177
+ g([
3178
+ m()
3179
+ ], u.prototype, "needsMfaCode", 1);
3180
+ g([
3181
+ m()
3182
+ ], u.prototype, "callbackDone", 1);
3183
+ u = g([
3184
+ fe("singlebase-authui")
3185
+ ], u);
3186
+ var Ms = Object.defineProperty, Ns = Object.getOwnPropertyDescriptor, Ee = (r, t, e, s) => {
3187
+ for (var i = s > 1 ? void 0 : s ? Ns(t, e) : t, h = r.length - 1, c; h >= 0; h--)
3188
+ (c = r[h]) && (i = (s ? c(t, e, i) : c(i)) || i);
3189
+ return s && i && Ms(t, e, i), i;
3190
+ };
3191
+ const Is = ["loading", "authenticated", "unauthenticated"];
3192
+ var he, de, ce, Re;
3193
+ let O = (Re = class extends $ {
3194
+ constructor() {
3195
+ super(...arguments);
3196
+ o(this, he, "");
3197
+ o(this, de, null);
3198
+ o(this, ce, "unauthenticated");
3199
+ b(this, "warnedFor", null);
3200
+ }
3201
+ get slot() {
3202
+ return n(this, he);
3203
+ }
3204
+ set slot(t) {
3205
+ l(this, he, t);
3206
+ }
3207
+ get predicate() {
3208
+ return n(this, de);
3209
+ }
3210
+ set predicate(t) {
3211
+ l(this, de, t);
3212
+ }
3213
+ get onMismatch() {
3214
+ return n(this, ce);
3215
+ }
3216
+ set onMismatch(t) {
3217
+ l(this, ce, t);
3218
+ }
3219
+ createRenderRoot() {
3220
+ return this;
3221
+ }
3222
+ /** The state this guard currently resolves to, after applying the predicate. */
3223
+ get activeState() {
3224
+ const t = this.auth.state.status;
3225
+ if (t === "loading") return "loading";
3226
+ if (t !== "authenticated") return "unauthenticated";
3227
+ if (!this.predicate) return "authenticated";
3228
+ this.warnOnce(this.predicate);
3229
+ const e = this.auth.state.user;
3230
+ return us(e, this.predicate) ? "authenticated" : this.onMismatch === "hidden" ? "hidden" : "unauthenticated";
3231
+ }
3232
+ /** Surfaces a malformed predicate once, rather than silently never matching. */
3233
+ warnOnce(t) {
3234
+ const e = JSON.stringify(t);
3235
+ if (this.warnedFor !== e) {
3236
+ this.warnedFor = e;
3237
+ for (const s of ps(t))
3238
+ console.warn(`[singlebase] <singlebase-authui-guard> predicate: ${s}`);
3239
+ }
3240
+ }
3241
+ render() {
3242
+ const t = this.activeState;
3243
+ if (this.slot) {
3244
+ const e = Is.includes(this.slot) && this.slot === t;
3245
+ return this.toggleAttribute("hidden", !e), a`<slot></slot>`;
3246
+ }
3247
+ this.toggleAttribute("hidden", !1);
3248
+ for (const e of Array.from(this.children)) {
3249
+ const s = e.getAttribute("slot");
3250
+ e.toggleAttribute("hidden", s !== t);
3251
+ }
3252
+ return a`<slot></slot>`;
3253
+ }
3254
+ }, he = new WeakMap(), de = new WeakMap(), ce = new WeakMap(), Re);
3255
+ Ee([
3256
+ p({ reflect: !0 })
3257
+ ], O.prototype, "slot", 1);
3258
+ Ee([
3259
+ p({
3260
+ converter: {
3261
+ fromAttribute: (r) => {
3262
+ if (!r) return null;
3263
+ try {
3264
+ return JSON.parse(r);
3265
+ } catch {
3266
+ return console.error("[singlebase] guard predicate is not valid JSON:", r), null;
3267
+ }
3268
+ },
3269
+ toAttribute: (r) => r ? JSON.stringify(r) : null
3270
+ }
3271
+ })
3272
+ ], O.prototype, "predicate", 1);
3273
+ Ee([
3274
+ p({ attribute: "on-mismatch" })
3275
+ ], O.prototype, "onMismatch", 1);
3276
+ O = Ee([
3277
+ fe("singlebase-authui-guard")
3278
+ ], O);
3279
+ var We = Object.defineProperty, Fs = Object.getOwnPropertyDescriptor, Ds = (r, t, e) => t in r ? We(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e, _ = (r, t, e, s) => {
3280
+ for (var i = s > 1 ? void 0 : s ? Fs(t, e) : t, h = r.length - 1, c; h >= 0; h--)
3281
+ (c = r[h]) && (i = (s ? c(t, e, i) : c(i)) || i);
3282
+ return s && i && We(t, e, i), i;
3283
+ }, Bs = (r, t, e) => Ds(r, t + "", e);
3284
+ const Rs = "profile_photo";
3285
+ var ue, pe, ge, me, be, He;
3286
+ let S = (He = class extends $ {
3287
+ constructor() {
3288
+ super(...arguments);
3289
+ o(this, ue, "");
3290
+ o(this, pe, "");
3291
+ o(this, ge, !1);
3292
+ o(this, me, "");
3293
+ o(this, be, !1);
3294
+ }
3295
+ get path() {
3296
+ return n(this, ue);
3297
+ }
3298
+ set path(t) {
3299
+ l(this, ue, t);
3300
+ }
3301
+ get fallback() {
3302
+ return n(this, pe);
3303
+ }
3304
+ set fallback(t) {
3305
+ l(this, pe, t);
3306
+ }
3307
+ get avatar() {
3308
+ return n(this, ge);
3309
+ }
3310
+ set avatar(t) {
3311
+ l(this, ge, t);
3312
+ }
3313
+ get alt() {
3314
+ return n(this, me);
3315
+ }
3316
+ set alt(t) {
3317
+ l(this, me, t);
3318
+ }
3319
+ get imageFailed() {
3320
+ return n(this, be);
3321
+ }
3322
+ set imageFailed(t) {
3323
+ l(this, be, t);
3324
+ }
3325
+ willUpdate(t) {
3326
+ super.willUpdate(t), (t.has("path") || t.has("avatar")) && (this.imageFailed = !1);
3327
+ }
3328
+ get profile() {
3329
+ const t = this.auth.state;
3330
+ return t.status === "authenticated" ? t.user : null;
3331
+ }
3332
+ /** The resolved value as a string, or "" when there is nothing to show. */
3333
+ get textValue() {
3334
+ const t = this.profile;
3335
+ if (!t || !this.path) return "";
3336
+ const e = Le(t, this.path);
3337
+ return e == null || e === "" ? "" : Array.isArray(e) ? e.filter((s) => s != null).join(", ") : typeof e == "object" ? "" : String(e);
3338
+ }
3339
+ get avatarSrc() {
3340
+ const t = this.profile;
3341
+ if (!t) return "";
3342
+ const e = Le(t, this.path || Rs);
3343
+ return typeof e == "string" ? e : "";
3344
+ }
3345
+ render() {
3346
+ if (this.auth.state.status === "loading") return d;
3347
+ if (this.avatar) return this.renderAvatar();
3348
+ const t = this.textValue;
3349
+ return t ? a`<span part="text">${t}</span>` : this.fallback ? a`<span part="text">${this.fallback}</span>` : d;
3350
+ }
3351
+ renderAvatar() {
3352
+ const t = this.profile;
3353
+ if (!t) return d;
3354
+ const e = this.avatarSrc;
3355
+ return e && !this.imageFailed ? a`<img
3356
+ part="avatar-image"
3357
+ src=${e}
3358
+ alt=${this.alt}
3359
+ @error=${() => this.imageFailed = !0}
3360
+ />` : a`<span
3361
+ part="avatar-initials"
3362
+ class="initials"
3363
+ aria-hidden=${this.alt ? "false" : "true"}
3364
+ >${Ge(t)}</span
3365
+ >`;
3366
+ }
3367
+ }, ue = new WeakMap(), pe = new WeakMap(), ge = new WeakMap(), me = new WeakMap(), be = new WeakMap(), He);
3368
+ Bs(S, "styles", [
3369
+ ...$.styles,
3370
+ je`
3371
+ /* Text sits in a sentence; an avatar is a box the host sizes. */
3372
+ :host {
3373
+ display: inline;
3374
+ }
3375
+
3376
+ :host([avatar]) {
3377
+ display: inline-block;
3378
+ width: 42px;
3379
+ height: 42px;
3380
+ vertical-align: middle;
3381
+ }
3382
+
3383
+ img,
3384
+ .initials {
3385
+ display: block;
3386
+ width: 100%;
3387
+ height: 100%;
3388
+ border-radius: inherit;
3389
+ box-sizing: border-box;
3390
+ }
3391
+
3392
+ img {
3393
+ object-fit: cover;
3394
+ }
3395
+
3396
+ /* Matches the avatar in the account view. */
3397
+ .initials {
3398
+ display: flex;
3399
+ align-items: center;
3400
+ justify-content: center;
3401
+ background: var(--sb-surface-alt, #fafafa);
3402
+ border: 1px dashed var(--sb-border, #e4e6e9);
3403
+ font-family: var(--sb-mono, "Geist Mono", ui-monospace, monospace);
3404
+ font-size: 0.8em;
3405
+ color: var(--sb-muted-ink, #61666c);
3406
+ user-select: none;
3407
+ }
3408
+ `
3409
+ ]);
3410
+ _([
3411
+ p()
3412
+ ], S.prototype, "path", 1);
3413
+ _([
3414
+ p()
3415
+ ], S.prototype, "fallback", 1);
3416
+ _([
3417
+ p({ type: Boolean, reflect: !0 })
3418
+ ], S.prototype, "avatar", 1);
3419
+ _([
3420
+ p()
3421
+ ], S.prototype, "alt", 1);
3422
+ _([
3423
+ m()
3424
+ ], S.prototype, "imageFailed", 1);
3425
+ S = _([
3426
+ fe("singlebase-authui-display")
3427
+ ], S);
3428
+ export {
3429
+ gs as A,
3430
+ Se as S,
3431
+ f as a,
3432
+ E as b,
3433
+ S as c,
3434
+ O as d,
3435
+ u as e,
3436
+ Ae as f,
3437
+ qe as g,
3438
+ Ne as h,
3439
+ Ge as i,
3440
+ As as j,
3441
+ Ie as k,
3442
+ ms as r
3443
+ };
3444
+ //# sourceMappingURL=display-8HEcKYR4.js.map