dauth-context-react 6.4.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
@@ -30,7 +30,8 @@ var import_react2 = require("react");
30
30
  // src/initialDauthState.ts
31
31
  var initialDauthState = {
32
32
  user: {
33
- language: (typeof window !== "undefined" ? window.document.documentElement.getAttribute("lang") : null) || "es"
33
+ language: (typeof window !== "undefined" ? window.document.documentElement.getAttribute("lang") : null) || "es",
34
+ theme: "system"
34
35
  },
35
36
  domain: {},
36
37
  isLoading: true,
@@ -44,7 +45,8 @@ var initialDauthState = {
44
45
  getPasskeyCredentials: () => Promise.resolve([]),
45
46
  registerPasskey: () => Promise.resolve(null),
46
47
  deletePasskeyCredential: () => Promise.resolve(false),
47
- uploadAvatar: () => Promise.resolve(false)
48
+ uploadAvatar: () => Promise.resolve(false),
49
+ loginWithPasskey: () => Promise.resolve(false)
48
50
  };
49
51
  var initialDauthState_default = initialDauthState;
50
52
 
@@ -152,45 +154,59 @@ async function deleteAccountAPI(basePath) {
152
154
  return { response, data };
153
155
  }
154
156
  async function getPasskeyCredentialsAPI(basePath) {
155
- const response = await fetch(
156
- `${basePath}/passkey/credentials`,
157
- {
158
- method: "GET",
159
- headers: { "X-CSRF-Token": getCsrfToken() },
160
- credentials: "include"
161
- }
162
- );
157
+ const response = await fetch(`${basePath}/passkey/credentials`, {
158
+ method: "GET",
159
+ headers: { "X-CSRF-Token": getCsrfToken() },
160
+ credentials: "include"
161
+ });
163
162
  const data = await response.json();
164
163
  return { response, data };
165
164
  }
166
165
  async function startPasskeyRegistrationAPI(basePath) {
167
- const response = await fetch(
168
- `${basePath}/passkey/register/start`,
169
- {
170
- method: "POST",
171
- headers: {
172
- "Content-Type": "application/json",
173
- "X-CSRF-Token": getCsrfToken()
174
- },
175
- credentials: "include"
176
- }
177
- );
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
+ });
178
174
  const data = await response.json();
179
175
  return { response, data };
180
176
  }
181
177
  async function finishPasskeyRegistrationAPI(basePath, body) {
182
- const response = await fetch(
183
- `${basePath}/passkey/register/finish`,
184
- {
185
- method: "POST",
186
- headers: {
187
- "Content-Type": "application/json",
188
- "X-CSRF-Token": getCsrfToken()
189
- },
190
- credentials: "include",
191
- body: JSON.stringify(body)
192
- }
193
- );
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
+ });
194
210
  const data = await response.json();
195
211
  return { response, data };
196
212
  }
@@ -242,17 +258,16 @@ function bufferToBase64url(buffer) {
242
258
  async function createPasskeyCredential(options) {
243
259
  const publicKey = {
244
260
  ...options,
261
+ rp: { ...options.rp, id: window.location.hostname },
245
262
  challenge: base64urlToBuffer(options.challenge),
246
263
  user: {
247
264
  ...options.user,
248
265
  id: base64urlToBuffer(options.user.id)
249
266
  },
250
- excludeCredentials: (options.excludeCredentials ?? []).map(
251
- (c) => ({
252
- ...c,
253
- id: base64urlToBuffer(c.id)
254
- })
255
- )
267
+ excludeCredentials: (options.excludeCredentials ?? []).map((c) => ({
268
+ ...c,
269
+ id: base64urlToBuffer(c.id)
270
+ }))
256
271
  };
257
272
  const credential = await navigator.credentials.create({
258
273
  publicKey
@@ -266,20 +281,14 @@ async function createPasskeyCredential(options) {
266
281
  rawId: bufferToBase64url(credential.rawId),
267
282
  type: credential.type,
268
283
  response: {
269
- clientDataJSON: bufferToBase64url(
270
- attestation.clientDataJSON
271
- ),
272
- attestationObject: bufferToBase64url(
273
- attestation.attestationObject
274
- ),
284
+ clientDataJSON: bufferToBase64url(attestation.clientDataJSON),
285
+ attestationObject: bufferToBase64url(attestation.attestationObject),
275
286
  ...attestation.getTransports ? { transports: attestation.getTransports() } : {},
276
287
  ...attestation.getPublicKeyAlgorithm ? {
277
288
  publicKeyAlgorithm: attestation.getPublicKeyAlgorithm()
278
289
  } : {},
279
290
  ...attestation.getPublicKey ? {
280
- publicKey: bufferToBase64url(
281
- attestation.getPublicKey()
282
- )
291
+ publicKey: bufferToBase64url(attestation.getPublicKey())
283
292
  } : {},
284
293
  ...attestation.getAuthenticatorData ? {
285
294
  authenticatorData: bufferToBase64url(
@@ -291,6 +300,38 @@ async function createPasskeyCredential(options) {
291
300
  authenticatorAttachment: credential.authenticatorAttachment ?? void 0
292
301
  };
293
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
+ }
294
335
 
295
336
  // src/reducer/dauth.actions.ts
296
337
  async function exchangeCodeAction(ctx, code) {
@@ -437,19 +478,15 @@ async function registerPasskeyAction(ctx, name) {
437
478
  onError(new Error("Failed to start passkey registration"));
438
479
  return null;
439
480
  }
440
- const credential = await createPasskeyCredential(
441
- startResult.data
442
- );
443
- const finishResult = await finishPasskeyRegistrationAPI(
444
- authProxyPath,
445
- { credential, name }
446
- );
481
+ const credential = await createPasskeyCredential(startResult.data);
482
+ const finishResult = await finishPasskeyRegistrationAPI(authProxyPath, {
483
+ credential,
484
+ name
485
+ });
447
486
  if (finishResult.response.status === 200 || finishResult.response.status === 201) {
448
487
  return finishResult.data.credential;
449
488
  }
450
- onError(
451
- new Error("Failed to finish passkey registration")
452
- );
489
+ onError(new Error("Failed to finish passkey registration"));
453
490
  return null;
454
491
  } catch (error) {
455
492
  onError(
@@ -467,9 +504,7 @@ async function deletePasskeyCredentialAction(ctx, credentialId) {
467
504
  );
468
505
  return result.response.status === 200;
469
506
  } catch (error) {
470
- onError(
471
- error instanceof Error ? error : new Error("Delete passkey error")
472
- );
507
+ onError(error instanceof Error ? error : new Error("Delete passkey error"));
473
508
  return false;
474
509
  }
475
510
  }
@@ -484,16 +519,69 @@ async function uploadAvatarAction(ctx, file) {
484
519
  });
485
520
  return true;
486
521
  }
487
- onError(
488
- new Error(
489
- "Avatar upload error: " + result.data.message
490
- )
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
491
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
+ });
492
576
  return false;
493
577
  } catch (error) {
494
578
  onError(
495
- error instanceof Error ? error : new Error("Avatar upload error")
579
+ error instanceof Error ? error : new Error("Passkey authentication error")
496
580
  );
581
+ dispatch({
582
+ type: SET_IS_LOADING,
583
+ payload: { isLoading: false }
584
+ });
497
585
  return false;
498
586
  }
499
587
  }
@@ -517,13 +605,7 @@ function setDauthUrl(url) {
517
605
  function checkIsLocalhost() {
518
606
  if (typeof window === "undefined") return false;
519
607
  const hostname = window.location.hostname;
520
- return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
521
- hostname
522
- ) || /^192\.168(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){2}$/.test(
523
- hostname
524
- ) || /^10(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
525
- hostname
526
- );
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);
527
609
  }
528
610
  function getClientBasePath() {
529
611
  if (_dauthUrl) return _dauthUrl;
@@ -716,10 +798,7 @@ function useModalAnimation(open) {
716
798
  }
717
799
  if (phase === "entered" || phase === "entering") {
718
800
  setPhase("exiting");
719
- const timer = setTimeout(
720
- () => setPhase("exited"),
721
- MOBILE_TRANSITION_MS
722
- );
801
+ const timer = setTimeout(() => setPhase("exited"), MOBILE_TRANSITION_MS);
723
802
  return () => clearTimeout(timer);
724
803
  }
725
804
  return void 0;
@@ -869,18 +948,12 @@ function DauthProfileModal({
869
948
  }, [activeTab, showSecurity, getPasskeyCredentials]);
870
949
  (0, import_react.useEffect)(() => {
871
950
  if (status?.type !== "success") return;
872
- const timer = setTimeout(
873
- () => setStatus(null),
874
- SUCCESS_TIMEOUT_MS
875
- );
951
+ const timer = setTimeout(() => setStatus(null), SUCCESS_TIMEOUT_MS);
876
952
  return () => clearTimeout(timer);
877
953
  }, [status]);
878
954
  (0, import_react.useEffect)(() => {
879
955
  if (passkeyStatus?.type !== "success") return;
880
- const timer = setTimeout(
881
- () => setPasskeyStatus(null),
882
- SUCCESS_TIMEOUT_MS
883
- );
956
+ const timer = setTimeout(() => setPasskeyStatus(null), SUCCESS_TIMEOUT_MS);
884
957
  return () => clearTimeout(timer);
885
958
  }, [passkeyStatus]);
886
959
  useFocusTrap(modalRef, phase === "entered", onClose);
@@ -920,12 +993,9 @@ function DauthProfileModal({
920
993
  if (hasField("lastname")) fields.lastname = lastname;
921
994
  if (hasField("nickname")) fields.nickname = nickname;
922
995
  if (hasField("country")) fields.country = country;
923
- if (hasField("tel_prefix"))
924
- fields.telPrefix = telPrefix;
925
- if (hasField("tel_suffix"))
926
- fields.telSuffix = telSuffix;
927
- if (hasField("birth_date") && birthDate)
928
- 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;
929
999
  if ((domain.customFields ?? []).length > 0)
930
1000
  fields.customFields = customFieldValues;
931
1001
  const ok = await updateUser(fields);
@@ -978,9 +1048,7 @@ function DauthProfileModal({
978
1048
  const handleRegisterPasskey = (0, import_react.useCallback)(async () => {
979
1049
  setRegistering(true);
980
1050
  setPasskeyStatus(null);
981
- const cred = await registerPasskey(
982
- passkeyName || void 0
983
- );
1051
+ const cred = await registerPasskey(passkeyName || void 0);
984
1052
  setRegistering(false);
985
1053
  if (cred) {
986
1054
  setCredentials((prev) => [...prev, cred]);
@@ -1001,9 +1069,7 @@ function DauthProfileModal({
1001
1069
  async (credentialId) => {
1002
1070
  const ok = await deletePasskeyCredential(credentialId);
1003
1071
  if (ok) {
1004
- setCredentials(
1005
- (prev) => prev.filter((c) => c._id !== credentialId)
1006
- );
1072
+ setCredentials((prev) => prev.filter((c) => c._id !== credentialId));
1007
1073
  }
1008
1074
  },
1009
1075
  [deletePasskeyCredential]
@@ -1043,15 +1109,11 @@ function DauthProfileModal({
1043
1109
  if (!t) return {};
1044
1110
  const vars = {};
1045
1111
  if (t.accent) vars["--dauth-accent"] = t.accent;
1046
- if (t.accentHover)
1047
- vars["--dauth-accent-hover"] = t.accentHover;
1112
+ if (t.accentHover) vars["--dauth-accent-hover"] = t.accentHover;
1048
1113
  if (t.surface) vars["--dauth-surface"] = t.surface;
1049
- if (t.surfaceHover)
1050
- vars["--dauth-surface-hover"] = t.surfaceHover;
1051
- if (t.textPrimary)
1052
- vars["--dauth-text-primary"] = t.textPrimary;
1053
- if (t.textSecondary)
1054
- 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;
1055
1117
  if (t.border) vars["--dauth-border"] = t.border;
1056
1118
  return vars;
1057
1119
  }, [domain.modalTheme]);
@@ -1218,14 +1280,7 @@ function DauthProfileModal({
1218
1280
  ),
1219
1281
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1220
1282
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1221
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1222
- "label",
1223
- {
1224
- htmlFor: "dauth-name",
1225
- style: label,
1226
- children: "Name *"
1227
- }
1228
- ),
1283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
1229
1284
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1230
1285
  "input",
1231
1286
  {
@@ -1242,17 +1297,10 @@ function DauthProfileModal({
1242
1297
  )
1243
1298
  ] }),
1244
1299
  hasField("lastname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1245
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1246
- "label",
1247
- {
1248
- htmlFor: "dauth-lastname",
1249
- style: label,
1250
- children: [
1251
- "Last name",
1252
- isRequired("lastname") ? " *" : ""
1253
- ]
1254
- }
1255
- ),
1300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-lastname", style: label, children: [
1301
+ "Last name",
1302
+ isRequired("lastname") ? " *" : ""
1303
+ ] }),
1256
1304
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1257
1305
  "input",
1258
1306
  {
@@ -1269,17 +1317,10 @@ function DauthProfileModal({
1269
1317
  )
1270
1318
  ] }),
1271
1319
  hasField("nickname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1272
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1273
- "label",
1274
- {
1275
- htmlFor: "dauth-nickname",
1276
- style: label,
1277
- children: [
1278
- "Nickname",
1279
- isRequired("nickname") ? " *" : ""
1280
- ]
1281
- }
1282
- ),
1320
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-nickname", style: label, children: [
1321
+ "Nickname",
1322
+ isRequired("nickname") ? " *" : ""
1323
+ ] }),
1283
1324
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1284
1325
  "input",
1285
1326
  {
@@ -1296,17 +1337,10 @@ function DauthProfileModal({
1296
1337
  )
1297
1338
  ] }),
1298
1339
  hasField("country") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1299
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1300
- "label",
1301
- {
1302
- htmlFor: "dauth-country",
1303
- style: label,
1304
- children: [
1305
- "Country",
1306
- isRequired("country") ? " *" : ""
1307
- ]
1308
- }
1309
- ),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-country", style: label, children: [
1341
+ "Country",
1342
+ isRequired("country") ? " *" : ""
1343
+ ] }),
1310
1344
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1311
1345
  "input",
1312
1346
  {
@@ -1377,17 +1411,10 @@ function DauthProfileModal({
1377
1411
  )
1378
1412
  ] }),
1379
1413
  hasField("birth_date") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1380
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1381
- "label",
1382
- {
1383
- htmlFor: "dauth-birthdate",
1384
- style: label,
1385
- children: [
1386
- "Birth date",
1387
- isRequired("birth_date") ? " *" : ""
1388
- ]
1389
- }
1390
- ),
1414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-birthdate", style: label, children: [
1415
+ "Birth date",
1416
+ isRequired("birth_date") ? " *" : ""
1417
+ ] }),
1391
1418
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1392
1419
  "input",
1393
1420
  {
@@ -1404,44 +1431,28 @@ function DauthProfileModal({
1404
1431
  ] }),
1405
1432
  (domain.customFields ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1406
1433
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
1407
- domain.customFields.map((cf) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1408
- "div",
1409
- {
1410
- style: fieldGroup,
1411
- children: [
1412
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1413
- "label",
1414
- {
1415
- htmlFor: `dauth-cf-${cf.key}`,
1416
- style: label,
1417
- children: [
1418
- cf.label,
1419
- cf.required ? " *" : ""
1420
- ]
1421
- }
1422
- ),
1423
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1424
- "input",
1425
- {
1426
- id: `dauth-cf-${cf.key}`,
1427
- type: "text",
1428
- value: customFieldValues[cf.key] ?? "",
1429
- onChange: (e) => setCustomFieldValues(
1430
- (prev) => ({
1431
- ...prev,
1432
- [cf.key]: e.target.value
1433
- })
1434
- ),
1435
- disabled: saving,
1436
- style: input,
1437
- onFocus: inputFocusHandler,
1438
- onBlur: inputBlurHandler
1439
- }
1440
- )
1441
- ]
1442
- },
1443
- cf.key
1444
- ))
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))
1445
1456
  ] })
1446
1457
  ] }),
1447
1458
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
@@ -1501,14 +1512,7 @@ function DauthProfileModal({
1501
1512
  ),
1502
1513
  showRegister && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: registerPanel, children: [
1503
1514
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
1504
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1505
- "label",
1506
- {
1507
- htmlFor: "dauth-passkey-name",
1508
- style: label,
1509
- children: "Passkey name (optional)"
1510
- }
1511
- ),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-passkey-name", style: label, children: "Passkey name (optional)" }),
1512
1516
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1513
1517
  "input",
1514
1518
  {
@@ -1584,89 +1588,82 @@ function DauthProfileModal({
1584
1588
  },
1585
1589
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})
1586
1590
  }
1587
- ) : credentials.length > 0 ? credentials.map((cred) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1588
- "div",
1589
- {
1590
- style: credentialRow,
1591
- 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
- ]
1667
- },
1668
- cred._id
1669
- )) : /* @__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: [
1670
1667
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1671
1668
  "span",
1672
1669
  {
@@ -2229,10 +2226,12 @@ var DauthProvider = (props) => {
2229
2226
  telPrefix,
2230
2227
  telSuffix,
2231
2228
  language,
2229
+ theme,
2232
2230
  avatar,
2233
2231
  birthDate,
2234
2232
  country,
2235
- metadata
2233
+ metadata,
2234
+ customFields
2236
2235
  } = fields;
2237
2236
  const user = {
2238
2237
  name,
@@ -2241,10 +2240,12 @@ var DauthProvider = (props) => {
2241
2240
  telPrefix,
2242
2241
  telSuffix,
2243
2242
  language,
2243
+ theme,
2244
2244
  avatar,
2245
2245
  birthDate,
2246
2246
  country,
2247
- metadata
2247
+ metadata,
2248
+ customFields
2248
2249
  };
2249
2250
  return updateUserAction(ctx, user);
2250
2251
  },
@@ -2270,6 +2271,10 @@ var DauthProvider = (props) => {
2270
2271
  (file) => uploadAvatarAction(ctx, file),
2271
2272
  [ctx]
2272
2273
  );
2274
+ const loginWithPasskey = (0, import_react2.useCallback)(
2275
+ () => loginWithPasskeyAction(ctx),
2276
+ [ctx]
2277
+ );
2273
2278
  const memoProvider = (0, import_react2.useMemo)(
2274
2279
  () => ({
2275
2280
  ...dauthState,
@@ -2280,7 +2285,8 @@ var DauthProvider = (props) => {
2280
2285
  getPasskeyCredentials,
2281
2286
  registerPasskey,
2282
2287
  deletePasskeyCredential,
2283
- uploadAvatar
2288
+ uploadAvatar,
2289
+ loginWithPasskey
2284
2290
  }),
2285
2291
  [
2286
2292
  dauthState,
@@ -2291,7 +2297,8 @@ var DauthProvider = (props) => {
2291
2297
  getPasskeyCredentials,
2292
2298
  registerPasskey,
2293
2299
  deletePasskeyCredential,
2294
- uploadAvatar
2300
+ uploadAvatar,
2301
+ loginWithPasskey
2295
2302
  ]
2296
2303
  );
2297
2304
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DauthContext.Provider, { value: memoProvider, children });