@palbase/web 6.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/{analytics-facade-Cp3d4QI-.d.ts → analytics-facade-CZIwbsvG.d.ts} +65 -1
  2. package/dist/{analytics-facade-CaluA4bW.d.cts → analytics-facade-esr6cOBN.d.cts} +65 -1
  3. package/dist/{chunk-BNAGRUIQ.js → chunk-ACCJV6FV.js} +32 -2
  4. package/dist/chunk-ACCJV6FV.js.map +1 -0
  5. package/dist/{chunk-KOJ4OAAR.js → chunk-P6TWUWZC.js} +209 -3
  6. package/dist/chunk-P6TWUWZC.js.map +1 -0
  7. package/dist/{chunk-OWLTZG2V.js → chunk-ZC6Q3GPX.js} +2 -2
  8. package/dist/index.cjs +207 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +3 -3
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +2 -2
  13. package/dist/internal.cjs +238 -2
  14. package/dist/internal.cjs.map +1 -1
  15. package/dist/internal.d.cts +3 -3
  16. package/dist/internal.d.ts +3 -3
  17. package/dist/internal.js +2 -2
  18. package/dist/next/client.cjs +238 -2
  19. package/dist/next/client.cjs.map +1 -1
  20. package/dist/next/client.js +2 -2
  21. package/dist/next/index.cjs +238 -2
  22. package/dist/next/index.cjs.map +1 -1
  23. package/dist/next/index.d.cts +2 -2
  24. package/dist/next/index.d.ts +2 -2
  25. package/dist/next/index.js +3 -3
  26. package/dist/next/proxy.js +2 -2
  27. package/dist/{pb-DUK5qy81.d.ts → pb-AWwslm5m.d.ts} +1 -1
  28. package/dist/{pb-DvV6ftmf.d.cts → pb-BT-vKA4j.d.cts} +1 -1
  29. package/dist/react/index.cjs +1 -1
  30. package/dist/react/index.cjs.map +1 -1
  31. package/dist/react/index.d.cts +1 -1
  32. package/dist/react/index.d.ts +1 -1
  33. package/dist/react/index.js +2 -2
  34. package/package.json +1 -1
  35. package/dist/chunk-BNAGRUIQ.js.map +0 -1
  36. package/dist/chunk-KOJ4OAAR.js.map +0 -1
  37. /package/dist/{chunk-OWLTZG2V.js.map → chunk-ZC6Q3GPX.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BackendError
3
- } from "./chunk-BNAGRUIQ.js";
3
+ } from "./chunk-ACCJV6FV.js";
4
4
 
5
5
  // src/next/shared.ts
6
6
  var nextServerModule;
@@ -21,4 +21,4 @@ async function importNextServer(caller) {
21
21
  export {
22
22
  importNextServer
23
23
  };
24
- //# sourceMappingURL=chunk-OWLTZG2V.js.map
24
+ //# sourceMappingURL=chunk-ZC6Q3GPX.js.map
package/dist/index.cjs CHANGED
@@ -449,6 +449,162 @@ function asWireAuthResult(raw) {
449
449
  return raw;
450
450
  }
451
451
 
452
+ // src/passkey.ts
453
+ function base64UrlToBytes(value) {
454
+ const padded = value.replace(/-/g, "+").replace(/_/g, "/");
455
+ const binary = atob(padded.padEnd(padded.length + (4 - padded.length % 4) % 4, "="));
456
+ const bytes = new Uint8Array(new ArrayBuffer(binary.length));
457
+ for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
458
+ return bytes;
459
+ }
460
+ function bytesToBase64Url(buffer) {
461
+ const bytes = new Uint8Array(buffer);
462
+ let binary = "";
463
+ for (const b of bytes) binary += String.fromCharCode(b);
464
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
465
+ }
466
+ function requireString(source, key) {
467
+ const value = source[key];
468
+ if (typeof value !== "string" || value === "") {
469
+ throw new Error(`passkey options are missing ${key}`);
470
+ }
471
+ return value;
472
+ }
473
+ function toCreationOptions(publicKey) {
474
+ const rp = publicKey.rp;
475
+ const user = publicKey.user;
476
+ if (!user?.id) {
477
+ throw new Error("passkey options carry no user id \u2014 the credential would be unusable");
478
+ }
479
+ const excludeCredentials = Array.isArray(publicKey.excludeCredentials) ? publicKey.excludeCredentials.map((c) => ({
480
+ id: base64UrlToBytes(c.id),
481
+ type: "public-key"
482
+ })) : void 0;
483
+ return {
484
+ challenge: base64UrlToBytes(requireString(publicKey, "challenge")),
485
+ rp: { id: rp?.id, name: rp?.name ?? rp?.id ?? "" },
486
+ user: {
487
+ id: base64UrlToBytes(user.id),
488
+ name: user.name ?? "",
489
+ displayName: user.displayName ?? user.name ?? ""
490
+ },
491
+ pubKeyCredParams: publicKey.pubKeyCredParams ?? [],
492
+ authenticatorSelection: publicKey.authenticatorSelection,
493
+ timeout: publicKey.timeout,
494
+ attestation: publicKey.attestation,
495
+ excludeCredentials
496
+ };
497
+ }
498
+ function toRequestOptions(publicKey) {
499
+ const allowCredentials = Array.isArray(publicKey.allowCredentials) ? publicKey.allowCredentials.map((c) => ({
500
+ id: base64UrlToBytes(c.id),
501
+ type: "public-key"
502
+ })) : void 0;
503
+ return {
504
+ challenge: base64UrlToBytes(requireString(publicKey, "challenge")),
505
+ rpId: publicKey.rpId,
506
+ timeout: publicKey.timeout,
507
+ userVerification: publicKey.userVerification,
508
+ allowCredentials
509
+ };
510
+ }
511
+ function attestationToJSON(credential) {
512
+ const response = credential.response;
513
+ return {
514
+ id: credential.id,
515
+ rawId: bytesToBase64Url(credential.rawId),
516
+ type: credential.type,
517
+ response: {
518
+ clientDataJSON: bytesToBase64Url(response.clientDataJSON),
519
+ attestationObject: bytesToBase64Url(response.attestationObject)
520
+ }
521
+ };
522
+ }
523
+ function assertionToJSON(credential) {
524
+ const response = credential.response;
525
+ return {
526
+ id: credential.id,
527
+ rawId: bytesToBase64Url(credential.rawId),
528
+ type: credential.type,
529
+ response: {
530
+ clientDataJSON: bytesToBase64Url(response.clientDataJSON),
531
+ authenticatorData: bytesToBase64Url(response.authenticatorData),
532
+ signature: bytesToBase64Url(response.signature),
533
+ // The user handle is how palauth resolves WHO signed in on a discoverable
534
+ // login — there is no identifier in the request.
535
+ userHandle: response.userHandle ? bytesToBase64Url(response.userHandle) : null
536
+ }
537
+ };
538
+ }
539
+ function isPasskeySupported() {
540
+ return typeof window !== "undefined" && typeof window.PublicKeyCredential === "function" && typeof navigator !== "undefined" && navigator.credentials !== void 0;
541
+ }
542
+ function ensureSupported() {
543
+ if (!isPasskeySupported()) {
544
+ throw new Error("This browser cannot use passkeys \u2014 offer a password or e-mail sign-in");
545
+ }
546
+ }
547
+ async function createCredential(publicKey) {
548
+ const credential = await navigator.credentials.create({
549
+ publicKey: toCreationOptions(publicKey)
550
+ });
551
+ if (credential === null) {
552
+ throw new Error("the browser returned no credential");
553
+ }
554
+ return credential;
555
+ }
556
+ async function getCredential(publicKey) {
557
+ const credential = await navigator.credentials.get({
558
+ publicKey: toRequestOptions(publicKey)
559
+ });
560
+ if (credential === null) {
561
+ throw new Error("the browser returned no credential");
562
+ }
563
+ return credential;
564
+ }
565
+ async function passkeySignIn(rt) {
566
+ ensureSupported();
567
+ const envelope = await palbeRequest(rt, "POST", "/auth/webauthn/login/begin", {
568
+ body: {}
569
+ });
570
+ const credential = await getCredential(envelope.options.publicKey);
571
+ const raw = await palbeRequest(rt, "POST", "/auth/webauthn/login/finish", {
572
+ body: assertionToJSON(credential)
573
+ });
574
+ const result = asWireAuthResult(raw);
575
+ if (result === null) {
576
+ throw new Error("passkey sign-in returned an unusable session");
577
+ }
578
+ return result;
579
+ }
580
+ async function passkeySignUp(rt, email, displayName) {
581
+ ensureSupported();
582
+ const begun = await palbeRequest(rt, "POST", "/auth/webauthn/signup/begin", {
583
+ body: { email, user_name: displayName }
584
+ });
585
+ const credential = await createCredential(begun.options.publicKey);
586
+ await palbeRequest(
587
+ rt,
588
+ "POST",
589
+ `/auth/webauthn/signup/finish?user_id=${encodeURIComponent(begun.user_id)}`,
590
+ { body: attestationToJSON(credential) }
591
+ );
592
+ return await passkeySignIn(rt);
593
+ }
594
+ async function passkeyRegister(rt, name) {
595
+ ensureSupported();
596
+ const envelope = await palbeRequest(
597
+ rt,
598
+ "POST",
599
+ "/auth/webauthn/register/begin",
600
+ { body: { name } }
601
+ );
602
+ const credential = await createCredential(envelope.options.publicKey);
603
+ await palbeRequest(rt, "POST", "/auth/webauthn/register/finish", {
604
+ body: attestationToJSON(credential)
605
+ });
606
+ }
607
+
452
608
  // src/auth-facade.ts
453
609
  function mapWireUser(raw) {
454
610
  return {
@@ -585,6 +741,23 @@ var PalbeAuth = class {
585
741
  const raw = await palbeRequest(this.rt, "GET", "/auth/user");
586
742
  return mapWireUser(raw);
587
743
  }
744
+ /**
745
+ * Which credentials this account actually has.
746
+ *
747
+ * An account reached through Google has no password, so showing it a
748
+ * "current password" field gives the user something they can never fill —
749
+ * and `getUser()` cannot tell you, because GET /auth/user carries no
750
+ * credential information. Read this before rendering any re-auth or
751
+ * change-password form.
752
+ */
753
+ async getSignInMethods() {
754
+ const raw = await palbeRequest(this.rt, "GET", "/auth/me");
755
+ return {
756
+ password: raw.has_password,
757
+ mfa: raw.has_mfa,
758
+ providers: raw.providers ?? null
759
+ };
760
+ }
588
761
  async refreshUser() {
589
762
  const user = await this.getUser();
590
763
  const changed = !usersEqual(user, this.cachedUser);
@@ -786,6 +959,39 @@ var PalbeAuth = class {
786
959
  return this.adopt(data);
787
960
  });
788
961
  }
962
+ /**
963
+ * Sign in with a passkey stored for this Environment. No identifier is typed:
964
+ * the browser lists the accounts it holds and the user picks one.
965
+ *
966
+ * Throws when the browser cannot run a ceremony — check `passkeysSupported`
967
+ * first and keep a password or e-mail path beside the button.
968
+ */
969
+ async signInWithPasskey() {
970
+ return this.withSigningIn(async () => this.adoptWire(await passkeySignIn(this.rt)));
971
+ }
972
+ /**
973
+ * Create an account whose only credential is a passkey — the e-mail is the
974
+ * identifier, the passkey is the credential, and no password ever exists.
975
+ */
976
+ async signUpWithPasskey(email, displayName) {
977
+ return this.withSigningIn(
978
+ async () => this.adoptWire(await passkeySignUp(this.rt, email, displayName))
979
+ );
980
+ }
981
+ /**
982
+ * Add a passkey to the signed-in account, so the next sign-in is one tap.
983
+ *
984
+ * Rejects with a 403 `reauthentication_required` when the session is not
985
+ * recent: a passkey outlives a password reset, so enrolling one takes more
986
+ * than a valid session.
987
+ */
988
+ async registerPasskey(name) {
989
+ await passkeyRegister(this.rt, name);
990
+ }
991
+ /** Whether this browser can run a passkey ceremony at all. */
992
+ get passkeysSupported() {
993
+ return isPasskeySupported();
994
+ }
789
995
  async signInWithOAuth(params) {
790
996
  const { redirect = true, ...opts } = params;
791
997
  const { url } = unwrap(await this.rt.authClient.getOAuthURL(opts));
@@ -7685,7 +7891,7 @@ function localStorageSessionStorage(key = DEFAULT_KEY) {
7685
7891
  }
7686
7892
 
7687
7893
  // src/version.ts
7688
- var VERSION = "6.0.0";
7894
+ var VERSION = "7.1.0";
7689
7895
 
7690
7896
  // src/internal.ts
7691
7897
  function getRuntime() {