dauth-context-react 6.5.0 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -45,7 +45,8 @@ var initialDauthState = {
45
45
  getPasskeyCredentials: () => Promise.resolve([]),
46
46
  registerPasskey: () => Promise.resolve(null),
47
47
  deletePasskeyCredential: () => Promise.resolve(false),
48
- uploadAvatar: () => Promise.resolve(false)
48
+ uploadAvatar: () => Promise.resolve(false),
49
+ loginWithPasskey: () => Promise.resolve(false)
49
50
  };
50
51
  var initialDauthState_default = initialDauthState;
51
52
 
@@ -153,45 +154,59 @@ async function deleteAccountAPI(basePath) {
153
154
  return { response, data };
154
155
  }
155
156
  async function getPasskeyCredentialsAPI(basePath) {
156
- const response = await fetch(
157
- `${basePath}/passkey/credentials`,
158
- {
159
- method: "GET",
160
- headers: { "X-CSRF-Token": getCsrfToken() },
161
- credentials: "include"
162
- }
163
- );
157
+ const response = await fetch(`${basePath}/passkey/credentials`, {
158
+ method: "GET",
159
+ headers: { "X-CSRF-Token": getCsrfToken() },
160
+ credentials: "include"
161
+ });
164
162
  const data = await response.json();
165
163
  return { response, data };
166
164
  }
167
165
  async function startPasskeyRegistrationAPI(basePath) {
168
- const response = await fetch(
169
- `${basePath}/passkey/register/start`,
170
- {
171
- method: "POST",
172
- headers: {
173
- "Content-Type": "application/json",
174
- "X-CSRF-Token": getCsrfToken()
175
- },
176
- credentials: "include"
177
- }
178
- );
166
+ const response = await fetch(`${basePath}/passkey/register/start`, {
167
+ method: "POST",
168
+ headers: {
169
+ "Content-Type": "application/json",
170
+ "X-CSRF-Token": getCsrfToken()
171
+ },
172
+ credentials: "include"
173
+ });
179
174
  const data = await response.json();
180
175
  return { response, data };
181
176
  }
182
177
  async function finishPasskeyRegistrationAPI(basePath, body) {
183
- const response = await fetch(
184
- `${basePath}/passkey/register/finish`,
185
- {
186
- method: "POST",
187
- headers: {
188
- "Content-Type": "application/json",
189
- "X-CSRF-Token": getCsrfToken()
190
- },
191
- credentials: "include",
192
- body: JSON.stringify(body)
193
- }
194
- );
178
+ const response = await fetch(`${basePath}/passkey/register/finish`, {
179
+ method: "POST",
180
+ headers: {
181
+ "Content-Type": "application/json",
182
+ "X-CSRF-Token": getCsrfToken()
183
+ },
184
+ credentials: "include",
185
+ body: JSON.stringify(body)
186
+ });
187
+ const data = await response.json();
188
+ return { response, data };
189
+ }
190
+ async function startPasskeyAuthAPI(basePath) {
191
+ const response = await fetch(`${basePath}/passkey/auth-start`, {
192
+ method: "POST",
193
+ headers: {
194
+ "Content-Type": "application/json"
195
+ },
196
+ credentials: "include"
197
+ });
198
+ const data = await response.json();
199
+ return { response, data };
200
+ }
201
+ async function finishPasskeyAuthAPI(basePath, body) {
202
+ const response = await fetch(`${basePath}/passkey/auth-finish`, {
203
+ method: "POST",
204
+ headers: {
205
+ "Content-Type": "application/json"
206
+ },
207
+ credentials: "include",
208
+ body: JSON.stringify(body)
209
+ });
195
210
  const data = await response.json();
196
211
  return { response, data };
197
212
  }
@@ -243,17 +258,16 @@ function bufferToBase64url(buffer) {
243
258
  async function createPasskeyCredential(options) {
244
259
  const publicKey = {
245
260
  ...options,
261
+ rp: { ...options.rp, id: window.location.hostname },
246
262
  challenge: base64urlToBuffer(options.challenge),
247
263
  user: {
248
264
  ...options.user,
249
265
  id: base64urlToBuffer(options.user.id)
250
266
  },
251
- excludeCredentials: (options.excludeCredentials ?? []).map(
252
- (c) => ({
253
- ...c,
254
- id: base64urlToBuffer(c.id)
255
- })
256
- )
267
+ excludeCredentials: (options.excludeCredentials ?? []).map((c) => ({
268
+ ...c,
269
+ id: base64urlToBuffer(c.id)
270
+ }))
257
271
  };
258
272
  const credential = await navigator.credentials.create({
259
273
  publicKey
@@ -267,20 +281,14 @@ async function createPasskeyCredential(options) {
267
281
  rawId: bufferToBase64url(credential.rawId),
268
282
  type: credential.type,
269
283
  response: {
270
- clientDataJSON: bufferToBase64url(
271
- attestation.clientDataJSON
272
- ),
273
- attestationObject: bufferToBase64url(
274
- attestation.attestationObject
275
- ),
284
+ clientDataJSON: bufferToBase64url(attestation.clientDataJSON),
285
+ attestationObject: bufferToBase64url(attestation.attestationObject),
276
286
  ...attestation.getTransports ? { transports: attestation.getTransports() } : {},
277
287
  ...attestation.getPublicKeyAlgorithm ? {
278
288
  publicKeyAlgorithm: attestation.getPublicKeyAlgorithm()
279
289
  } : {},
280
290
  ...attestation.getPublicKey ? {
281
- publicKey: bufferToBase64url(
282
- attestation.getPublicKey()
283
- )
291
+ publicKey: bufferToBase64url(attestation.getPublicKey())
284
292
  } : {},
285
293
  ...attestation.getAuthenticatorData ? {
286
294
  authenticatorData: bufferToBase64url(
@@ -292,6 +300,38 @@ async function createPasskeyCredential(options) {
292
300
  authenticatorAttachment: credential.authenticatorAttachment ?? void 0
293
301
  };
294
302
  }
303
+ async function getPasskeyCredential(options) {
304
+ const publicKey = {
305
+ challenge: base64urlToBuffer(options.challenge),
306
+ timeout: options.timeout,
307
+ rpId: window.location.hostname,
308
+ userVerification: options.userVerification || "preferred",
309
+ allowCredentials: (options.allowCredentials || []).map(
310
+ (c) => ({
311
+ ...c,
312
+ id: base64urlToBuffer(c.id)
313
+ })
314
+ )
315
+ };
316
+ const credential = await navigator.credentials.get({
317
+ publicKey
318
+ });
319
+ if (!credential) throw new Error("No credential returned");
320
+ const assertion = credential.response;
321
+ return {
322
+ id: credential.id,
323
+ rawId: bufferToBase64url(credential.rawId),
324
+ type: credential.type,
325
+ response: {
326
+ clientDataJSON: bufferToBase64url(assertion.clientDataJSON),
327
+ authenticatorData: bufferToBase64url(assertion.authenticatorData),
328
+ signature: bufferToBase64url(assertion.signature),
329
+ userHandle: assertion.userHandle ? bufferToBase64url(assertion.userHandle) : null
330
+ },
331
+ clientExtensionResults: credential.getClientExtensionResults(),
332
+ authenticatorAttachment: credential.authenticatorAttachment
333
+ };
334
+ }
295
335
 
296
336
  // src/reducer/dauth.actions.ts
297
337
  async function exchangeCodeAction(ctx, code) {
@@ -438,19 +478,15 @@ async function registerPasskeyAction(ctx, name) {
438
478
  onError(new Error("Failed to start passkey registration"));
439
479
  return null;
440
480
  }
441
- const credential = await createPasskeyCredential(
442
- startResult.data
443
- );
444
- const finishResult = await finishPasskeyRegistrationAPI(
445
- authProxyPath,
446
- { credential, name }
447
- );
481
+ const credential = await createPasskeyCredential(startResult.data);
482
+ const finishResult = await finishPasskeyRegistrationAPI(authProxyPath, {
483
+ credential,
484
+ name
485
+ });
448
486
  if (finishResult.response.status === 200 || finishResult.response.status === 201) {
449
487
  return finishResult.data.credential;
450
488
  }
451
- onError(
452
- new Error("Failed to finish passkey registration")
453
- );
489
+ onError(new Error("Failed to finish passkey registration"));
454
490
  return null;
455
491
  } catch (error) {
456
492
  onError(
@@ -468,9 +504,7 @@ async function deletePasskeyCredentialAction(ctx, credentialId) {
468
504
  );
469
505
  return result.response.status === 200;
470
506
  } catch (error) {
471
- onError(
472
- error instanceof Error ? error : new Error("Delete passkey error")
473
- );
507
+ onError(error instanceof Error ? error : new Error("Delete passkey error"));
474
508
  return false;
475
509
  }
476
510
  }
@@ -485,16 +519,69 @@ async function uploadAvatarAction(ctx, file) {
485
519
  });
486
520
  return true;
487
521
  }
488
- onError(
489
- new Error(
490
- "Avatar upload error: " + result.data.message
491
- )
522
+ onError(new Error("Avatar upload error: " + result.data.message));
523
+ return false;
524
+ } catch (error) {
525
+ onError(error instanceof Error ? error : new Error("Avatar upload error"));
526
+ return false;
527
+ }
528
+ }
529
+ async function loginWithPasskeyAction(ctx) {
530
+ const { dispatch, authProxyPath, onError } = ctx;
531
+ dispatch({
532
+ type: SET_IS_LOADING,
533
+ payload: { isLoading: true }
534
+ });
535
+ try {
536
+ const startResult = await startPasskeyAuthAPI(authProxyPath);
537
+ if (startResult.data.status !== "success" || !startResult.data.options) {
538
+ dispatch({
539
+ type: SET_IS_LOADING,
540
+ payload: { isLoading: false }
541
+ });
542
+ return false;
543
+ }
544
+ const credential = await getPasskeyCredential(
545
+ startResult.data.options
492
546
  );
547
+ const finishResult = await finishPasskeyAuthAPI(authProxyPath, {
548
+ credential,
549
+ sessionId: startResult.data.sessionId
550
+ });
551
+ if (finishResult.data.status === "login-success" && finishResult.data.redirect) {
552
+ const code = new URL(finishResult.data.redirect).searchParams.get("code");
553
+ if (code) {
554
+ const exchangeResult = await exchangeCodeAPI(authProxyPath, code);
555
+ if (exchangeResult.response.status === 200) {
556
+ dispatch({
557
+ type: LOGIN,
558
+ payload: {
559
+ user: exchangeResult.data.user,
560
+ domain: exchangeResult.data.domain,
561
+ isAuthenticated: true
562
+ }
563
+ });
564
+ dispatch({
565
+ type: SET_IS_LOADING,
566
+ payload: { isLoading: false }
567
+ });
568
+ return true;
569
+ }
570
+ }
571
+ }
572
+ dispatch({
573
+ type: SET_IS_LOADING,
574
+ payload: { isLoading: false }
575
+ });
493
576
  return false;
494
577
  } catch (error) {
495
578
  onError(
496
- error instanceof Error ? error : new Error("Avatar upload error")
579
+ error instanceof Error ? error : new Error("Passkey authentication error")
497
580
  );
581
+ dispatch({
582
+ type: SET_IS_LOADING,
583
+ payload: { isLoading: false }
584
+ });
498
585
  return false;
499
586
  }
500
587
  }
@@ -518,13 +605,7 @@ function setDauthUrl(url) {
518
605
  function checkIsLocalhost() {
519
606
  if (typeof window === "undefined") return false;
520
607
  const hostname = window.location.hostname;
521
- return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
522
- hostname
523
- ) || /^192\.168(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){2}$/.test(
524
- hostname
525
- ) || /^10(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
526
- hostname
527
- );
608
+ return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(hostname) || /^192\.168(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){2}$/.test(hostname) || /^10(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(hostname);
528
609
  }
529
610
  function getClientBasePath() {
530
611
  if (_dauthUrl) return _dauthUrl;
@@ -717,10 +798,7 @@ function useModalAnimation(open) {
717
798
  }
718
799
  if (phase === "entered" || phase === "entering") {
719
800
  setPhase("exiting");
720
- const timer = setTimeout(
721
- () => setPhase("exited"),
722
- MOBILE_TRANSITION_MS
723
- );
801
+ const timer = setTimeout(() => setPhase("exited"), MOBILE_TRANSITION_MS);
724
802
  return () => clearTimeout(timer);
725
803
  }
726
804
  return void 0;
@@ -870,18 +948,12 @@ function DauthProfileModal({
870
948
  }, [activeTab, showSecurity, getPasskeyCredentials]);
871
949
  (0, import_react.useEffect)(() => {
872
950
  if (status?.type !== "success") return;
873
- const timer = setTimeout(
874
- () => setStatus(null),
875
- SUCCESS_TIMEOUT_MS
876
- );
951
+ const timer = setTimeout(() => setStatus(null), SUCCESS_TIMEOUT_MS);
877
952
  return () => clearTimeout(timer);
878
953
  }, [status]);
879
954
  (0, import_react.useEffect)(() => {
880
955
  if (passkeyStatus?.type !== "success") return;
881
- const timer = setTimeout(
882
- () => setPasskeyStatus(null),
883
- SUCCESS_TIMEOUT_MS
884
- );
956
+ const timer = setTimeout(() => setPasskeyStatus(null), SUCCESS_TIMEOUT_MS);
885
957
  return () => clearTimeout(timer);
886
958
  }, [passkeyStatus]);
887
959
  useFocusTrap(modalRef, phase === "entered", onClose);
@@ -921,12 +993,9 @@ function DauthProfileModal({
921
993
  if (hasField("lastname")) fields.lastname = lastname;
922
994
  if (hasField("nickname")) fields.nickname = nickname;
923
995
  if (hasField("country")) fields.country = country;
924
- if (hasField("tel_prefix"))
925
- fields.telPrefix = telPrefix;
926
- if (hasField("tel_suffix"))
927
- fields.telSuffix = telSuffix;
928
- if (hasField("birth_date") && birthDate)
929
- fields.birthDate = birthDate;
996
+ if (hasField("tel_prefix")) fields.telPrefix = telPrefix;
997
+ if (hasField("tel_suffix")) fields.telSuffix = telSuffix;
998
+ if (hasField("birth_date") && birthDate) fields.birthDate = birthDate;
930
999
  if ((domain.customFields ?? []).length > 0)
931
1000
  fields.customFields = customFieldValues;
932
1001
  const ok = await updateUser(fields);
@@ -979,9 +1048,7 @@ function DauthProfileModal({
979
1048
  const handleRegisterPasskey = (0, import_react.useCallback)(async () => {
980
1049
  setRegistering(true);
981
1050
  setPasskeyStatus(null);
982
- const cred = await registerPasskey(
983
- passkeyName || void 0
984
- );
1051
+ const cred = await registerPasskey(passkeyName || void 0);
985
1052
  setRegistering(false);
986
1053
  if (cred) {
987
1054
  setCredentials((prev) => [...prev, cred]);
@@ -1002,9 +1069,7 @@ function DauthProfileModal({
1002
1069
  async (credentialId) => {
1003
1070
  const ok = await deletePasskeyCredential(credentialId);
1004
1071
  if (ok) {
1005
- setCredentials(
1006
- (prev) => prev.filter((c) => c._id !== credentialId)
1007
- );
1072
+ setCredentials((prev) => prev.filter((c) => c._id !== credentialId));
1008
1073
  }
1009
1074
  },
1010
1075
  [deletePasskeyCredential]
@@ -1044,15 +1109,11 @@ function DauthProfileModal({
1044
1109
  if (!t) return {};
1045
1110
  const vars = {};
1046
1111
  if (t.accent) vars["--dauth-accent"] = t.accent;
1047
- if (t.accentHover)
1048
- vars["--dauth-accent-hover"] = t.accentHover;
1112
+ if (t.accentHover) vars["--dauth-accent-hover"] = t.accentHover;
1049
1113
  if (t.surface) vars["--dauth-surface"] = t.surface;
1050
- if (t.surfaceHover)
1051
- vars["--dauth-surface-hover"] = t.surfaceHover;
1052
- if (t.textPrimary)
1053
- vars["--dauth-text-primary"] = t.textPrimary;
1054
- if (t.textSecondary)
1055
- vars["--dauth-text-secondary"] = t.textSecondary;
1114
+ if (t.surfaceHover) vars["--dauth-surface-hover"] = t.surfaceHover;
1115
+ if (t.textPrimary) vars["--dauth-text-primary"] = t.textPrimary;
1116
+ if (t.textSecondary) vars["--dauth-text-secondary"] = t.textSecondary;
1056
1117
  if (t.border) vars["--dauth-border"] = t.border;
1057
1118
  return vars;
1058
1119
  }, [domain.modalTheme]);
@@ -1219,14 +1280,7 @@ function DauthProfileModal({
1219
1280
  ),
1220
1281
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1221
1282
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1222
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1223
- "label",
1224
- {
1225
- htmlFor: "dauth-name",
1226
- style: label,
1227
- children: "Name *"
1228
- }
1229
- ),
1283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
1230
1284
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1231
1285
  "input",
1232
1286
  {
@@ -1243,17 +1297,10 @@ function DauthProfileModal({
1243
1297
  )
1244
1298
  ] }),
1245
1299
  hasField("lastname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1246
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1247
- "label",
1248
- {
1249
- htmlFor: "dauth-lastname",
1250
- style: label,
1251
- children: [
1252
- "Last name",
1253
- isRequired("lastname") ? " *" : ""
1254
- ]
1255
- }
1256
- ),
1300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-lastname", style: label, children: [
1301
+ "Last name",
1302
+ isRequired("lastname") ? " *" : ""
1303
+ ] }),
1257
1304
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1258
1305
  "input",
1259
1306
  {
@@ -1270,17 +1317,10 @@ function DauthProfileModal({
1270
1317
  )
1271
1318
  ] }),
1272
1319
  hasField("nickname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1273
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1274
- "label",
1275
- {
1276
- htmlFor: "dauth-nickname",
1277
- style: label,
1278
- children: [
1279
- "Nickname",
1280
- isRequired("nickname") ? " *" : ""
1281
- ]
1282
- }
1283
- ),
1320
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-nickname", style: label, children: [
1321
+ "Nickname",
1322
+ isRequired("nickname") ? " *" : ""
1323
+ ] }),
1284
1324
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1285
1325
  "input",
1286
1326
  {
@@ -1297,17 +1337,10 @@ function DauthProfileModal({
1297
1337
  )
1298
1338
  ] }),
1299
1339
  hasField("country") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1300
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1301
- "label",
1302
- {
1303
- htmlFor: "dauth-country",
1304
- style: label,
1305
- children: [
1306
- "Country",
1307
- isRequired("country") ? " *" : ""
1308
- ]
1309
- }
1310
- ),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-country", style: label, children: [
1341
+ "Country",
1342
+ isRequired("country") ? " *" : ""
1343
+ ] }),
1311
1344
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1312
1345
  "input",
1313
1346
  {
@@ -1378,17 +1411,10 @@ function DauthProfileModal({
1378
1411
  )
1379
1412
  ] }),
1380
1413
  hasField("birth_date") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1381
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1382
- "label",
1383
- {
1384
- htmlFor: "dauth-birthdate",
1385
- style: label,
1386
- children: [
1387
- "Birth date",
1388
- isRequired("birth_date") ? " *" : ""
1389
- ]
1390
- }
1391
- ),
1414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-birthdate", style: label, children: [
1415
+ "Birth date",
1416
+ isRequired("birth_date") ? " *" : ""
1417
+ ] }),
1392
1418
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1393
1419
  "input",
1394
1420
  {
@@ -1405,44 +1431,28 @@ function DauthProfileModal({
1405
1431
  ] }),
1406
1432
  (domain.customFields ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1407
1433
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
1408
- domain.customFields.map((cf) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1409
- "div",
1410
- {
1411
- style: fieldGroup,
1412
- children: [
1413
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1414
- "label",
1415
- {
1416
- htmlFor: `dauth-cf-${cf.key}`,
1417
- style: label,
1418
- children: [
1419
- cf.label,
1420
- cf.required ? " *" : ""
1421
- ]
1422
- }
1423
- ),
1424
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1425
- "input",
1426
- {
1427
- id: `dauth-cf-${cf.key}`,
1428
- type: "text",
1429
- value: customFieldValues[cf.key] ?? "",
1430
- onChange: (e) => setCustomFieldValues(
1431
- (prev) => ({
1432
- ...prev,
1433
- [cf.key]: e.target.value
1434
- })
1435
- ),
1436
- disabled: saving,
1437
- style: input,
1438
- onFocus: inputFocusHandler,
1439
- onBlur: inputBlurHandler
1440
- }
1441
- )
1442
- ]
1443
- },
1444
- cf.key
1445
- ))
1434
+ domain.customFields.map((cf) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1435
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: `dauth-cf-${cf.key}`, style: label, children: [
1436
+ cf.label,
1437
+ cf.required ? " *" : ""
1438
+ ] }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1440
+ "input",
1441
+ {
1442
+ id: `dauth-cf-${cf.key}`,
1443
+ type: "text",
1444
+ value: customFieldValues[cf.key] ?? "",
1445
+ onChange: (e) => setCustomFieldValues((prev) => ({
1446
+ ...prev,
1447
+ [cf.key]: e.target.value
1448
+ })),
1449
+ disabled: saving,
1450
+ style: input,
1451
+ onFocus: inputFocusHandler,
1452
+ onBlur: inputBlurHandler
1453
+ }
1454
+ )
1455
+ ] }, cf.key))
1446
1456
  ] })
1447
1457
  ] }),
1448
1458
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
@@ -1502,14 +1512,7 @@ function DauthProfileModal({
1502
1512
  ),
1503
1513
  showRegister && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: registerPanel, children: [
1504
1514
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1505
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1506
- "label",
1507
- {
1508
- htmlFor: "dauth-passkey-name",
1509
- style: label,
1510
- children: "Passkey name (optional)"
1511
- }
1512
- ),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-passkey-name", style: label, children: "Passkey name (optional)" }),
1513
1516
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1514
1517
  "input",
1515
1518
  {
@@ -1585,89 +1588,82 @@ function DauthProfileModal({
1585
1588
  },
1586
1589
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})
1587
1590
  }
1588
- ) : credentials.length > 0 ? credentials.map((cred) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1589
- "div",
1590
- {
1591
- style: credentialRow,
1592
- children: [
1593
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1594
- "div",
1595
- {
1596
- style: {
1597
- display: "flex",
1598
- alignItems: "center",
1599
- gap: 12,
1600
- flex: 1,
1601
- minWidth: 0
1602
- },
1603
- children: [
1604
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1605
- "span",
1606
- {
1607
- style: {
1608
- color: "var(--dauth-accent, #6366f1)",
1609
- flexShrink: 0
1610
- },
1611
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFingerprint, {})
1612
- }
1613
- ),
1614
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1615
- "div",
1616
- {
1617
- style: {
1618
- minWidth: 0,
1619
- flex: 1
1620
- },
1621
- children: [
1622
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1623
- "div",
1624
- {
1625
- style: {
1626
- fontSize: "var(--dauth-font-size-sm, 0.875rem)",
1627
- fontWeight: 500,
1628
- color: "var(--dauth-text-primary, #e4e4e7)",
1629
- overflow: "hidden",
1630
- textOverflow: "ellipsis",
1631
- whiteSpace: "nowrap"
1632
- },
1633
- children: cred.name || "Passkey"
1634
- }
1635
- ),
1636
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1637
- "div",
1638
- {
1639
- style: {
1640
- fontSize: "var(--dauth-font-size-xs, 0.75rem)",
1641
- color: "var(--dauth-text-muted, #71717a)"
1642
- },
1643
- children: [
1644
- cred.deviceType === "multiDevice" ? "Synced" : "Device-bound",
1645
- cred.createdAt && ` \xB7 Created ${new Date(cred.createdAt).toLocaleDateString()}`
1646
- ]
1647
- }
1648
- )
1649
- ]
1650
- }
1651
- )
1652
- ]
1653
- }
1654
- ),
1655
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1656
- "button",
1657
- {
1658
- type: "button",
1659
- onClick: () => handleDeletePasskey(cred._id),
1660
- style: trashBtn,
1661
- onMouseEnter: (e) => e.currentTarget.style.color = "var(--dauth-error, #ef4444)",
1662
- onMouseLeave: (e) => e.currentTarget.style.color = "var(--dauth-text-muted, #71717a)",
1663
- "aria-label": `Delete passkey ${cred.name || ""}`,
1664
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconTrash, {})
1665
- }
1666
- )
1667
- ]
1668
- },
1669
- cred._id
1670
- )) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: emptyState, children: [
1591
+ ) : credentials.length > 0 ? credentials.map((cred) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: credentialRow, children: [
1592
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1593
+ "div",
1594
+ {
1595
+ style: {
1596
+ display: "flex",
1597
+ alignItems: "center",
1598
+ gap: 12,
1599
+ flex: 1,
1600
+ minWidth: 0
1601
+ },
1602
+ children: [
1603
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1604
+ "span",
1605
+ {
1606
+ style: {
1607
+ color: "var(--dauth-accent, #6366f1)",
1608
+ flexShrink: 0
1609
+ },
1610
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFingerprint, {})
1611
+ }
1612
+ ),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1614
+ "div",
1615
+ {
1616
+ style: {
1617
+ minWidth: 0,
1618
+ flex: 1
1619
+ },
1620
+ children: [
1621
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1622
+ "div",
1623
+ {
1624
+ style: {
1625
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
1626
+ fontWeight: 500,
1627
+ color: "var(--dauth-text-primary, #e4e4e7)",
1628
+ overflow: "hidden",
1629
+ textOverflow: "ellipsis",
1630
+ whiteSpace: "nowrap"
1631
+ },
1632
+ children: cred.name || "Passkey"
1633
+ }
1634
+ ),
1635
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1636
+ "div",
1637
+ {
1638
+ style: {
1639
+ fontSize: "var(--dauth-font-size-xs, 0.75rem)",
1640
+ color: "var(--dauth-text-muted, #71717a)"
1641
+ },
1642
+ children: [
1643
+ cred.deviceType === "multiDevice" ? "Synced" : "Device-bound",
1644
+ cred.createdAt && ` \xB7 Created ${new Date(cred.createdAt).toLocaleDateString()}`
1645
+ ]
1646
+ }
1647
+ )
1648
+ ]
1649
+ }
1650
+ )
1651
+ ]
1652
+ }
1653
+ ),
1654
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1655
+ "button",
1656
+ {
1657
+ type: "button",
1658
+ onClick: () => handleDeletePasskey(cred._id),
1659
+ style: trashBtn,
1660
+ onMouseEnter: (e) => e.currentTarget.style.color = "var(--dauth-error, #ef4444)",
1661
+ onMouseLeave: (e) => e.currentTarget.style.color = "var(--dauth-text-muted, #71717a)",
1662
+ "aria-label": `Delete passkey ${cred.name || ""}`,
1663
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconTrash, {})
1664
+ }
1665
+ )
1666
+ ] }, cred._id)) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: emptyState, children: [
1671
1667
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1672
1668
  "span",
1673
1669
  {
@@ -2275,6 +2271,10 @@ var DauthProvider = (props) => {
2275
2271
  (file) => uploadAvatarAction(ctx, file),
2276
2272
  [ctx]
2277
2273
  );
2274
+ const loginWithPasskey = (0, import_react2.useCallback)(
2275
+ () => loginWithPasskeyAction(ctx),
2276
+ [ctx]
2277
+ );
2278
2278
  const memoProvider = (0, import_react2.useMemo)(
2279
2279
  () => ({
2280
2280
  ...dauthState,
@@ -2285,7 +2285,8 @@ var DauthProvider = (props) => {
2285
2285
  getPasskeyCredentials,
2286
2286
  registerPasskey,
2287
2287
  deletePasskeyCredential,
2288
- uploadAvatar
2288
+ uploadAvatar,
2289
+ loginWithPasskey
2289
2290
  }),
2290
2291
  [
2291
2292
  dauthState,
@@ -2296,7 +2297,8 @@ var DauthProvider = (props) => {
2296
2297
  getPasskeyCredentials,
2297
2298
  registerPasskey,
2298
2299
  deletePasskeyCredential,
2299
- uploadAvatar
2300
+ uploadAvatar,
2301
+ loginWithPasskey
2300
2302
  ]
2301
2303
  );
2302
2304
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DauthContext.Provider, { value: memoProvider, children });