@finueva/auth 0.7.0 → 0.8.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/README.md CHANGED
@@ -16,6 +16,8 @@ const auth = createAuthClient({
16
16
  appOrigin: window.location.origin,
17
17
  });
18
18
 
19
+ if (auth._type !== "browser") throw new Error("Expected a browser Auth client");
20
+
19
21
  const stop = auth.onAuthStateChange((state) => {
20
22
  if (state.status === "cached") renderSessionHint(state.session);
21
23
  if (state.status === "authenticated") renderVerifiedSession(state.session);
@@ -117,6 +119,7 @@ const auth = createDeviceAuth({
117
119
  authOrigin: "https://auth.finueva.com",
118
120
  clientId: "finueva-cli",
119
121
  });
122
+ if (auth._type !== "device") throw new Error("Expected a device Auth client");
120
123
  const authorization = await auth.requestAuthorization();
121
124
  showCode(authorization.userCode, authorization.verificationUri);
122
125
  const token = await auth.pollForToken(authorization, { signal });
@@ -134,6 +137,8 @@ Polling starts at the server-provided interval, adds five seconds after each RFC
134
137
 
135
138
  The token is memory-only by default. Secure persistence is opt-in through a structural adapter implementing `read`, atomic `replace`, and `delete`; every operation receives an `AbortSignal`. The SDK serializes polling, account changes, expiry synchronization, and revocation, including persistence calls. Malformed non-null persisted authority is best-effort deleted before hydration fails, allowing a later process to start without the bad value. The caller owns encryption and platform credential storage. Adapter and authority failures are value-free and never include device codes or tokens. This export uses standard expiring/revocable Better Auth sessions and does not implement refresh tokens.
136
139
 
140
+ Browser and device clients expose the literal `_type` values `"browser"` and `"device"`. Use that discriminant to narrow a union before invoking runtime-specific methods; do not infer the client type from environment globals.
141
+
137
142
  Direct email and social signup/sign-in are intended for registered first-party mobile or Tauri clients. The SDK verifies the opaque token through bearer `get-session`, derives its expiry from that authoritative session, atomically replaces secure persistence, and only then publishes it in memory. Verification or replacement failure triggers best-effort revocation of the new session and retains the previous token only after current authority verifies it. A successful account switch best-effort revokes the replaced current-device session after publishing the new token. Password replacement follows the same rule; when Better Auth returns no replacement token, the current token is retained only after an authoritative session check. `getSession()` synchronizes changed authoritative expiry back to persistence.
138
143
 
139
144
  For Tauri, implement `DeviceTokenPersistence` in Rust commands backed by the operating system credential vault (Keychain, Credential Manager, or Secret Service). Store the complete `DeviceToken` as one encrypted/versioned item, make replacement atomic, and restrict access to this application identity. An `AbortSignal` cannot cancel a native `invoke` that has already been dispatched. The SDK retains an internal persistence queue after public timeout, runs compensating deletion after a late replacement, and rejects later authority operations with `state_conflict` until that queue settles. The process can still terminate between a native commit and compensation; production adapters need a native pending-operation journal or equivalent startup cleanup before returning a stored token. This process-crash recovery remains outside SDK qualification. Do not use WebView local storage, a plaintext file, Tauri Store, logs, crash metadata, or frontend state. Drive credentials remain memory-only even when the Better Auth session uses secure OS persistence; the device client keeps only one selected workspace credential and renews it with two minutes remaining. It permits at most one issuance request: an exact same-workspace non-forced call may share that request, while a workspace switch or forced refresh returns `state_conflict` until it settles.
package/dist/device.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, l as DriveCredential, o as AuthSession, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError, y as UpdateProfileInput } from "./types-B1SZbs6Z.js";
1
+ import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, l as DriveCredential, o as AuthSession, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError, y as UpdateProfileInput } from "./types-DDopQNZR.js";
2
2
  //#region src/device.d.ts
3
3
  type DeviceAuthorizationErrorCode = "device_access_denied" | "device_authorization_cancelled" | "device_code_expired" | "invalid_device_authorization" | "identity_authority_unavailable";
4
4
  declare class DeviceAuthorizationError extends Error {
@@ -37,6 +37,7 @@ interface PollDeviceOptions {
37
37
  signal?: AbortSignal;
38
38
  }
39
39
  interface DeviceAuthClient {
40
+ readonly _type: "device";
40
41
  requestAuthorization(options?: {
41
42
  signal?: AbortSignal;
42
43
  }): Promise<DeviceAuthorization>;
package/dist/device.js CHANGED
@@ -1101,6 +1101,7 @@ function createDeviceAuth(options) {
1101
1101
  }
1102
1102
  }
1103
1103
  return {
1104
+ _type: "device",
1104
1105
  requestAuthorization,
1105
1106
  pollForToken(authorization, pollOptions) {
1106
1107
  let signal;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, a as AuthPersistenceDriver, b as WorkspaceSelection, c as AuthUser, d as FinuevaAuthClient, f as InvitationAcceptance, g as SignInInput, h as SendVerificationEmailInput, i as AuthPersistence, l as DriveCredential, m as PersonalWorkspaceSelection, n as AuthClientOptions, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, s as AuthState, t as AcceptInvitationInput, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError, y as UpdateProfileInput } from "./types-B1SZbs6Z.js";
1
+ import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, a as AuthPersistenceDriver, b as WorkspaceSelection, c as AuthUser, d as FinuevaAuthClient, f as InvitationAcceptance, g as SignInInput, h as SendVerificationEmailInput, i as AuthPersistence, l as DriveCredential, m as PersonalWorkspaceSelection, n as AuthClientOptions, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, s as AuthState, t as AcceptInvitationInput, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError, y as UpdateProfileInput } from "./types-DDopQNZR.js";
2
2
  //#region src/client.d.ts
3
3
  declare function createAuthClient(options: AuthClientOptions): FinuevaAuthClient;
4
4
  //#endregion
package/dist/index.js CHANGED
@@ -3535,6 +3535,7 @@ function createAuthClient(options) {
3535
3535
  })).value;
3536
3536
  }
3537
3537
  return {
3538
+ _type: "browser",
3538
3539
  acceptInvitation(input) {
3539
3540
  let invitation;
3540
3541
  try {
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, b as WorkspaceSelection, c as AuthUser, f as InvitationAcceptance, l as DriveCredential, m as PersonalWorkspaceSelection, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, t as AcceptInvitationInput, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError } from "./types-B1SZbs6Z.js";
1
+ import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, b as WorkspaceSelection, c as AuthUser, f as InvitationAcceptance, l as DriveCredential, m as PersonalWorkspaceSelection, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, t as AcceptInvitationInput, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError } from "./types-DDopQNZR.js";
2
2
  //#region src/server.d.ts
3
3
  interface ServerAuthOptions {
4
4
  authOrigin: string;
@@ -102,6 +102,7 @@ interface AuthClientOptions {
102
102
  timeoutMs?: number;
103
103
  }
104
104
  interface FinuevaAuthClient {
105
+ readonly _type: "browser";
105
106
  acceptInvitation(input: AcceptInvitationInput): Promise<InvitationAcceptance>;
106
107
  getSession(): Promise<AuthSession | null>;
107
108
  listOrganizations(): Promise<AuthOrganization[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finueva/auth",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Public browser and server SDK for Finueva Auth",
5
5
  "type": "module",
6
6
  "sideEffects": false,