@aurabase/core 0.6.2 → 0.7.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.cjs CHANGED
@@ -90,17 +90,17 @@ var AuraError = class _AuraError extends Error {
90
90
  this.code = canonical;
91
91
  } else if (status === 429) {
92
92
  this.code = "RATE_LIMITED";
93
- } else if (status === 401 && (lowerMsg.includes("identifiants") || lowerMsg.includes("credentials") || lowerMsg.includes("mot de passe incorrect"))) {
93
+ } else if (status === 401 && lowerMsg.includes("credentials")) {
94
94
  this.code = "INVALID_CREDENTIALS";
95
- } else if (status === 401 && (lowerMsg.includes("r\xE9voqu\xE9e") || lowerMsg.includes("revoked"))) {
95
+ } else if (status === 401 && lowerMsg.includes("revoked")) {
96
96
  this.code = "SESSION_REVOKED";
97
- } else if (status === 401 && (lowerMsg.includes("expir\xE9") || lowerMsg.includes("expired"))) {
97
+ } else if (status === 401 && lowerMsg.includes("expired")) {
98
98
  this.code = "SESSION_EXPIRED";
99
- } else if (status === 400 && (lowerMsg.includes("mot de passe") || lowerMsg.includes("password"))) {
99
+ } else if (status === 400 && lowerMsg.includes("password")) {
100
100
  this.code = "WEAK_PASSWORD";
101
- } else if (status === 409 && (lowerMsg.includes("d\xE9j\xE0 utilis\xE9") || lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
101
+ } else if (status === 409 && (lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
102
102
  this.code = "EMAIL_ALREADY_IN_USE";
103
- } else if (status === 404 && (lowerMsg.includes("utilisateur") || lowerMsg.includes("user not found"))) {
103
+ } else if (status === 404 && lowerMsg.includes("user not found")) {
104
104
  this.code = "USER_NOT_FOUND";
105
105
  } else {
106
106
  this.code = canonical ?? `HTTP_${status}`;
@@ -292,6 +292,24 @@ function decodeJwtPayload(token) {
292
292
  return null;
293
293
  }
294
294
  }
295
+ function userFromAccessToken(token) {
296
+ const c = decodeJwtPayload(token);
297
+ if (!c || typeof c.sub !== "string") return null;
298
+ const meta = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
299
+ const amr = Array.isArray(c.amr) ? c.amr : [];
300
+ return {
301
+ id: c.sub,
302
+ email: typeof c.email === "string" ? c.email : null,
303
+ role: "authenticated",
304
+ email_verified: false,
305
+ is_banned: false,
306
+ is_anonymous: amr.some((a) => a?.method === "anonymous"),
307
+ mfa_enabled: c.aal === "aal2",
308
+ user_metadata: meta(c.user_metadata),
309
+ app_metadata: meta(c.app_metadata),
310
+ created_at: ""
311
+ };
312
+ }
295
313
  function isTokenExpired(token, marginSec = 0) {
296
314
  const payload = decodeJwtPayload(token);
297
315
  if (!payload || typeof payload.exp !== "number") return true;
@@ -983,6 +1001,9 @@ var LocalAuthStore = class extends BaseAuthStore {
983
1001
  /**
984
1002
  * Populate the store from a raw `Cookie` header string (server-side).
985
1003
  * Looks for the key matching `this.key`.
1004
+ *
1005
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
1006
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
986
1007
  */
987
1008
  loadFromCookie(cookieString) {
988
1009
  const prefix = `${this.key}=`;
@@ -991,20 +1012,22 @@ var LocalAuthStore = class extends BaseAuthStore {
991
1012
  try {
992
1013
  const raw = decodeURIComponent(entry.slice(prefix.length));
993
1014
  const parsed = JSON.parse(raw);
994
- if (parsed.token && parsed.refreshToken && parsed.user) {
995
- super.save(parsed.token, parsed.refreshToken, parsed.user);
1015
+ const user = parsed.token ? userFromAccessToken(parsed.token) : null;
1016
+ if (parsed.token && parsed.refreshToken && user) {
1017
+ super.save(parsed.token, parsed.refreshToken, user);
996
1018
  }
997
1019
  } catch {
998
1020
  }
999
1021
  }
1000
1022
  /**
1001
- * Serialize current auth state into a `Set-Cookie` value.
1023
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
1024
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
1025
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
1002
1026
  */
1003
1027
  exportToCookie(options = {}) {
1004
1028
  const data = {
1005
1029
  token: this.token,
1006
- refreshToken: this.refreshToken,
1007
- user: this.user
1030
+ refreshToken: this.refreshToken
1008
1031
  };
1009
1032
  const encoded = encodeURIComponent(JSON.stringify(data));
1010
1033
  const parts = [`${this.key}=${encoded}`];
package/dist/index.d.cts CHANGED
@@ -14,7 +14,7 @@
14
14
  * - storage/path.ts : invalid_path
15
15
  * - db/QueryBuilder.ts: PGRST116 (parité PostgREST : `.single()` sur 0/plusieurs lignes)
16
16
  */
17
- type AuraErrorCode = 'NO_SESSION' | 'TIMEOUT' | 'NETWORK_ERROR' | 'INVALID_RESPONSE' | 'REFRESH_DISCARDED' | 'UNVERIFIABLE_TOKEN' | 'NO_CODE_VERIFIER' | 'PKCE_GENERATION_FAILED' | 'MISSING_EMAIL' | 'JWKS_FETCH_FAILED' | 'SIGNATURE_INVALID' | 'TOKEN_EXPIRED' | 'TOKEN_NOT_YET_VALID' | 'INVALID_JWT' | 'UNSUPPORTED_ALG' | 'NO_MATCHING_KEY' | 'INVALID_ISSUER' | 'INVALID_AUDIENCE' | 'INVALID_PATH' | 'PGRST116' | 'INVALID_CREDENTIALS' | 'WEAK_PASSWORD' | 'EMAIL_ALREADY_IN_USE' | 'USER_NOT_FOUND' | 'RATE_LIMITED' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'SESSION_REVOKED' | (string & {});
17
+ type AuraErrorCode = 'NO_SESSION' | 'TIMEOUT' | 'NETWORK_ERROR' | 'INVALID_RESPONSE' | 'REFRESH_DISCARDED' | 'UNVERIFIABLE_TOKEN' | 'NO_CODE_VERIFIER' | 'PKCE_GENERATION_FAILED' | 'MISSING_EMAIL' | 'JWKS_FETCH_FAILED' | 'SIGNATURE_INVALID' | 'TOKEN_EXPIRED' | 'TOKEN_NOT_YET_VALID' | 'INVALID_JWT' | 'UNSUPPORTED_ALG' | 'NO_MATCHING_KEY' | 'INVALID_ISSUER' | 'INVALID_AUDIENCE' | 'INVALID_PATH' | 'PGRST116' | 'INVALID_CREDENTIALS' | 'WEAK_PASSWORD' | 'PASSWORD_REQUIRED' | 'EMAIL_ALREADY_IN_USE' | 'USER_NOT_FOUND' | 'USER_BANNED' | 'EMAIL_NOT_CONFIRMED' | 'RATE_LIMITED' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'SESSION_REVOKED' | 'MFA_CODE_INVALID' | 'MFA_CODE_ALREADY_USED' | 'TOTP_CODE_REUSED' | 'MFA_CHALLENGE_EXPIRED' | (string & {});
18
18
  /**
19
19
  * Structured error thrown/returned by the Aurabase SDK.
20
20
  * Mirrors the backend's `AuraError` JSON shape with semantic DX normalization.
@@ -34,6 +34,8 @@ declare class AuraError extends Error {
34
34
  error?: {
35
35
  code?: string;
36
36
  message?: string;
37
+ hint?: string;
38
+ details?: unknown;
37
39
  };
38
40
  message?: string;
39
41
  } | null, headers?: Headers | Record<string, string | null | undefined>);
@@ -203,10 +205,6 @@ interface User {
203
205
  interface Session {
204
206
  access_token: string;
205
207
  refresh_token: string;
206
- /** Alias camelCase pour parité DX Supabase/JS */
207
- accessToken?: string;
208
- /** Alias camelCase pour parité DX Supabase/JS */
209
- refreshToken?: string;
210
208
  token_type: string;
211
209
  expires_in: number;
212
210
  expires_at?: number;
@@ -217,30 +215,20 @@ interface Session {
217
215
  interface TokenPair {
218
216
  access_token: string;
219
217
  refresh_token: string;
220
- /** Alias camelCase pour parité DX Supabase/JS */
221
- accessToken?: string;
222
- /** Alias camelCase pour parité DX Supabase/JS */
223
- refreshToken?: string;
224
218
  token_type: string;
225
219
  expires_in: number;
226
220
  user: User;
227
221
  provider_token?: string | null;
228
222
  provider_refresh_token?: string | null;
229
- /** Sous-objet session pour parité DX Supabase (`data.session.access_token`). */
230
- session?: Session;
231
- mfaChallenge?: undefined;
223
+ /** Sous-objet session pour parité DX Supabase (`data.session.access_token`).
224
+ * `null` après une inscription sur un projet qui exige un e-mail vérifié (AUTH-002). */
225
+ session?: Session | null;
232
226
  }
233
227
  interface MfaChallenge {
234
228
  mfa_required: true;
235
229
  mfa_token: string;
236
230
  mfa_setup_required?: boolean;
237
231
  session?: undefined;
238
- /** Alias ergonomique aligné sur la documentation officielle */
239
- mfaChallenge?: {
240
- mfaRequired: boolean;
241
- mfaToken: string;
242
- mfaSetupRequired?: boolean;
243
- };
244
232
  }
245
233
  type LoginResponse = TokenPair | MfaChallenge;
246
234
  type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
@@ -375,9 +363,35 @@ interface MfaEnrollResponse {
375
363
  otpauth_url: string;
376
364
  secret: string;
377
365
  }
378
- interface MfaVerifyRequest {
366
+ /**
367
+ * Relève un défi MFA : exactement UN facteur parmi `code` (TOTP à 6 chiffres), `recovery_code`
368
+ * (code de secours `XXXXXXXX-XXXXXXXX`) et `sms_code` (code reçu après `auth.mfa.sms.send`).
369
+ * Pour une passkey, utilisez `auth.mfa.webauthn.verify`.
370
+ */
371
+ type MfaVerifyRequest = {
379
372
  mfa_token: string;
380
373
  code: string;
374
+ } | {
375
+ mfa_token: string;
376
+ recovery_code: string;
377
+ } | {
378
+ mfa_token: string;
379
+ sms_code: string;
380
+ };
381
+ /** Facteur MFA utilisable pour relever un défi (`auth.mfa.factors`). */
382
+ type MfaFactorType = 'totp' | 'webauthn' | 'sms';
383
+ /** Passkey WebAuthn enrôlée (`auth.mfa.webauthn.list`). */
384
+ interface PasskeyInfo {
385
+ id: string;
386
+ friendly_name: string;
387
+ created_at: string;
388
+ last_used_at: string | null;
389
+ }
390
+ /** Résultat de l'enrôlement d'une passkey. `recovery_codes` n'est présent que si cette passkey est le premier facteur du compte. */
391
+ interface PasskeyRegisterResult {
392
+ id: string;
393
+ friendly_name: string;
394
+ recovery_codes?: string[];
381
395
  }
382
396
  interface SessionInfo {
383
397
  id: string;
@@ -1504,6 +1518,11 @@ interface AuraClientOptions {
1504
1518
  * Défaut : `true` en navigateur, no-op hors navigateur (SSR/Node).
1505
1519
  */
1506
1520
  detectSessionInUrl?: boolean;
1521
+ /**
1522
+ * AUTH-015 — flux OAuth par défaut de `signInWithOAuth` pour ce client (`'pkce'` recommandé
1523
+ * en navigateur). Une option `flowType` passée à l'appel reste prioritaire.
1524
+ */
1525
+ flowType?: 'pkce' | 'implicit';
1507
1526
  };
1508
1527
  fetch?: typeof globalThis.fetch;
1509
1528
  /**
@@ -1787,7 +1806,7 @@ interface AdminUpdateUserRequest {
1787
1806
  mfa_enabled?: boolean;
1788
1807
  revoke_sessions?: boolean;
1789
1808
  }
1790
- type GenerateLinkType = 'magic' | 'recovery' | 'invite';
1809
+ type GenerateLinkType = 'signup' | 'magic' | 'recovery' | 'invite';
1791
1810
  interface GenerateLinkResult {
1792
1811
  link: string;
1793
1812
  token: string;
@@ -2067,10 +2086,15 @@ declare class LocalAuthStore extends BaseAuthStore {
2067
2086
  /**
2068
2087
  * Populate the store from a raw `Cookie` header string (server-side).
2069
2088
  * Looks for the key matching `this.key`.
2089
+ *
2090
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
2091
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
2070
2092
  */
2071
2093
  loadFromCookie(cookieString: string): void;
2072
2094
  /**
2073
- * Serialize current auth state into a `Set-Cookie` value.
2095
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
2096
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
2097
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
2074
2098
  */
2075
2099
  exportToCookie(options?: CookieOptions): string;
2076
2100
  private _getStorage;
@@ -2079,4 +2103,4 @@ declare class LocalAuthStore extends BaseAuthStore {
2079
2103
  private _removeStorage;
2080
2104
  }
2081
2105
 
2082
- export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
2106
+ export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaFactorType, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasskeyInfo, type PasskeyRegisterResult, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * - storage/path.ts : invalid_path
15
15
  * - db/QueryBuilder.ts: PGRST116 (parité PostgREST : `.single()` sur 0/plusieurs lignes)
16
16
  */
17
- type AuraErrorCode = 'NO_SESSION' | 'TIMEOUT' | 'NETWORK_ERROR' | 'INVALID_RESPONSE' | 'REFRESH_DISCARDED' | 'UNVERIFIABLE_TOKEN' | 'NO_CODE_VERIFIER' | 'PKCE_GENERATION_FAILED' | 'MISSING_EMAIL' | 'JWKS_FETCH_FAILED' | 'SIGNATURE_INVALID' | 'TOKEN_EXPIRED' | 'TOKEN_NOT_YET_VALID' | 'INVALID_JWT' | 'UNSUPPORTED_ALG' | 'NO_MATCHING_KEY' | 'INVALID_ISSUER' | 'INVALID_AUDIENCE' | 'INVALID_PATH' | 'PGRST116' | 'INVALID_CREDENTIALS' | 'WEAK_PASSWORD' | 'EMAIL_ALREADY_IN_USE' | 'USER_NOT_FOUND' | 'RATE_LIMITED' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'SESSION_REVOKED' | (string & {});
17
+ type AuraErrorCode = 'NO_SESSION' | 'TIMEOUT' | 'NETWORK_ERROR' | 'INVALID_RESPONSE' | 'REFRESH_DISCARDED' | 'UNVERIFIABLE_TOKEN' | 'NO_CODE_VERIFIER' | 'PKCE_GENERATION_FAILED' | 'MISSING_EMAIL' | 'JWKS_FETCH_FAILED' | 'SIGNATURE_INVALID' | 'TOKEN_EXPIRED' | 'TOKEN_NOT_YET_VALID' | 'INVALID_JWT' | 'UNSUPPORTED_ALG' | 'NO_MATCHING_KEY' | 'INVALID_ISSUER' | 'INVALID_AUDIENCE' | 'INVALID_PATH' | 'PGRST116' | 'INVALID_CREDENTIALS' | 'WEAK_PASSWORD' | 'PASSWORD_REQUIRED' | 'EMAIL_ALREADY_IN_USE' | 'USER_NOT_FOUND' | 'USER_BANNED' | 'EMAIL_NOT_CONFIRMED' | 'RATE_LIMITED' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'SESSION_REVOKED' | 'MFA_CODE_INVALID' | 'MFA_CODE_ALREADY_USED' | 'TOTP_CODE_REUSED' | 'MFA_CHALLENGE_EXPIRED' | (string & {});
18
18
  /**
19
19
  * Structured error thrown/returned by the Aurabase SDK.
20
20
  * Mirrors the backend's `AuraError` JSON shape with semantic DX normalization.
@@ -34,6 +34,8 @@ declare class AuraError extends Error {
34
34
  error?: {
35
35
  code?: string;
36
36
  message?: string;
37
+ hint?: string;
38
+ details?: unknown;
37
39
  };
38
40
  message?: string;
39
41
  } | null, headers?: Headers | Record<string, string | null | undefined>);
@@ -203,10 +205,6 @@ interface User {
203
205
  interface Session {
204
206
  access_token: string;
205
207
  refresh_token: string;
206
- /** Alias camelCase pour parité DX Supabase/JS */
207
- accessToken?: string;
208
- /** Alias camelCase pour parité DX Supabase/JS */
209
- refreshToken?: string;
210
208
  token_type: string;
211
209
  expires_in: number;
212
210
  expires_at?: number;
@@ -217,30 +215,20 @@ interface Session {
217
215
  interface TokenPair {
218
216
  access_token: string;
219
217
  refresh_token: string;
220
- /** Alias camelCase pour parité DX Supabase/JS */
221
- accessToken?: string;
222
- /** Alias camelCase pour parité DX Supabase/JS */
223
- refreshToken?: string;
224
218
  token_type: string;
225
219
  expires_in: number;
226
220
  user: User;
227
221
  provider_token?: string | null;
228
222
  provider_refresh_token?: string | null;
229
- /** Sous-objet session pour parité DX Supabase (`data.session.access_token`). */
230
- session?: Session;
231
- mfaChallenge?: undefined;
223
+ /** Sous-objet session pour parité DX Supabase (`data.session.access_token`).
224
+ * `null` après une inscription sur un projet qui exige un e-mail vérifié (AUTH-002). */
225
+ session?: Session | null;
232
226
  }
233
227
  interface MfaChallenge {
234
228
  mfa_required: true;
235
229
  mfa_token: string;
236
230
  mfa_setup_required?: boolean;
237
231
  session?: undefined;
238
- /** Alias ergonomique aligné sur la documentation officielle */
239
- mfaChallenge?: {
240
- mfaRequired: boolean;
241
- mfaToken: string;
242
- mfaSetupRequired?: boolean;
243
- };
244
232
  }
245
233
  type LoginResponse = TokenPair | MfaChallenge;
246
234
  type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
@@ -375,9 +363,35 @@ interface MfaEnrollResponse {
375
363
  otpauth_url: string;
376
364
  secret: string;
377
365
  }
378
- interface MfaVerifyRequest {
366
+ /**
367
+ * Relève un défi MFA : exactement UN facteur parmi `code` (TOTP à 6 chiffres), `recovery_code`
368
+ * (code de secours `XXXXXXXX-XXXXXXXX`) et `sms_code` (code reçu après `auth.mfa.sms.send`).
369
+ * Pour une passkey, utilisez `auth.mfa.webauthn.verify`.
370
+ */
371
+ type MfaVerifyRequest = {
379
372
  mfa_token: string;
380
373
  code: string;
374
+ } | {
375
+ mfa_token: string;
376
+ recovery_code: string;
377
+ } | {
378
+ mfa_token: string;
379
+ sms_code: string;
380
+ };
381
+ /** Facteur MFA utilisable pour relever un défi (`auth.mfa.factors`). */
382
+ type MfaFactorType = 'totp' | 'webauthn' | 'sms';
383
+ /** Passkey WebAuthn enrôlée (`auth.mfa.webauthn.list`). */
384
+ interface PasskeyInfo {
385
+ id: string;
386
+ friendly_name: string;
387
+ created_at: string;
388
+ last_used_at: string | null;
389
+ }
390
+ /** Résultat de l'enrôlement d'une passkey. `recovery_codes` n'est présent que si cette passkey est le premier facteur du compte. */
391
+ interface PasskeyRegisterResult {
392
+ id: string;
393
+ friendly_name: string;
394
+ recovery_codes?: string[];
381
395
  }
382
396
  interface SessionInfo {
383
397
  id: string;
@@ -1504,6 +1518,11 @@ interface AuraClientOptions {
1504
1518
  * Défaut : `true` en navigateur, no-op hors navigateur (SSR/Node).
1505
1519
  */
1506
1520
  detectSessionInUrl?: boolean;
1521
+ /**
1522
+ * AUTH-015 — flux OAuth par défaut de `signInWithOAuth` pour ce client (`'pkce'` recommandé
1523
+ * en navigateur). Une option `flowType` passée à l'appel reste prioritaire.
1524
+ */
1525
+ flowType?: 'pkce' | 'implicit';
1507
1526
  };
1508
1527
  fetch?: typeof globalThis.fetch;
1509
1528
  /**
@@ -1787,7 +1806,7 @@ interface AdminUpdateUserRequest {
1787
1806
  mfa_enabled?: boolean;
1788
1807
  revoke_sessions?: boolean;
1789
1808
  }
1790
- type GenerateLinkType = 'magic' | 'recovery' | 'invite';
1809
+ type GenerateLinkType = 'signup' | 'magic' | 'recovery' | 'invite';
1791
1810
  interface GenerateLinkResult {
1792
1811
  link: string;
1793
1812
  token: string;
@@ -2067,10 +2086,15 @@ declare class LocalAuthStore extends BaseAuthStore {
2067
2086
  /**
2068
2087
  * Populate the store from a raw `Cookie` header string (server-side).
2069
2088
  * Looks for the key matching `this.key`.
2089
+ *
2090
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
2091
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
2070
2092
  */
2071
2093
  loadFromCookie(cookieString: string): void;
2072
2094
  /**
2073
- * Serialize current auth state into a `Set-Cookie` value.
2095
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
2096
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
2097
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
2074
2098
  */
2075
2099
  exportToCookie(options?: CookieOptions): string;
2076
2100
  private _getStorage;
@@ -2079,4 +2103,4 @@ declare class LocalAuthStore extends BaseAuthStore {
2079
2103
  private _removeStorage;
2080
2104
  }
2081
2105
 
2082
- export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
2106
+ export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaFactorType, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasskeyInfo, type PasskeyRegisterResult, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
package/dist/index.js CHANGED
@@ -88,17 +88,17 @@ var AuraError = class _AuraError extends Error {
88
88
  this.code = canonical;
89
89
  } else if (status === 429) {
90
90
  this.code = "RATE_LIMITED";
91
- } else if (status === 401 && (lowerMsg.includes("identifiants") || lowerMsg.includes("credentials") || lowerMsg.includes("mot de passe incorrect"))) {
91
+ } else if (status === 401 && lowerMsg.includes("credentials")) {
92
92
  this.code = "INVALID_CREDENTIALS";
93
- } else if (status === 401 && (lowerMsg.includes("r\xE9voqu\xE9e") || lowerMsg.includes("revoked"))) {
93
+ } else if (status === 401 && lowerMsg.includes("revoked")) {
94
94
  this.code = "SESSION_REVOKED";
95
- } else if (status === 401 && (lowerMsg.includes("expir\xE9") || lowerMsg.includes("expired"))) {
95
+ } else if (status === 401 && lowerMsg.includes("expired")) {
96
96
  this.code = "SESSION_EXPIRED";
97
- } else if (status === 400 && (lowerMsg.includes("mot de passe") || lowerMsg.includes("password"))) {
97
+ } else if (status === 400 && lowerMsg.includes("password")) {
98
98
  this.code = "WEAK_PASSWORD";
99
- } else if (status === 409 && (lowerMsg.includes("d\xE9j\xE0 utilis\xE9") || lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
99
+ } else if (status === 409 && (lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
100
100
  this.code = "EMAIL_ALREADY_IN_USE";
101
- } else if (status === 404 && (lowerMsg.includes("utilisateur") || lowerMsg.includes("user not found"))) {
101
+ } else if (status === 404 && lowerMsg.includes("user not found")) {
102
102
  this.code = "USER_NOT_FOUND";
103
103
  } else {
104
104
  this.code = canonical ?? `HTTP_${status}`;
@@ -290,6 +290,24 @@ function decodeJwtPayload(token) {
290
290
  return null;
291
291
  }
292
292
  }
293
+ function userFromAccessToken(token) {
294
+ const c = decodeJwtPayload(token);
295
+ if (!c || typeof c.sub !== "string") return null;
296
+ const meta = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
297
+ const amr = Array.isArray(c.amr) ? c.amr : [];
298
+ return {
299
+ id: c.sub,
300
+ email: typeof c.email === "string" ? c.email : null,
301
+ role: "authenticated",
302
+ email_verified: false,
303
+ is_banned: false,
304
+ is_anonymous: amr.some((a) => a?.method === "anonymous"),
305
+ mfa_enabled: c.aal === "aal2",
306
+ user_metadata: meta(c.user_metadata),
307
+ app_metadata: meta(c.app_metadata),
308
+ created_at: ""
309
+ };
310
+ }
293
311
  function isTokenExpired(token, marginSec = 0) {
294
312
  const payload = decodeJwtPayload(token);
295
313
  if (!payload || typeof payload.exp !== "number") return true;
@@ -981,6 +999,9 @@ var LocalAuthStore = class extends BaseAuthStore {
981
999
  /**
982
1000
  * Populate the store from a raw `Cookie` header string (server-side).
983
1001
  * Looks for the key matching `this.key`.
1002
+ *
1003
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
1004
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
984
1005
  */
985
1006
  loadFromCookie(cookieString) {
986
1007
  const prefix = `${this.key}=`;
@@ -989,20 +1010,22 @@ var LocalAuthStore = class extends BaseAuthStore {
989
1010
  try {
990
1011
  const raw = decodeURIComponent(entry.slice(prefix.length));
991
1012
  const parsed = JSON.parse(raw);
992
- if (parsed.token && parsed.refreshToken && parsed.user) {
993
- super.save(parsed.token, parsed.refreshToken, parsed.user);
1013
+ const user = parsed.token ? userFromAccessToken(parsed.token) : null;
1014
+ if (parsed.token && parsed.refreshToken && user) {
1015
+ super.save(parsed.token, parsed.refreshToken, user);
994
1016
  }
995
1017
  } catch {
996
1018
  }
997
1019
  }
998
1020
  /**
999
- * Serialize current auth state into a `Set-Cookie` value.
1021
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
1022
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
1023
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
1000
1024
  */
1001
1025
  exportToCookie(options = {}) {
1002
1026
  const data = {
1003
1027
  token: this.token,
1004
- refreshToken: this.refreshToken,
1005
- user: this.user
1028
+ refreshToken: this.refreshToken
1006
1029
  };
1007
1030
  const encoded = encodeURIComponent(JSON.stringify(data));
1008
1031
  const parts = [`${this.key}=${encoded}`];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurabase/core",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Cœur du SDK Aurabase : fetch résilient, erreurs, stores auth, types de réponse (infrastructure interne)",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",