diff --git a/.changeset/lemon-doors-listen.md b/.changeset/lemon-doors-listen.md deleted file mode 100644 index 13cb2a8..0000000 --- a/.changeset/lemon-doors-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@seamless-auth/react': patch ---- - -Read the OAuth failure code from a nested `details` object when the error body does not carry it at the top level. `getOAuthErrorCode` only looked at a top-level `code`, which is where the auth API puts it, so a proxy that normalized the error body and moved the siblings of `error` under `details` silently downgraded OAuth messaging to a generic failure. Both locations are accepted now, the top level still wins, and the allowlist is unchanged: an unrecognized code in either place still returns `undefined`. diff --git a/.changeset/lucky-pandas-listen.md b/.changeset/lucky-pandas-listen.md deleted file mode 100644 index a0efff5..0000000 --- a/.changeset/lucky-pandas-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@seamless-auth/react': minor ---- - -Stop discarding the underlying WebAuthn error. The passkey login, passkey registration, and step-up verification methods now attach the thrown ceremony error to the returned `SeamlessAuthError` as `cause`, and a new `getWebAuthnErrorDetail()` export reads its `name`, `code`, and `message`. Callers can tell a dismissed prompt or missing credential (`NotAllowedError`) apart from an origin or RP ID mismatch (`SecurityError`) instead of seeing one generic string. The friendly result messages are unchanged, and only the error name is logged. diff --git a/.changeset/nine-pans-shake.md b/.changeset/nine-pans-shake.md deleted file mode 100644 index 3cb1cb0..0000000 --- a/.changeset/nine-pans-shake.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@seamless-auth/react': patch ---- - -Stop calling the logout endpoint when the session check fails. A failed `/users/me` means the server already considers the session unusable, so the SDK now clears it locally instead of sending a `DELETE /logout` for a session that does not exist. Previously every anonymous page load fired that second request. - -Session state now lives in a framework-agnostic store behind `AuthProvider`, which reads it through `useSyncExternalStore`. The provider's public API is unchanged. Reading a previous sign-in goes through a storage port that falls back to memory when there is no `localStorage`, so the store is safe to create during server-side rendering. - -The store survives a remount. React can run mount, cleanup, mount against the same provider, which StrictMode does on every mount and Activity does whenever a hidden tree is shown again, so the provider no longer destroys the store from its effect cleanup. `destroy()` is terminal, and tearing it down there left the remounted provider holding a store that refused every update and stayed on `loading: true`. diff --git a/.changeset/olive-carrots-repeat.md b/.changeset/olive-carrots-repeat.md deleted file mode 100644 index 600e3f9..0000000 --- a/.changeset/olive-carrots-repeat.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@seamless-auth/react': minor ---- - -Adopt `@seamless-auth/types` for the API request and response shapes. The SDK's types were hand-written and maintained in parallel with the auth API's schemas; they are now aliases of the published contract, so they cannot drift from what the API actually sends. The dependency is types-only, imported with `import type`, so no schema validation library reaches your bundle and the export names you import are unchanged. - -Some types are now more accurate, which is a breaking change at the type level for adopters: - -- `Credential.lastUsedAt` is `string | null | undefined`, not `Date | null`. The API serializes it as an ISO 8601 string, so code calling a `Date` method on it was relying on a type that never matched the wire value and threw at runtime. Wrap it yourself: `new Date(credential.lastUsedAt)`. -- `Credential.deviceType`, `friendlyName`, `platform`, `browser`, and `deviceInfo` are optional, matching the API. `Credential.createdAt` is now present. -- `User.phone` is `string | null`, and `User.roles` is required rather than optional. `User` also carries `lastLogin`. -- `Organization.createdAt` and `updatedAt` are `string` rather than `string | Date`. - -No runtime behavior changes. diff --git a/.changeset/olive-jokes-report.md b/.changeset/olive-jokes-report.md deleted file mode 100644 index 54db94e..0000000 --- a/.changeset/olive-jokes-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@seamless-auth/react': minor ---- - -Surface OAuth callback error codes. A new `getOAuthErrorCode()` export reads the auth API's machine-readable `code` off a `SeamlessAuthError` and narrows it to `oauth_missing_email`, `oauth_email_not_verified`, or `oauth_missing_subject`, returning `undefined` for anything unrecognized. The bundled OAuth callback screen now maps those three codes to actionable text instead of one generic failure message. diff --git a/.changeset/tidy-moons-tap.md b/.changeset/tidy-moons-tap.md deleted file mode 100644 index 9ff7f98..0000000 --- a/.changeset/tidy-moons-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@seamless-auth/react': patch ---- - -Take the last five response envelopes from `@seamless-auth/types` instead of declaring them here. `OAuthProvidersResult`, `CredentialUpdateResult`, `OrganizationResult`, `OrganizationMembersResult`, and `OrganizationMembershipResult` were hand-written because the package had no exported alias for their schemas; types 0.4.0 exports one for every schema, so they are aliases now like the rest. The shapes are identical, so this is a no-op for adopters, and the dependency stays types-only. diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c6198..1bf90f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # @seamless-auth/react +## 0.7.0 + +### Minor Changes + +- b4b7ca1: Stop discarding the underlying WebAuthn error. The passkey login, passkey registration, and step-up verification methods now attach the thrown ceremony error to the returned `SeamlessAuthError` as `cause`, and a new `getWebAuthnErrorDetail()` export reads its `name`, `code`, and `message`. Callers can tell a dismissed prompt or missing credential (`NotAllowedError`) apart from an origin or RP ID mismatch (`SecurityError`) instead of seeing one generic string. The friendly result messages are unchanged, and only the error name is logged. +- 41dfea7: Adopt `@seamless-auth/types` for the API request and response shapes. The SDK's types were hand-written and maintained in parallel with the auth API's schemas; they are now aliases of the published contract, so they cannot drift from what the API actually sends. The dependency is types-only, imported with `import type`, so no schema validation library reaches your bundle and the export names you import are unchanged. + + Some types are now more accurate, which is a breaking change at the type level for adopters: + - `Credential.lastUsedAt` is `string | null | undefined`, not `Date | null`. The API serializes it as an ISO 8601 string, so code calling a `Date` method on it was relying on a type that never matched the wire value and threw at runtime. Wrap it yourself: `new Date(credential.lastUsedAt)`. + - `Credential.deviceType`, `friendlyName`, `platform`, `browser`, and `deviceInfo` are optional, matching the API. `Credential.createdAt` is now present. + - `User.phone` is `string | null`, and `User.roles` is required rather than optional. `User` also carries `lastLogin`. + - `Organization.createdAt` and `updatedAt` are `string` rather than `string | Date`. + + No runtime behavior changes. + +- 3922389: Surface OAuth callback error codes. A new `getOAuthErrorCode()` export reads the auth API's machine-readable `code` off a `SeamlessAuthError` and narrows it to `oauth_missing_email`, `oauth_email_not_verified`, or `oauth_missing_subject`, returning `undefined` for anything unrecognized. The bundled OAuth callback screen now maps those three codes to actionable text instead of one generic failure message. + +### Patch Changes + +- a82768d: Read the OAuth failure code from a nested `details` object when the error body does not carry it at the top level. `getOAuthErrorCode` only looked at a top-level `code`, which is where the auth API puts it, so a proxy that normalized the error body and moved the siblings of `error` under `details` silently downgraded OAuth messaging to a generic failure. Both locations are accepted now, the top level still wins, and the allowlist is unchanged: an unrecognized code in either place still returns `undefined`. +- e27dcca: Stop calling the logout endpoint when the session check fails. A failed `/users/me` means the server already considers the session unusable, so the SDK now clears it locally instead of sending a `DELETE /logout` for a session that does not exist. Previously every anonymous page load fired that second request. + + Session state now lives in a framework-agnostic store behind `AuthProvider`, which reads it through `useSyncExternalStore`. The provider's public API is unchanged. Reading a previous sign-in goes through a storage port that falls back to memory when there is no `localStorage`, so the store is safe to create during server-side rendering. + + The store survives a remount. React can run mount, cleanup, mount against the same provider, which StrictMode does on every mount and Activity does whenever a hidden tree is shown again, so the provider no longer destroys the store from its effect cleanup. `destroy()` is terminal, and tearing it down there left the remounted provider holding a store that refused every update and stayed on `loading: true`. + +- 83bf7b8: Take the last five response envelopes from `@seamless-auth/types` instead of declaring them here. `OAuthProvidersResult`, `CredentialUpdateResult`, `OrganizationResult`, `OrganizationMembersResult`, and `OrganizationMembershipResult` were hand-written because the package had no exported alias for their schemas; types 0.4.0 exports one for every schema, so they are aliases now like the rest. The shapes are identical, so this is a no-op for adopters, and the dependency stays types-only. + ## 0.6.0 ### Minor Changes diff --git a/package.json b/package.json index 24fa8fe..49ceaa2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@seamless-auth/react", - "version": "0.6.0", + "version": "0.7.0", "description": "A drop-in authentication solution for modern React applications.", "type": "module", "exports": {