@design.estate/dees-catalog 3.97.0 → 3.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_bundle/bundle.js +4701 -3485
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-button/dees-button/dees-button.d.ts +35 -0
- package/dist_ts_web/elements/00group-button/dees-button/dees-button.js +128 -5
- package/dist_ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.js +5 -6
- package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.d.ts +1 -0
- package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.js +21 -11
- package/dist_ts_web/elements/00group-feedback/dees-spinner/dees-spinner.js +12 -3
- package/dist_ts_web/elements/00group-form/dees-form-submit/dees-form-submit.d.ts +9 -0
- package/dist_ts_web/elements/00group-form/dees-form-submit/dees-form-submit.js +25 -2
- package/dist_ts_web/elements/00group-input/dees-input-multitoggle/dees-input-multitoggle.js +20 -4
- package/dist_ts_web/elements/00group-input/dees-input-text/dees-input-text.d.ts +15 -0
- package/dist_ts_web/elements/00group-input/dees-input-text/dees-input-text.js +36 -2
- package/dist_ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.js +2 -1
- package/dist_ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.d.ts +246 -0
- package/dist_ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.demo.js +439 -21
- package/dist_ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.js +857 -23
- package/dist_ts_web/elements/00group-utility/dees-icon/dees-icon.d.ts +2 -1
- package/dist_ts_web/elements/00group-utility/dees-icon/dees-icon.js +52 -80
- package/dist_ts_web/elements/00theme.d.ts +2 -0
- package/dist_ts_web/elements/00theme.js +7 -1
- package/package.json +3 -3
- package/readme.hints.md +35 -0
- package/readme.md +85 -11
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-button/dees-button/dees-button.ts +128 -2
- package/ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.ts +5 -6
- package/ts_web/elements/00group-dataview/dees-table/dees-table.ts +43 -27
- package/ts_web/elements/00group-feedback/dees-spinner/dees-spinner.ts +11 -2
- package/ts_web/elements/00group-form/dees-form-submit/dees-form-submit.ts +18 -0
- package/ts_web/elements/00group-input/dees-input-multitoggle/dees-input-multitoggle.ts +19 -3
- package/ts_web/elements/00group-input/dees-input-text/dees-input-text.ts +29 -0
- package/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts +1 -0
- package/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.demo.ts +418 -19
- package/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.ts +969 -20
- package/ts_web/elements/00group-utility/dees-icon/dees-icon.ts +55 -91
- package/ts_web/elements/00theme.ts +8 -0
|
@@ -33,9 +33,46 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
35
|
import { demoFunc } from './dees-simple-login.demo.js';
|
|
36
|
-
import { customElement, html, DeesElement, property, cssManager, css, } from '@design.estate/dees-element';
|
|
36
|
+
import { customElement, html, DeesElement, property, state, cssManager, css, } from '@design.estate/dees-element';
|
|
37
37
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
38
38
|
import '../../00group-layout/dees-tile/dees-tile.js';
|
|
39
|
+
import '../../00group-button/dees-button/dees-button.js';
|
|
40
|
+
import '../../00group-form/dees-form/dees-form.js';
|
|
41
|
+
import '../../00group-form/dees-form-submit/dees-form-submit.js';
|
|
42
|
+
import '../../00group-input/dees-input-text/dees-input-text.js';
|
|
43
|
+
import '../../00group-utility/dees-icon/dees-icon.js';
|
|
44
|
+
const canonicalMethodOrder = ['passkey', 'provider', 'password'];
|
|
45
|
+
/**
|
|
46
|
+
* dees-simple-login — the login surface for an application shell.
|
|
47
|
+
*
|
|
48
|
+
* Offers up to three authentication methods in one card: passkeys, identity providers
|
|
49
|
+
* ("sign in with …") and a username/password form. A method is offered only when it is
|
|
50
|
+
* configured, so the zero-configuration default is the password form alone.
|
|
51
|
+
*
|
|
52
|
+
* ## Who owns the WebAuthn ceremony
|
|
53
|
+
*
|
|
54
|
+
* Not this component. A passkey ceremony needs server-issued options and server-side
|
|
55
|
+
* verification, so the catalog deliberately carries no WebAuthn dependency and no
|
|
56
|
+
* knowledge of any wire protocol. There are two ways to plug a ceremony in, and exactly
|
|
57
|
+
* one of them is active per interaction:
|
|
58
|
+
*
|
|
59
|
+
* 1. **Event mode** (no handler set) — the component dispatches `passkey-login`,
|
|
60
|
+
* `passkey-register` or `provider-login` and stops. The consumer drives everything and
|
|
61
|
+
* reports progress back through `setBusy()` / `reportError()`.
|
|
62
|
+
* 2. **Handler mode** (handler property set) — the component awaits the handler, owns the
|
|
63
|
+
* per-method busy state and turns a rejection into that method's error message. The
|
|
64
|
+
* request event is *not* dispatched, so a ceremony can never be started twice.
|
|
65
|
+
*
|
|
66
|
+
* The legacy `login` event is a notification rather than a request and always fires, even
|
|
67
|
+
* when `passwordLoginHandler` is set. Do not both listen to `login` and set that handler.
|
|
68
|
+
*
|
|
69
|
+
* ## Shadow DOM contract
|
|
70
|
+
*
|
|
71
|
+
* Consumers reach into this shadow root: `.loginContainer`, `.login` and `.slotContainer`
|
|
72
|
+
* carry the post-login transition, and `shadowRoot.querySelector('dees-form')` is expected
|
|
73
|
+
* to be the password form. Those are load-bearing and must not be renamed, and no second
|
|
74
|
+
* `dees-form` may precede the password form.
|
|
75
|
+
*/
|
|
39
76
|
let DeesSimpleLogin = (() => {
|
|
40
77
|
let _classDecorators = [customElement('dees-simple-login')];
|
|
41
78
|
let _classDescriptor;
|
|
@@ -45,12 +82,87 @@ let DeesSimpleLogin = (() => {
|
|
|
45
82
|
let _name_decorators;
|
|
46
83
|
let _name_initializers = [];
|
|
47
84
|
let _name_extraInitializers = [];
|
|
85
|
+
let _passkey_decorators;
|
|
86
|
+
let _passkey_initializers = [];
|
|
87
|
+
let _passkey_extraInitializers = [];
|
|
88
|
+
let _passkeyIntents_decorators;
|
|
89
|
+
let _passkeyIntents_initializers = [];
|
|
90
|
+
let _passkeyIntents_extraInitializers = [];
|
|
91
|
+
let _passkeyAvailable_decorators;
|
|
92
|
+
let _passkeyAvailable_initializers = [];
|
|
93
|
+
let _passkeyAvailable_extraInitializers = [];
|
|
94
|
+
let _passkeyAutofill_decorators;
|
|
95
|
+
let _passkeyAutofill_initializers = [];
|
|
96
|
+
let _passkeyAutofill_extraInitializers = [];
|
|
97
|
+
let _providers_decorators;
|
|
98
|
+
let _providers_initializers = [];
|
|
99
|
+
let _providers_extraInitializers = [];
|
|
100
|
+
let _password_decorators;
|
|
101
|
+
let _password_initializers = [];
|
|
102
|
+
let _password_extraInitializers = [];
|
|
103
|
+
let _methodOrder_decorators;
|
|
104
|
+
let _methodOrder_initializers = [];
|
|
105
|
+
let _methodOrder_extraInitializers = [];
|
|
106
|
+
let _labels_decorators;
|
|
107
|
+
let _labels_initializers = [];
|
|
108
|
+
let _labels_extraInitializers = [];
|
|
109
|
+
let _passkeyLoginHandler_decorators;
|
|
110
|
+
let _passkeyLoginHandler_initializers = [];
|
|
111
|
+
let _passkeyLoginHandler_extraInitializers = [];
|
|
112
|
+
let _passkeyRegisterHandler_decorators;
|
|
113
|
+
let _passkeyRegisterHandler_initializers = [];
|
|
114
|
+
let _passkeyRegisterHandler_extraInitializers = [];
|
|
115
|
+
let _providerLoginHandler_decorators;
|
|
116
|
+
let _providerLoginHandler_initializers = [];
|
|
117
|
+
let _providerLoginHandler_extraInitializers = [];
|
|
118
|
+
let _passwordLoginHandler_decorators;
|
|
119
|
+
let _passwordLoginHandler_initializers = [];
|
|
120
|
+
let _passwordLoginHandler_extraInitializers = [];
|
|
121
|
+
let _detectedPasskeySupport_decorators;
|
|
122
|
+
let _detectedPasskeySupport_initializers = [];
|
|
123
|
+
let _detectedPasskeySupport_extraInitializers = [];
|
|
124
|
+
let _busyKeys_decorators;
|
|
125
|
+
let _busyKeys_initializers = [];
|
|
126
|
+
let _busyKeys_extraInitializers = [];
|
|
127
|
+
let _errorMap_decorators;
|
|
128
|
+
let _errorMap_initializers = [];
|
|
129
|
+
let _errorMap_extraInitializers = [];
|
|
48
130
|
var DeesSimpleLogin = class extends _classSuper {
|
|
49
131
|
static { _classThis = this; }
|
|
50
132
|
static {
|
|
51
133
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
52
134
|
_name_decorators = [property()];
|
|
135
|
+
_passkey_decorators = [property({ type: Boolean })];
|
|
136
|
+
_passkeyIntents_decorators = [property({ attribute: false })];
|
|
137
|
+
_passkeyAvailable_decorators = [property({ attribute: false })];
|
|
138
|
+
_passkeyAutofill_decorators = [property({ type: Boolean })];
|
|
139
|
+
_providers_decorators = [property({ attribute: false })];
|
|
140
|
+
_password_decorators = [property({ type: Boolean })];
|
|
141
|
+
_methodOrder_decorators = [property({ attribute: false })];
|
|
142
|
+
_labels_decorators = [property({ attribute: false })];
|
|
143
|
+
_passkeyLoginHandler_decorators = [property({ attribute: false })];
|
|
144
|
+
_passkeyRegisterHandler_decorators = [property({ attribute: false })];
|
|
145
|
+
_providerLoginHandler_decorators = [property({ attribute: false })];
|
|
146
|
+
_passwordLoginHandler_decorators = [property({ attribute: false })];
|
|
147
|
+
_detectedPasskeySupport_decorators = [state()];
|
|
148
|
+
_busyKeys_decorators = [state()];
|
|
149
|
+
_errorMap_decorators = [state()];
|
|
53
150
|
__esDecorate(this, null, _name_decorators, { kind: "accessor", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
|
|
151
|
+
__esDecorate(this, null, _passkey_decorators, { kind: "accessor", name: "passkey", static: false, private: false, access: { has: obj => "passkey" in obj, get: obj => obj.passkey, set: (obj, value) => { obj.passkey = value; } }, metadata: _metadata }, _passkey_initializers, _passkey_extraInitializers);
|
|
152
|
+
__esDecorate(this, null, _passkeyIntents_decorators, { kind: "accessor", name: "passkeyIntents", static: false, private: false, access: { has: obj => "passkeyIntents" in obj, get: obj => obj.passkeyIntents, set: (obj, value) => { obj.passkeyIntents = value; } }, metadata: _metadata }, _passkeyIntents_initializers, _passkeyIntents_extraInitializers);
|
|
153
|
+
__esDecorate(this, null, _passkeyAvailable_decorators, { kind: "accessor", name: "passkeyAvailable", static: false, private: false, access: { has: obj => "passkeyAvailable" in obj, get: obj => obj.passkeyAvailable, set: (obj, value) => { obj.passkeyAvailable = value; } }, metadata: _metadata }, _passkeyAvailable_initializers, _passkeyAvailable_extraInitializers);
|
|
154
|
+
__esDecorate(this, null, _passkeyAutofill_decorators, { kind: "accessor", name: "passkeyAutofill", static: false, private: false, access: { has: obj => "passkeyAutofill" in obj, get: obj => obj.passkeyAutofill, set: (obj, value) => { obj.passkeyAutofill = value; } }, metadata: _metadata }, _passkeyAutofill_initializers, _passkeyAutofill_extraInitializers);
|
|
155
|
+
__esDecorate(this, null, _providers_decorators, { kind: "accessor", name: "providers", static: false, private: false, access: { has: obj => "providers" in obj, get: obj => obj.providers, set: (obj, value) => { obj.providers = value; } }, metadata: _metadata }, _providers_initializers, _providers_extraInitializers);
|
|
156
|
+
__esDecorate(this, null, _password_decorators, { kind: "accessor", name: "password", static: false, private: false, access: { has: obj => "password" in obj, get: obj => obj.password, set: (obj, value) => { obj.password = value; } }, metadata: _metadata }, _password_initializers, _password_extraInitializers);
|
|
157
|
+
__esDecorate(this, null, _methodOrder_decorators, { kind: "accessor", name: "methodOrder", static: false, private: false, access: { has: obj => "methodOrder" in obj, get: obj => obj.methodOrder, set: (obj, value) => { obj.methodOrder = value; } }, metadata: _metadata }, _methodOrder_initializers, _methodOrder_extraInitializers);
|
|
158
|
+
__esDecorate(this, null, _labels_decorators, { kind: "accessor", name: "labels", static: false, private: false, access: { has: obj => "labels" in obj, get: obj => obj.labels, set: (obj, value) => { obj.labels = value; } }, metadata: _metadata }, _labels_initializers, _labels_extraInitializers);
|
|
159
|
+
__esDecorate(this, null, _passkeyLoginHandler_decorators, { kind: "accessor", name: "passkeyLoginHandler", static: false, private: false, access: { has: obj => "passkeyLoginHandler" in obj, get: obj => obj.passkeyLoginHandler, set: (obj, value) => { obj.passkeyLoginHandler = value; } }, metadata: _metadata }, _passkeyLoginHandler_initializers, _passkeyLoginHandler_extraInitializers);
|
|
160
|
+
__esDecorate(this, null, _passkeyRegisterHandler_decorators, { kind: "accessor", name: "passkeyRegisterHandler", static: false, private: false, access: { has: obj => "passkeyRegisterHandler" in obj, get: obj => obj.passkeyRegisterHandler, set: (obj, value) => { obj.passkeyRegisterHandler = value; } }, metadata: _metadata }, _passkeyRegisterHandler_initializers, _passkeyRegisterHandler_extraInitializers);
|
|
161
|
+
__esDecorate(this, null, _providerLoginHandler_decorators, { kind: "accessor", name: "providerLoginHandler", static: false, private: false, access: { has: obj => "providerLoginHandler" in obj, get: obj => obj.providerLoginHandler, set: (obj, value) => { obj.providerLoginHandler = value; } }, metadata: _metadata }, _providerLoginHandler_initializers, _providerLoginHandler_extraInitializers);
|
|
162
|
+
__esDecorate(this, null, _passwordLoginHandler_decorators, { kind: "accessor", name: "passwordLoginHandler", static: false, private: false, access: { has: obj => "passwordLoginHandler" in obj, get: obj => obj.passwordLoginHandler, set: (obj, value) => { obj.passwordLoginHandler = value; } }, metadata: _metadata }, _passwordLoginHandler_initializers, _passwordLoginHandler_extraInitializers);
|
|
163
|
+
__esDecorate(this, null, _detectedPasskeySupport_decorators, { kind: "accessor", name: "detectedPasskeySupport", static: false, private: false, access: { has: obj => "detectedPasskeySupport" in obj, get: obj => obj.detectedPasskeySupport, set: (obj, value) => { obj.detectedPasskeySupport = value; } }, metadata: _metadata }, _detectedPasskeySupport_initializers, _detectedPasskeySupport_extraInitializers);
|
|
164
|
+
__esDecorate(this, null, _busyKeys_decorators, { kind: "accessor", name: "busyKeys", static: false, private: false, access: { has: obj => "busyKeys" in obj, get: obj => obj.busyKeys, set: (obj, value) => { obj.busyKeys = value; } }, metadata: _metadata }, _busyKeys_initializers, _busyKeys_extraInitializers);
|
|
165
|
+
__esDecorate(this, null, _errorMap_decorators, { kind: "accessor", name: "errorMap", static: false, private: false, access: { has: obj => "errorMap" in obj, get: obj => obj.errorMap, set: (obj, value) => { obj.errorMap = value; } }, metadata: _metadata }, _errorMap_initializers, _errorMap_extraInitializers);
|
|
54
166
|
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
55
167
|
DeesSimpleLogin = _classThis = _classDescriptor.value;
|
|
56
168
|
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
@@ -60,8 +172,88 @@ let DeesSimpleLogin = (() => {
|
|
|
60
172
|
static demoGroups = ['Simple'];
|
|
61
173
|
#name_accessor_storage = __runInitializers(this, _name_initializers, 'Application');
|
|
62
174
|
// INSTANCE
|
|
175
|
+
/** application name, interpolated into the default subheading */
|
|
63
176
|
get name() { return this.#name_accessor_storage; }
|
|
64
177
|
set name(value) { this.#name_accessor_storage = value; }
|
|
178
|
+
#passkey_accessor_storage = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _passkey_initializers, false));
|
|
179
|
+
/**
|
|
180
|
+
* offer a passkey affordance. Silently drops out when the browser cannot do WebAuthn,
|
|
181
|
+
* unless it is the only configured method — then the card explains itself instead of
|
|
182
|
+
* rendering empty.
|
|
183
|
+
*/
|
|
184
|
+
get passkey() { return this.#passkey_accessor_storage; }
|
|
185
|
+
set passkey(value) { this.#passkey_accessor_storage = value; }
|
|
186
|
+
#passkeyIntents_accessor_storage = (__runInitializers(this, _passkey_extraInitializers), __runInitializers(this, _passkeyIntents_initializers, ['authenticate']));
|
|
187
|
+
/** which passkey affordances to render, in this order */
|
|
188
|
+
get passkeyIntents() { return this.#passkeyIntents_accessor_storage; }
|
|
189
|
+
set passkeyIntents(value) { this.#passkeyIntents_accessor_storage = value; }
|
|
190
|
+
#passkeyAvailable_accessor_storage = (__runInitializers(this, _passkeyIntents_extraInitializers), __runInitializers(this, _passkeyAvailable_initializers, undefined));
|
|
191
|
+
/**
|
|
192
|
+
* overrides browser capability detection. `undefined` detects automatically; set it when
|
|
193
|
+
* the server already knows whether passkeys are configured for this deployment.
|
|
194
|
+
*/
|
|
195
|
+
get passkeyAvailable() { return this.#passkeyAvailable_accessor_storage; }
|
|
196
|
+
set passkeyAvailable(value) { this.#passkeyAvailable_accessor_storage = value; }
|
|
197
|
+
#passkeyAutofill_accessor_storage = (__runInitializers(this, _passkeyAvailable_extraInitializers), __runInitializers(this, _passkeyAutofill_initializers, false));
|
|
198
|
+
/**
|
|
199
|
+
* opt into WebAuthn conditional mediation (passkey autofill). Requires
|
|
200
|
+
* `passkeyLoginHandler` and a rendered password method — the username field is what the
|
|
201
|
+
* browser attaches its passkey picker to. Silently inert when either is missing.
|
|
202
|
+
*/
|
|
203
|
+
get passkeyAutofill() { return this.#passkeyAutofill_accessor_storage; }
|
|
204
|
+
set passkeyAutofill(value) { this.#passkeyAutofill_accessor_storage = value; }
|
|
205
|
+
#providers_accessor_storage = (__runInitializers(this, _passkeyAutofill_extraInitializers), __runInitializers(this, _providers_initializers, []));
|
|
206
|
+
/** identity providers to offer. Empty means the provider method is not configured. */
|
|
207
|
+
get providers() { return this.#providers_accessor_storage; }
|
|
208
|
+
set providers(value) { this.#providers_accessor_storage = value; }
|
|
209
|
+
#password_accessor_storage = (__runInitializers(this, _providers_extraInitializers), __runInitializers(this, _password_initializers, true));
|
|
210
|
+
/** offer the username/password form. On by default — set `.password=${false}` to drop it. */
|
|
211
|
+
get password() { return this.#password_accessor_storage; }
|
|
212
|
+
set password(value) { this.#password_accessor_storage = value; }
|
|
213
|
+
#methodOrder_accessor_storage = (__runInitializers(this, _password_extraInitializers), __runInitializers(this, _methodOrder_initializers, ['passkey', 'provider', 'password']));
|
|
214
|
+
/**
|
|
215
|
+
* reorders the configured methods. Configured methods missing from this list are appended
|
|
216
|
+
* in canonical order, so an incomplete list can never silently hide a method.
|
|
217
|
+
*/
|
|
218
|
+
get methodOrder() { return this.#methodOrder_accessor_storage; }
|
|
219
|
+
set methodOrder(value) { this.#methodOrder_accessor_storage = value; }
|
|
220
|
+
#labels_accessor_storage = (__runInitializers(this, _methodOrder_extraInitializers), __runInitializers(this, _labels_initializers, {}));
|
|
221
|
+
/** copy overrides */
|
|
222
|
+
get labels() { return this.#labels_accessor_storage; }
|
|
223
|
+
set labels(value) { this.#labels_accessor_storage = value; }
|
|
224
|
+
#passkeyLoginHandler_accessor_storage = (__runInitializers(this, _labels_extraInitializers), __runInitializers(this, _passkeyLoginHandler_initializers, undefined));
|
|
225
|
+
/** drives the passkey sign-in ceremony — see "Who owns the WebAuthn ceremony" */
|
|
226
|
+
get passkeyLoginHandler() { return this.#passkeyLoginHandler_accessor_storage; }
|
|
227
|
+
set passkeyLoginHandler(value) { this.#passkeyLoginHandler_accessor_storage = value; }
|
|
228
|
+
#passkeyRegisterHandler_accessor_storage = (__runInitializers(this, _passkeyLoginHandler_extraInitializers), __runInitializers(this, _passkeyRegisterHandler_initializers, undefined));
|
|
229
|
+
/** drives the passkey enrollment ceremony */
|
|
230
|
+
get passkeyRegisterHandler() { return this.#passkeyRegisterHandler_accessor_storage; }
|
|
231
|
+
set passkeyRegisterHandler(value) { this.#passkeyRegisterHandler_accessor_storage = value; }
|
|
232
|
+
#providerLoginHandler_accessor_storage = (__runInitializers(this, _passkeyRegisterHandler_extraInitializers), __runInitializers(this, _providerLoginHandler_initializers, undefined));
|
|
233
|
+
/** drives a provider sign-in (redirect or popup) */
|
|
234
|
+
get providerLoginHandler() { return this.#providerLoginHandler_accessor_storage; }
|
|
235
|
+
set providerLoginHandler(value) { this.#providerLoginHandler_accessor_storage = value; }
|
|
236
|
+
#passwordLoginHandler_accessor_storage = (__runInitializers(this, _providerLoginHandler_extraInitializers), __runInitializers(this, _passwordLoginHandler_initializers, undefined));
|
|
237
|
+
/** drives a credential sign-in. The legacy `login` event fires regardless. */
|
|
238
|
+
get passwordLoginHandler() { return this.#passwordLoginHandler_accessor_storage; }
|
|
239
|
+
set passwordLoginHandler(value) { this.#passwordLoginHandler_accessor_storage = value; }
|
|
240
|
+
#detectedPasskeySupport_accessor_storage = (__runInitializers(this, _passwordLoginHandler_extraInitializers), __runInitializers(this, _detectedPasskeySupport_initializers, {
|
|
241
|
+
available: false,
|
|
242
|
+
conditionalMediation: false,
|
|
243
|
+
platformAuthenticator: false,
|
|
244
|
+
}));
|
|
245
|
+
get detectedPasskeySupport() { return this.#detectedPasskeySupport_accessor_storage; }
|
|
246
|
+
set detectedPasskeySupport(value) { this.#detectedPasskeySupport_accessor_storage = value; }
|
|
247
|
+
#busyKeys_accessor_storage = (__runInitializers(this, _detectedPasskeySupport_extraInitializers), __runInitializers(this, _busyKeys_initializers, []));
|
|
248
|
+
get busyKeys() { return this.#busyKeys_accessor_storage; }
|
|
249
|
+
set busyKeys(value) { this.#busyKeys_accessor_storage = value; }
|
|
250
|
+
#errorMap_accessor_storage = (__runInitializers(this, _busyKeys_extraInitializers), __runInitializers(this, _errorMap_initializers, {}));
|
|
251
|
+
get errorMap() { return this.#errorMap_accessor_storage; }
|
|
252
|
+
set errorMap(value) { this.#errorMap_accessor_storage = value; }
|
|
253
|
+
ceremonyControllers = (__runInitializers(this, _errorMap_extraInitializers), new Map());
|
|
254
|
+
autofillController = undefined;
|
|
255
|
+
autofillStarted = false;
|
|
256
|
+
interactivityObserver = undefined;
|
|
65
257
|
static styles = [
|
|
66
258
|
themeDefaultStyles,
|
|
67
259
|
cssManager.defaultStyles,
|
|
@@ -84,6 +276,11 @@ let DeesSimpleLogin = (() => {
|
|
|
84
276
|
height: 100%;
|
|
85
277
|
top: 0;
|
|
86
278
|
left: 0;
|
|
279
|
+
box-sizing: border-box;
|
|
280
|
+
/* a card with passkey + several providers + credentials can outgrow a short
|
|
281
|
+
viewport, so the container scrolls instead of clipping */
|
|
282
|
+
padding: var(--dees-spacing-xl);
|
|
283
|
+
overflow-y: auto;
|
|
87
284
|
background: var(--dees-color-bg-primary);
|
|
88
285
|
}
|
|
89
286
|
|
|
@@ -121,8 +318,117 @@ let DeesSimpleLogin = (() => {
|
|
|
121
318
|
}
|
|
122
319
|
|
|
123
320
|
.subheader {
|
|
321
|
+
font-size: var(--dees-font-control-size);
|
|
322
|
+
/* secondary rather than muted: the tertiary label token is a 0.30 alpha and drops
|
|
323
|
+
under 2:1 against both backgrounds */
|
|
324
|
+
color: var(--dees-color-text-secondary);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.methods {
|
|
328
|
+
display: flex;
|
|
329
|
+
flex-direction: column;
|
|
330
|
+
gap: var(--dees-spacing-lg);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.method {
|
|
334
|
+
display: flex;
|
|
335
|
+
flex-direction: column;
|
|
336
|
+
gap: var(--dees-spacing-sm);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.methodActions {
|
|
340
|
+
display: flex;
|
|
341
|
+
flex-direction: column;
|
|
342
|
+
gap: var(--dees-spacing-sm);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* Four or more providers would turn the card into a tower, so they pair up. The
|
|
346
|
+
labels lose their prefix at the same time — see denseProviders. */
|
|
347
|
+
.methodActions.dense {
|
|
348
|
+
display: grid;
|
|
349
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* an odd trailing provider spans the row instead of leaving a ragged half cell */
|
|
353
|
+
.methodActions.dense > :last-child:nth-child(odd) {
|
|
354
|
+
grid-column: 1 / -1;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* dees-button's default pending face is a 20% accent tint with accent-coloured text,
|
|
358
|
+
which lands under 2:1 on a dark canvas. Each group therefore states a busy face in
|
|
359
|
+
its own emphasis instead: the primary action keeps its solid accent, and a provider
|
|
360
|
+
keeps its secondary surface so only the spinner changes. */
|
|
361
|
+
.passkeyActions dees-button {
|
|
362
|
+
--button-pending-bg: var(--dees-color-accent-primary);
|
|
363
|
+
--button-pending-fg: var(--dees-color-on-accent);
|
|
364
|
+
--dees-spinner-color: var(--dees-color-on-accent);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.providerActions dees-button {
|
|
368
|
+
--button-pending-bg: var(--dees-color-fill-secondary);
|
|
369
|
+
--button-pending-fg: var(--dees-color-text-primary);
|
|
370
|
+
--dees-spinner-color: var(--dees-color-text-primary);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.divider {
|
|
374
|
+
display: flex;
|
|
375
|
+
align-items: center;
|
|
376
|
+
gap: var(--dees-spacing-md);
|
|
377
|
+
font-size: var(--dees-font-control-size-sm);
|
|
378
|
+
color: var(--dees-color-text-secondary);
|
|
379
|
+
text-transform: lowercase;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.divider::before,
|
|
383
|
+
.divider::after {
|
|
384
|
+
content: '';
|
|
385
|
+
flex: 1;
|
|
386
|
+
height: 1px;
|
|
387
|
+
background: var(--dees-color-border-subtle);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.methodError {
|
|
391
|
+
display: flex;
|
|
392
|
+
align-items: flex-start;
|
|
393
|
+
gap: var(--dees-spacing-xs);
|
|
394
|
+
font-size: var(--dees-font-control-size-sm);
|
|
395
|
+
line-height: 1.4;
|
|
396
|
+
color: var(--dees-color-text-error);
|
|
397
|
+
user-select: text;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.methodError dees-icon {
|
|
401
|
+
flex-shrink: 0;
|
|
402
|
+
margin-top: 1px;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.unavailable {
|
|
406
|
+
padding: var(--dees-spacing-lg);
|
|
407
|
+
border: 1px solid var(--dees-color-border-subtle);
|
|
408
|
+
border-radius: var(--dees-radius-xl);
|
|
409
|
+
corner-shape: var(--dees-corner-shape);
|
|
410
|
+
background: var(--dees-color-bg-secondary);
|
|
124
411
|
font-size: var(--dees-font-control-size);
|
|
125
412
|
color: var(--dees-color-text-muted);
|
|
413
|
+
text-align: center;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* The bare credentials block, used whenever the card already offers another method.
|
|
417
|
+
A nested tile there would inset the fields 24px against full-width buttons above
|
|
418
|
+
it and add a second frame inside the card. */
|
|
419
|
+
.credentials {
|
|
420
|
+
display: flex;
|
|
421
|
+
flex-direction: column;
|
|
422
|
+
gap: var(--dees-spacing-lg);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.credentials dees-input-text {
|
|
426
|
+
width: 100%;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.credentials dees-form-submit {
|
|
430
|
+
margin-top: var(--dees-spacing-sm);
|
|
431
|
+
width: 100%;
|
|
126
432
|
}
|
|
127
433
|
|
|
128
434
|
dees-tile {
|
|
@@ -149,21 +455,149 @@ let DeesSimpleLogin = (() => {
|
|
|
149
455
|
}
|
|
150
456
|
`,
|
|
151
457
|
];
|
|
458
|
+
// ------------------------------------------------------------------------------------
|
|
459
|
+
// resolution
|
|
460
|
+
// ------------------------------------------------------------------------------------
|
|
461
|
+
/** resolved browser capability, with `passkeyAvailable` applied */
|
|
462
|
+
get passkeySupport() {
|
|
463
|
+
if (this.passkeyAvailable === undefined) {
|
|
464
|
+
return this.detectedPasskeySupport;
|
|
465
|
+
}
|
|
466
|
+
return { ...this.detectedPasskeySupport, available: this.passkeyAvailable };
|
|
467
|
+
}
|
|
468
|
+
/** the methods that are configured, in render order */
|
|
469
|
+
get resolvedMethods() {
|
|
470
|
+
const configured = canonicalMethodOrder.filter((methodArg) => this.isConfigured(methodArg));
|
|
471
|
+
const ordered = [];
|
|
472
|
+
for (const methodArg of this.methodOrder || []) {
|
|
473
|
+
if (configured.includes(methodArg) && !ordered.includes(methodArg)) {
|
|
474
|
+
ordered.push(methodArg);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
for (const methodArg of configured) {
|
|
478
|
+
if (!ordered.includes(methodArg)) {
|
|
479
|
+
ordered.push(methodArg);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return ordered;
|
|
483
|
+
}
|
|
484
|
+
isConfigured(methodArg) {
|
|
485
|
+
switch (methodArg) {
|
|
486
|
+
case 'passkey':
|
|
487
|
+
return this.passkey && this.passkeySupport.available && this.resolvedPasskeyIntents.length > 0;
|
|
488
|
+
case 'provider':
|
|
489
|
+
return this.providers.length > 0;
|
|
490
|
+
case 'password':
|
|
491
|
+
return this.password;
|
|
492
|
+
default:
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
get resolvedPasskeyIntents() {
|
|
497
|
+
const intents = (this.passkeyIntents || []).filter((intentArg, index, all) => all.indexOf(intentArg) === index);
|
|
498
|
+
return intents.length > 0 ? intents : ['authenticate'];
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* true when nothing at all is offered — typically a passkey-only card in a browser that
|
|
502
|
+
* cannot do WebAuthn. Silent degradation would leave an empty card, so this case gets a
|
|
503
|
+
* message instead.
|
|
504
|
+
*/
|
|
505
|
+
get isUnavailable() {
|
|
506
|
+
return this.resolvedMethods.length === 0;
|
|
507
|
+
}
|
|
508
|
+
get shouldOfferPasskeyAutofill() {
|
|
509
|
+
const methods = this.resolvedMethods;
|
|
510
|
+
return (this.passkeyAutofill &&
|
|
511
|
+
Boolean(this.passkeyLoginHandler) &&
|
|
512
|
+
this.passkeySupport.conditionalMediation &&
|
|
513
|
+
methods.includes('passkey') &&
|
|
514
|
+
methods.includes('password'));
|
|
515
|
+
}
|
|
516
|
+
copy(keyArg, fallbackArg) {
|
|
517
|
+
const value = (this.labels || {})[keyArg];
|
|
518
|
+
return value === undefined ? fallbackArg : value;
|
|
519
|
+
}
|
|
520
|
+
// ------------------------------------------------------------------------------------
|
|
521
|
+
// per-method state
|
|
522
|
+
// ------------------------------------------------------------------------------------
|
|
523
|
+
static targetKey(targetArg) {
|
|
524
|
+
const target = typeof targetArg === 'string' ? { method: targetArg } : targetArg;
|
|
525
|
+
if (target.method === 'passkey') {
|
|
526
|
+
return `passkey:${target.intent || 'authenticate'}`;
|
|
527
|
+
}
|
|
528
|
+
if (target.method === 'provider') {
|
|
529
|
+
return `provider:${target.providerId || ''}`;
|
|
530
|
+
}
|
|
531
|
+
return 'password';
|
|
532
|
+
}
|
|
533
|
+
/** true while a ceremony for this target is running */
|
|
534
|
+
isBusy(targetArg) {
|
|
535
|
+
return this.busyKeys.includes(DeesSimpleLogin.targetKey(targetArg));
|
|
536
|
+
}
|
|
537
|
+
/** marks a target busy — for consumers driving a ceremony from an intent event */
|
|
538
|
+
setBusy(targetArg, busyArg) {
|
|
539
|
+
const key = DeesSimpleLogin.targetKey(targetArg);
|
|
540
|
+
const isBusy = this.busyKeys.includes(key);
|
|
541
|
+
if (busyArg === isBusy) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
this.busyKeys = busyArg
|
|
545
|
+
? [...this.busyKeys, key]
|
|
546
|
+
: this.busyKeys.filter((busyKey) => busyKey !== key);
|
|
547
|
+
}
|
|
548
|
+
/** the error currently shown for a target, if any */
|
|
549
|
+
getError(targetArg) {
|
|
550
|
+
return this.errorMap[DeesSimpleLogin.targetKey(targetArg)];
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* shows an error next to one method without touching the others — a failed passkey
|
|
554
|
+
* attempt must never blank the password form.
|
|
555
|
+
*/
|
|
556
|
+
reportError(targetArg, messageArg) {
|
|
557
|
+
const key = DeesSimpleLogin.targetKey(targetArg);
|
|
558
|
+
if (this.errorMap[key] === messageArg) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
this.errorMap = { ...this.errorMap, [key]: messageArg };
|
|
562
|
+
}
|
|
563
|
+
/** clears one target's error, or every error when called without a target */
|
|
564
|
+
clearError(targetArg) {
|
|
565
|
+
if (targetArg === undefined) {
|
|
566
|
+
if (Object.keys(this.errorMap).length > 0) {
|
|
567
|
+
this.errorMap = {};
|
|
568
|
+
}
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const key = DeesSimpleLogin.targetKey(targetArg);
|
|
572
|
+
if (this.errorMap[key] === undefined) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const nextMap = { ...this.errorMap };
|
|
576
|
+
delete nextMap[key];
|
|
577
|
+
this.errorMap = nextMap;
|
|
578
|
+
}
|
|
579
|
+
/** clears every busy and error state and resets the password form */
|
|
580
|
+
reset() {
|
|
581
|
+
this.abortCeremonies();
|
|
582
|
+
this.busyKeys = [];
|
|
583
|
+
this.errorMap = {};
|
|
584
|
+
const form = this.shadowRoot?.querySelector('dees-form');
|
|
585
|
+
form?.reset();
|
|
586
|
+
}
|
|
587
|
+
// ------------------------------------------------------------------------------------
|
|
588
|
+
// render
|
|
589
|
+
// ------------------------------------------------------------------------------------
|
|
152
590
|
render() {
|
|
153
591
|
return html `
|
|
154
592
|
<div class="loginContainer">
|
|
155
593
|
<div class="login">
|
|
156
594
|
<div class="login-header">
|
|
157
|
-
<div class="header"
|
|
158
|
-
<div class="subheader">
|
|
595
|
+
<div class="header">${this.copy('heading', 'Sign in')}</div>
|
|
596
|
+
<div class="subheader">
|
|
597
|
+
${this.copy('subheading', `Enter your credentials to access ${this.name}`)}
|
|
598
|
+
</div>
|
|
159
599
|
</div>
|
|
160
|
-
|
|
161
|
-
<dees-form>
|
|
162
|
-
<dees-input-text key="username" label="Username" required></dees-input-text>
|
|
163
|
-
<dees-input-text key="password" label="Password" isPasswordBool required></dees-input-text>
|
|
164
|
-
<dees-form-submit>Sign in</dees-form-submit>
|
|
165
|
-
</dees-form>
|
|
166
|
-
</dees-tile>
|
|
600
|
+
${this.renderMethods()}
|
|
167
601
|
</div>
|
|
168
602
|
</div>
|
|
169
603
|
<div class="slotContainer">
|
|
@@ -171,18 +605,422 @@ let DeesSimpleLogin = (() => {
|
|
|
171
605
|
</div>
|
|
172
606
|
`;
|
|
173
607
|
}
|
|
608
|
+
renderMethods() {
|
|
609
|
+
if (this.isUnavailable) {
|
|
610
|
+
return html `
|
|
611
|
+
<div class="methods">
|
|
612
|
+
<div class="unavailable">
|
|
613
|
+
${this.copy('unavailable', 'No sign-in method is available in this browser.')}
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
`;
|
|
617
|
+
}
|
|
618
|
+
const methods = this.resolvedMethods;
|
|
619
|
+
return html `
|
|
620
|
+
<div class="methods">
|
|
621
|
+
${methods.map((methodArg, index) => html `
|
|
622
|
+
${index === 0
|
|
623
|
+
? ''
|
|
624
|
+
: html `<div class="divider">${this.copy('divider', 'or')}</div>`}
|
|
625
|
+
${this.renderMethod(methodArg)}
|
|
626
|
+
`)}
|
|
627
|
+
</div>
|
|
628
|
+
`;
|
|
629
|
+
}
|
|
630
|
+
renderMethod(methodArg) {
|
|
631
|
+
if (methodArg === 'passkey') {
|
|
632
|
+
return this.renderPasskeyMethod();
|
|
633
|
+
}
|
|
634
|
+
if (methodArg === 'provider') {
|
|
635
|
+
return this.renderProviderMethod();
|
|
636
|
+
}
|
|
637
|
+
return this.renderPasswordMethod();
|
|
638
|
+
}
|
|
639
|
+
renderPasskeyMethod() {
|
|
640
|
+
const intents = this.resolvedPasskeyIntents;
|
|
641
|
+
// Concurrent WebAuthn calls reject each other, so a running ceremony locks the *other*
|
|
642
|
+
// passkey intent — providers and the password form stay usable. The busy button itself
|
|
643
|
+
// is never marked disabled: dees-button dims a disabled face to 50% opacity, which
|
|
644
|
+
// would wash out the pending spinner. handlePasskey() guards the re-entry instead.
|
|
645
|
+
const anyPasskeyBusy = intents.some((intentArg) => this.isBusy({ method: 'passkey', intent: intentArg }));
|
|
646
|
+
return html `
|
|
647
|
+
<div class="method">
|
|
648
|
+
<div class="methodActions passkeyActions">
|
|
649
|
+
${intents.map((intentArg) => {
|
|
650
|
+
const busy = this.isBusy({ method: 'passkey', intent: intentArg });
|
|
651
|
+
const isRegister = intentArg === 'register';
|
|
652
|
+
return html `
|
|
653
|
+
<dees-button
|
|
654
|
+
full-width
|
|
655
|
+
.type=${isRegister ? 'outline' : 'accent'}
|
|
656
|
+
.icon=${busy ? '' : isRegister ? 'lucide:keyRound' : 'lucide:fingerprint'}
|
|
657
|
+
.text=${isRegister
|
|
658
|
+
? this.copy('passkeyRegister', 'Create a passkey')
|
|
659
|
+
: this.copy('passkeyAuthenticate', 'Sign in with a passkey')}
|
|
660
|
+
.status=${busy ? 'pending' : 'normal'}
|
|
661
|
+
.disabled=${anyPasskeyBusy && !busy}
|
|
662
|
+
@clicked=${() => this.handlePasskey(intentArg)}
|
|
663
|
+
></dees-button>
|
|
664
|
+
`;
|
|
665
|
+
})}
|
|
666
|
+
</div>
|
|
667
|
+
${intents.map((intentArg) => this.renderError(this.getError({ method: 'passkey', intent: intentArg })))}
|
|
668
|
+
</div>
|
|
669
|
+
`;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Past three providers the buttons pair up into two columns, and the "Continue with"
|
|
673
|
+
* prefix is dropped so a bare provider name still fits its half-width button.
|
|
674
|
+
*/
|
|
675
|
+
get denseProviders() {
|
|
676
|
+
return this.providers.length >= 4;
|
|
677
|
+
}
|
|
678
|
+
renderProviderMethod() {
|
|
679
|
+
const dense = this.denseProviders;
|
|
680
|
+
// Half-width buttons cannot carry "Continue with …", so the prefix is dropped when the
|
|
681
|
+
// grid kicks in — unless the consumer stated one explicitly, which always wins.
|
|
682
|
+
const prefix = this.copy('providerPrefix', dense ? '' : 'Continue with');
|
|
683
|
+
return html `
|
|
684
|
+
<div class="method">
|
|
685
|
+
<div class="methodActions providerActions ${dense ? 'dense' : ''}">
|
|
686
|
+
${this.providers.map((providerArg) => {
|
|
687
|
+
const busy = this.isBusy({ method: 'provider', providerId: providerArg.id });
|
|
688
|
+
return html `
|
|
689
|
+
<dees-button
|
|
690
|
+
full-width
|
|
691
|
+
title=${dense ? providerArg.label : ''}
|
|
692
|
+
.type=${'secondary'}
|
|
693
|
+
.icon=${busy ? '' : providerArg.icon || ''}
|
|
694
|
+
.text=${prefix ? `${prefix} ${providerArg.label}` : providerArg.label}
|
|
695
|
+
.status=${busy ? 'pending' : 'normal'}
|
|
696
|
+
.disabled=${Boolean(providerArg.disabled)}
|
|
697
|
+
@clicked=${() => this.handleProvider(providerArg)}
|
|
698
|
+
></dees-button>
|
|
699
|
+
`;
|
|
700
|
+
})}
|
|
701
|
+
</div>
|
|
702
|
+
${this.renderError(this.getError({ method: 'provider' }))}
|
|
703
|
+
${this.providers.map((providerArg) => {
|
|
704
|
+
const message = this.getError({ method: 'provider', providerId: providerArg.id });
|
|
705
|
+
if (!message) {
|
|
706
|
+
return '';
|
|
707
|
+
}
|
|
708
|
+
return this.renderError(this.providers.length > 1 ? `${providerArg.label}: ${message}` : message);
|
|
709
|
+
})}
|
|
710
|
+
</div>
|
|
711
|
+
`;
|
|
712
|
+
}
|
|
713
|
+
renderPasswordMethod() {
|
|
714
|
+
// The submit label is slotted, not bound: consumers call dees-form.setStatus(), which
|
|
715
|
+
// writes dees-form-submit.text imperatively. A property binding here would clobber
|
|
716
|
+
// their status text on the next render.
|
|
717
|
+
const form = html `
|
|
718
|
+
<dees-form @formData=${this.handleFormData}>
|
|
719
|
+
<dees-input-text
|
|
720
|
+
key="username"
|
|
721
|
+
.label=${this.copy('usernameLabel', 'Username')}
|
|
722
|
+
.autocomplete=${this.shouldOfferPasskeyAutofill ? 'username webauthn' : 'username'}
|
|
723
|
+
required
|
|
724
|
+
></dees-input-text>
|
|
725
|
+
<dees-input-text
|
|
726
|
+
key="password"
|
|
727
|
+
.label=${this.copy('passwordLabel', 'Password')}
|
|
728
|
+
.autocomplete=${'current-password'}
|
|
729
|
+
isPasswordBool
|
|
730
|
+
required
|
|
731
|
+
></dees-input-text>
|
|
732
|
+
<dees-form-submit full-width>${this.copy('passwordSubmit', 'Sign in')}</dees-form-submit>
|
|
733
|
+
</dees-form>
|
|
734
|
+
`;
|
|
735
|
+
// The tile is what gives a lone credentials form its card. Once the column holds other
|
|
736
|
+
// methods the column *is* the card, and a second frame around only the fields reads as
|
|
737
|
+
// a stray box — so the form joins the column bare and keeps the same 360px edge.
|
|
738
|
+
return html `
|
|
739
|
+
<div class="method">
|
|
740
|
+
${this.resolvedMethods.length === 1
|
|
741
|
+
? html `
|
|
742
|
+
<dees-tile .heading=${this.copy('credentialsHeading', 'Credentials')}>
|
|
743
|
+
${form}
|
|
744
|
+
</dees-tile>
|
|
745
|
+
`
|
|
746
|
+
: html `<div class="credentials">${form}</div>`}
|
|
747
|
+
${this.renderError(this.getError('password'))}
|
|
748
|
+
</div>
|
|
749
|
+
`;
|
|
750
|
+
}
|
|
751
|
+
renderError(messageArg) {
|
|
752
|
+
if (!messageArg) {
|
|
753
|
+
return '';
|
|
754
|
+
}
|
|
755
|
+
return html `
|
|
756
|
+
<div class="methodError" role="alert">
|
|
757
|
+
<dees-icon .icon=${'lucide:circleAlert'} .iconSize=${14}></dees-icon>
|
|
758
|
+
<span>${messageArg}</span>
|
|
759
|
+
</div>
|
|
760
|
+
`;
|
|
761
|
+
}
|
|
762
|
+
// ------------------------------------------------------------------------------------
|
|
763
|
+
// lifecycle
|
|
764
|
+
// ------------------------------------------------------------------------------------
|
|
765
|
+
async connectedCallback() {
|
|
766
|
+
await super.connectedCallback();
|
|
767
|
+
this.detectPasskeySupportSync();
|
|
768
|
+
void this.detectPasskeySupportAsync();
|
|
769
|
+
}
|
|
174
770
|
async firstUpdated(_changedProperties) {
|
|
175
771
|
super.firstUpdated(_changedProperties);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
772
|
+
this.observeContainerInteractivity();
|
|
773
|
+
void this.maybeStartPasskeyAutofill();
|
|
774
|
+
}
|
|
775
|
+
updated(_changedProperties) {
|
|
776
|
+
super.updated(_changedProperties);
|
|
777
|
+
// Only take over the submit button's visual state when this component actually owns
|
|
778
|
+
// the credential ceremony. Legacy consumers drive it through dees-form.setStatus().
|
|
779
|
+
if (this.passwordLoginHandler) {
|
|
780
|
+
const submitButton = this.shadowRoot?.querySelector('dees-form-submit');
|
|
781
|
+
if (submitButton) {
|
|
782
|
+
submitButton.status = this.isBusy('password') ? 'pending' : 'normal';
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
void this.maybeStartPasskeyAutofill();
|
|
786
|
+
}
|
|
787
|
+
async disconnectedCallback() {
|
|
788
|
+
await super.disconnectedCallback();
|
|
789
|
+
this.abortCeremonies();
|
|
790
|
+
this.interactivityObserver?.disconnect();
|
|
791
|
+
this.interactivityObserver = undefined;
|
|
792
|
+
// re-arm autofill if this element is attached again
|
|
793
|
+
this.autofillStarted = false;
|
|
794
|
+
}
|
|
795
|
+
detectPasskeySupportSync() {
|
|
796
|
+
const available = typeof window !== 'undefined' &&
|
|
797
|
+
window.isSecureContext === true &&
|
|
798
|
+
typeof window.PublicKeyCredential ===
|
|
799
|
+
'function' &&
|
|
800
|
+
typeof navigator !== 'undefined' &&
|
|
801
|
+
typeof navigator.credentials?.get === 'function';
|
|
802
|
+
if (this.detectedPasskeySupport.available !== available) {
|
|
803
|
+
this.detectedPasskeySupport = { ...this.detectedPasskeySupport, available };
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
async detectPasskeySupportAsync() {
|
|
807
|
+
if (!this.detectedPasskeySupport.available) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const publicKeyCredential = window.PublicKeyCredential;
|
|
811
|
+
const probe = async (probeArg) => {
|
|
812
|
+
if (typeof probeArg !== 'function') {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
try {
|
|
816
|
+
return (await probeArg.call(publicKeyCredential)) === true;
|
|
817
|
+
}
|
|
818
|
+
catch {
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
const [conditionalMediation, platformAuthenticator] = await Promise.all([
|
|
823
|
+
probe(publicKeyCredential.isConditionalMediationAvailable),
|
|
824
|
+
probe(publicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable),
|
|
825
|
+
]);
|
|
826
|
+
this.detectedPasskeySupport = {
|
|
827
|
+
available: true,
|
|
828
|
+
conditionalMediation,
|
|
829
|
+
platformAuthenticator,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
// ------------------------------------------------------------------------------------
|
|
833
|
+
// interactions
|
|
834
|
+
// ------------------------------------------------------------------------------------
|
|
835
|
+
handleFormData = async (eventArg) => {
|
|
836
|
+
const detail = eventArg.detail;
|
|
837
|
+
if (this.isBusy('password')) {
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
this.clearError('password');
|
|
841
|
+
// Unchanged legacy contract: `login` carries dees-form's detail verbatim.
|
|
842
|
+
this.dispatchEvent(new CustomEvent('login', {
|
|
843
|
+
detail,
|
|
844
|
+
bubbles: true,
|
|
845
|
+
composed: true,
|
|
846
|
+
}));
|
|
847
|
+
if (!this.passwordLoginHandler) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
const handler = this.passwordLoginHandler;
|
|
851
|
+
await this.runCeremony({ method: 'password' }, () => handler({ data: detail?.data || {} }));
|
|
852
|
+
};
|
|
853
|
+
handlePasskey = async (intentArg) => {
|
|
854
|
+
const target = { method: 'passkey', intent: intentArg };
|
|
855
|
+
if (this.resolvedPasskeyIntents.some((candidate) => this.isBusy({ method: 'passkey', intent: candidate }))) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
// An explicit ceremony supersedes a silent autofill request; leaving both in flight
|
|
859
|
+
// makes the browser reject one of them.
|
|
860
|
+
this.abortAutofill();
|
|
861
|
+
this.clearError(target);
|
|
862
|
+
const handler = intentArg === 'register' ? this.passkeyRegisterHandler : this.passkeyLoginHandler;
|
|
863
|
+
if (!handler) {
|
|
864
|
+
this.dispatchEvent(new CustomEvent(intentArg === 'register' ? 'passkey-register' : 'passkey-login', {
|
|
865
|
+
detail: { intent: intentArg, username: this.readUsername() },
|
|
866
|
+
bubbles: true,
|
|
867
|
+
composed: true,
|
|
868
|
+
}));
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const key = DeesSimpleLogin.targetKey(target);
|
|
872
|
+
const controller = new AbortController();
|
|
873
|
+
this.ceremonyControllers.set(key, controller);
|
|
874
|
+
try {
|
|
875
|
+
await this.runCeremony(target, () => handler({
|
|
876
|
+
intent: intentArg,
|
|
877
|
+
username: this.readUsername(),
|
|
878
|
+
mediation: 'optional',
|
|
879
|
+
signal: controller.signal,
|
|
880
|
+
}));
|
|
881
|
+
}
|
|
882
|
+
finally {
|
|
883
|
+
if (this.ceremonyControllers.get(key) === controller) {
|
|
884
|
+
this.ceremonyControllers.delete(key);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
handleProvider = async (providerArg) => {
|
|
889
|
+
const target = { method: 'provider', providerId: providerArg.id };
|
|
890
|
+
if (providerArg.disabled || this.isBusy(target)) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
this.clearError(target);
|
|
894
|
+
if (!this.providerLoginHandler) {
|
|
895
|
+
this.dispatchEvent(new CustomEvent('provider-login', {
|
|
896
|
+
detail: { providerId: providerArg.id, provider: providerArg },
|
|
897
|
+
bubbles: true,
|
|
898
|
+
composed: true,
|
|
184
899
|
}));
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
const handler = this.providerLoginHandler;
|
|
903
|
+
await this.runCeremony(target, () => handler({ providerId: providerArg.id, provider: providerArg }));
|
|
904
|
+
};
|
|
905
|
+
async runCeremony(targetArg, ceremonyArg) {
|
|
906
|
+
this.setBusy(targetArg, true);
|
|
907
|
+
try {
|
|
908
|
+
await ceremonyArg();
|
|
909
|
+
}
|
|
910
|
+
catch (error) {
|
|
911
|
+
if (!DeesSimpleLogin.isAbortError(error)) {
|
|
912
|
+
this.reportError(targetArg, DeesSimpleLogin.toErrorMessage(error));
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
finally {
|
|
916
|
+
this.setBusy(targetArg, false);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Starts the browser's passkey autofill. Conditional mediation has to be requested
|
|
921
|
+
* before the user touches anything, and it must stay silent — a background ceremony that
|
|
922
|
+
* finds no credential is not an error the user should see.
|
|
923
|
+
*/
|
|
924
|
+
async maybeStartPasskeyAutofill() {
|
|
925
|
+
if (this.autofillStarted || !this.shouldOfferPasskeyAutofill) {
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
const handler = this.passkeyLoginHandler;
|
|
929
|
+
if (!handler) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
this.autofillStarted = true;
|
|
933
|
+
const controller = new AbortController();
|
|
934
|
+
this.autofillController = controller;
|
|
935
|
+
try {
|
|
936
|
+
await handler({
|
|
937
|
+
intent: 'authenticate',
|
|
938
|
+
username: undefined,
|
|
939
|
+
mediation: 'conditional',
|
|
940
|
+
signal: controller.signal,
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
catch (error) {
|
|
944
|
+
if (!DeesSimpleLogin.isAbortError(error)) {
|
|
945
|
+
console.warn('dees-simple-login: passkey autofill ceremony failed', error);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
finally {
|
|
949
|
+
if (this.autofillController === controller) {
|
|
950
|
+
this.autofillController = undefined;
|
|
951
|
+
}
|
|
952
|
+
// deliberately not reset: one silent attempt per connection, so a rejecting handler
|
|
953
|
+
// can never be retried in a render loop
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
abortAutofill() {
|
|
957
|
+
this.autofillController?.abort();
|
|
958
|
+
this.autofillController = undefined;
|
|
959
|
+
}
|
|
960
|
+
abortCeremonies() {
|
|
961
|
+
this.abortAutofill();
|
|
962
|
+
for (const controller of this.ceremonyControllers.values()) {
|
|
963
|
+
controller.abort();
|
|
964
|
+
}
|
|
965
|
+
this.ceremonyControllers.clear();
|
|
966
|
+
}
|
|
967
|
+
readUsername() {
|
|
968
|
+
const input = this.shadowRoot?.querySelector('dees-input-text[key="username"]');
|
|
969
|
+
const value = input?.value;
|
|
970
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
971
|
+
}
|
|
972
|
+
static isAbortError(errorArg) {
|
|
973
|
+
return Boolean(errorArg) && errorArg.name === 'AbortError';
|
|
974
|
+
}
|
|
975
|
+
static toErrorMessage(errorArg) {
|
|
976
|
+
if (errorArg instanceof Error) {
|
|
977
|
+
return errorArg.message;
|
|
978
|
+
}
|
|
979
|
+
return String(errorArg);
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* The login card and the slotted app are both permanently in the DOM, stacked and
|
|
983
|
+
* cross-faded with opacity plus `pointer-events`. That was enough while nothing inside
|
|
984
|
+
* either half could hold focus — but `dees-button` faces are focusable now, and
|
|
985
|
+
* `pointer-events: none` does not remove anything from the tab order. Without this, a
|
|
986
|
+
* keyboard user could Tab out of the password form straight into the invisible app shell,
|
|
987
|
+
* and after signing in could Tab back into the invisible login card and start a passkey
|
|
988
|
+
* ceremony there. `inert` is what actually takes a hidden subtree out of focus and the
|
|
989
|
+
* accessibility tree.
|
|
990
|
+
*
|
|
991
|
+
* Inertness is derived from each container's effective `pointer-events` rather than from
|
|
992
|
+
* an internal flag, because consumers reverse this transition by hand — cloudly's
|
|
993
|
+
* `switchToLoginContent()` writes these inline styles directly and knows nothing about
|
|
994
|
+
* `inert`. Keying off a flag they cannot reset would leave their login card permanently
|
|
995
|
+
* inert. A MutationObserver on the inline styles keeps both directions correct no matter
|
|
996
|
+
* who wrote them.
|
|
997
|
+
*/
|
|
998
|
+
syncContainerInertness = () => {
|
|
999
|
+
for (const selector of ['.loginContainer', '.slotContainer']) {
|
|
1000
|
+
const container = this.shadowRoot?.querySelector(selector);
|
|
1001
|
+
if (!(container instanceof HTMLElement)) {
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
container.inert = getComputedStyle(container).pointerEvents === 'none';
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
observeContainerInteractivity() {
|
|
1008
|
+
if (this.interactivityObserver) {
|
|
1009
|
+
return;
|
|
185
1010
|
}
|
|
1011
|
+
this.interactivityObserver = new MutationObserver(() => this.syncContainerInertness());
|
|
1012
|
+
for (const selector of ['.loginContainer', '.slotContainer']) {
|
|
1013
|
+
const container = this.shadowRoot?.querySelector(selector);
|
|
1014
|
+
if (container) {
|
|
1015
|
+
// only the inline style matters; `inert` reflects to an attribute of its own and
|
|
1016
|
+
// must not re-trigger this observer
|
|
1017
|
+
this.interactivityObserver.observe(container, {
|
|
1018
|
+
attributes: true,
|
|
1019
|
+
attributeFilter: ['style'],
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
this.syncContainerInertness();
|
|
186
1024
|
}
|
|
187
1025
|
/**
|
|
188
1026
|
* allows switching to slotted content
|
|
@@ -202,10 +1040,6 @@ let DeesSimpleLogin = (() => {
|
|
|
202
1040
|
await domtools.convenience.smartdelay.delayFor(300);
|
|
203
1041
|
slotContainerDiv.style.pointerEvents = 'all';
|
|
204
1042
|
}
|
|
205
|
-
constructor() {
|
|
206
|
-
super(...arguments);
|
|
207
|
-
__runInitializers(this, _name_extraInitializers);
|
|
208
|
-
}
|
|
209
1043
|
static {
|
|
210
1044
|
__runInitializers(_classThis, _classExtraInitializers);
|
|
211
1045
|
}
|
|
@@ -213,4 +1047,4 @@ let DeesSimpleLogin = (() => {
|
|
|
213
1047
|
return DeesSimpleLogin = _classThis;
|
|
214
1048
|
})();
|
|
215
1049
|
export { DeesSimpleLogin };
|
|
216
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVlcy1zaW1wbGUtbG9naW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvMDBncm91cC1zaW1wbGUvZGVlcy1zaW1wbGUtbG9naW4vZGVlcy1zaW1wbGUtbG9naW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUV2RCxPQUFPLEVBQ0wsYUFBYSxFQUNiLElBQUksRUFDSixXQUFXLEVBQ1gsUUFBUSxFQUVSLFVBQVUsRUFDVixHQUFHLEdBQ0osTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN0RCxPQUFPLDZDQUE2QyxDQUFDO0lBU3hDLGVBQWU7NEJBRDNCLGFBQWEsQ0FBQyxtQkFBbUIsQ0FBQzs7OztzQkFDRSxXQUFXOzs7OytCQUFuQixTQUFRLFdBQVc7Ozs7Z0NBTTdDLFFBQVEsRUFBRTtZQUNYLGlLQUFTLElBQUksNkJBQUosSUFBSSxtRkFBeUI7WUFQeEMsNktBeUpDOzs7O1FBeEpDLFNBQVM7UUFDRixNQUFNLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQztRQUN2QixNQUFNLENBQUMsVUFBVSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7UUFJdEMscUVBQXdCLGFBQWEsRUFBQztRQUh0QyxXQUFXO1FBR1gsSUFBUyxJQUFJLDBDQUF5QjtRQUF0QyxJQUFTLElBQUksZ0RBQXlCO1FBRS9CLE1BQU0sQ0FBQyxNQUFNLEdBQUc7WUFDckIsa0JBQWtCO1lBQ2xCLFVBQVUsQ0FBQyxhQUFhO1lBQ3hCLEdBQUcsQ0FBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQWtGRjtTQUNGLENBQUM7UUFFSyxNQUFNO1lBQ1gsT0FBTyxJQUFJLENBQUE7Ozs7O3NFQUt1RCxJQUFJLENBQUMsSUFBSTs7Z0NBRS9DLGFBQWE7Ozs7Ozs7Ozs7OztLQVl4QyxDQUFDO1FBQ0osQ0FBQztRQUVNLEtBQUssQ0FBQyxZQUFZLENBQUMsa0JBQTBEO1lBQ2xGLEtBQUssQ0FBQyxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUV2QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVyxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQVEsQ0FBQztZQUNoRSxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNULElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLEtBQWtCLEVBQUUsRUFBRTtvQkFDeEQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxPQUFPLEVBQUU7d0JBQzFDLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTTt3QkFDcEIsT0FBTyxFQUFFLElBQUk7d0JBQ2IsUUFBUSxFQUFFLElBQUk7cUJBQ2YsQ0FBQyxDQUFDLENBQUM7Z0JBQ04sQ0FBQyxDQUFrQixDQUFDLENBQUM7WUFDdkIsQ0FBQztRQUNILENBQUM7UUFFRDs7V0FFRztRQUNJLEtBQUssQ0FBQyxzQkFBc0I7WUFDakMsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDO1lBQzVDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxVQUFXLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBbUIsQ0FBQztZQUM1RSxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxVQUFXLENBQUMsYUFBYSxDQUFDLGlCQUFpQixDQUFtQixDQUFDO1lBQzlGLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFVBQVcsQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLENBQW1CLENBQUM7WUFDNUYsUUFBUSxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDO1lBQzdCLFFBQVEsQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLGtCQUFrQixDQUFDO1lBQzlDLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxhQUFhLEdBQUcsTUFBTSxDQUFDO1lBQy9DLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsa0JBQWtCLENBQUM7WUFDdEQsTUFBTSxRQUFRLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDcEQsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUM7WUFDckMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQztZQUNyRCxNQUFNLFFBQVEsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNwRCxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztRQUMvQyxDQUFDOzs7Ozs7WUF4SlUsdURBQWU7Ozs7O1NBQWYsZUFBZSJ9
|
|
1050
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVlcy1zaW1wbGUtbG9naW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90c193ZWIvZWxlbWVudHMvMDBncm91cC1zaW1wbGUvZGVlcy1zaW1wbGUtbG9naW4vZGVlcy1zaW1wbGUtbG9naW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUV2RCxPQUFPLEVBQ0wsYUFBYSxFQUNiLElBQUksRUFDSixXQUFXLEVBQ1gsUUFBUSxFQUNSLEtBQUssRUFFTCxVQUFVLEVBQ1YsR0FBRyxHQUNKLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDdEQsT0FBTyw2Q0FBNkMsQ0FBQztBQUNyRCxPQUFPLGlEQUFpRCxDQUFDO0FBQ3pELE9BQU8sMkNBQTJDLENBQUM7QUFDbkQsT0FBTyx5REFBeUQsQ0FBQztBQUNqRSxPQUFPLHdEQUF3RCxDQUFDO0FBQ2hFLE9BQU8sOENBQThDLENBQUM7QUErR3RELE1BQU0sb0JBQW9CLEdBQXVCLENBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUVyRjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOEJHO0lBRVUsZUFBZTs0QkFEM0IsYUFBYSxDQUFDLG1CQUFtQixDQUFDOzs7O3NCQUNFLFdBQVc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7K0JBQW5CLFNBQVEsV0FBVzs7OztnQ0FRN0MsUUFBUSxFQUFFO21DQVFWLFFBQVEsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQzswQ0FJM0IsUUFBUSxDQUFDLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDOzRDQU85QixRQUFRLENBQUMsRUFBRSxT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
|