@aurabase/core 0.5.2 → 0.5.3

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
@@ -5,15 +5,60 @@ var AuraError = class _AuraError extends Error {
5
5
  status;
6
6
  code;
7
7
  details;
8
+ retryAfter;
8
9
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
9
10
  __isAuraError = true;
10
- constructor(status, body) {
11
- const message = body?.error?.message ?? body?.message ?? `HTTP ${status}`;
12
- super(message);
11
+ constructor(status, body, headers) {
12
+ let rawMessage = body?.error?.message ?? body?.message ?? (status === 429 ? "Trop de requ\xEAtes, veuillez patienter avant de r\xE9essayer." : `HTTP ${status}`);
13
+ let retryAfterSec;
14
+ if (headers) {
15
+ const getHeader = (name) => {
16
+ if (typeof headers.get === "function") {
17
+ return headers.get(name);
18
+ }
19
+ const record = headers;
20
+ return record[name] ?? record[name.toLowerCase()];
21
+ };
22
+ const ra = getHeader("retry-after") ?? getHeader("x-ratelimit-after");
23
+ if (ra) {
24
+ const sec = parseInt(ra, 10);
25
+ if (!isNaN(sec)) {
26
+ retryAfterSec = sec;
27
+ if (status === 429) {
28
+ rawMessage = `Trop de requ\xEAtes, veuillez patienter ${sec} seconde${sec > 1 ? "s" : ""} avant de r\xE9essayer.`;
29
+ }
30
+ }
31
+ }
32
+ }
33
+ super(rawMessage);
13
34
  this.name = "AuraError";
14
35
  this.status = status;
15
- this.code = body?.error?.code ?? `http_${status}`;
16
36
  this.details = body;
37
+ if (retryAfterSec !== void 0) {
38
+ this.retryAfter = retryAfterSec;
39
+ }
40
+ const rawCode = body?.error?.code;
41
+ const lowerMsg = rawMessage.toLowerCase();
42
+ const isGenericHttpCode = typeof rawCode !== "string" || rawCode === "UNAUTHORIZED" || rawCode === "BAD_REQUEST" || rawCode === "CONFLICT" || rawCode === "RATE_LIMITED" || rawCode.startsWith("http_");
43
+ if (!isGenericHttpCode) {
44
+ this.code = rawCode;
45
+ } else if (status === 429 || rawCode === "RATE_LIMITED" || rawCode === "http_429") {
46
+ this.code = "rate_limit_exceeded";
47
+ } else if (status === 401 && (lowerMsg.includes("identifiants") || lowerMsg.includes("credentials") || lowerMsg.includes("mot de passe incorrect"))) {
48
+ this.code = "invalid_credentials";
49
+ } else if (status === 401 && lowerMsg.includes("r\xE9voqu\xE9e")) {
50
+ this.code = "session_revoked";
51
+ } else if (status === 401 && lowerMsg.includes("expir\xE9")) {
52
+ this.code = "session_expired";
53
+ } else if (status === 400 && (lowerMsg.includes("mot de passe") || lowerMsg.includes("password"))) {
54
+ this.code = "weak_password";
55
+ } else if (status === 409 && (lowerMsg.includes("d\xE9j\xE0 utilis\xE9") || lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
56
+ this.code = "email_already_in_use";
57
+ } else if (status === 404 && lowerMsg.includes("utilisateur")) {
58
+ this.code = "user_not_found";
59
+ } else {
60
+ this.code = rawCode ?? `http_${status}`;
61
+ }
17
62
  Object.setPrototypeOf(this, _AuraError.prototype);
18
63
  }
19
64
  get isNotFound() {
@@ -300,6 +345,15 @@ function unwrapEnvelope(body) {
300
345
  }
301
346
  return body;
302
347
  }
348
+ function parseContentRangeTotal(headerVal) {
349
+ if (!headerVal) return void 0;
350
+ const parts = headerVal.split("/");
351
+ if (parts.length === 2 && parts[1] !== "*") {
352
+ const n = parseInt(parts[1], 10);
353
+ if (!Number.isNaN(n)) return n;
354
+ }
355
+ return void 0;
356
+ }
303
357
  async function readTextBounded(res, timeoutMs) {
304
358
  const body = res.body;
305
359
  if (!body || typeof body.getReader !== "function" || !(timeoutMs > 0)) {
@@ -648,11 +702,12 @@ async function fetchWithAuth(url, init, client) {
648
702
  try {
649
703
  body2 = JSON.parse(errRead.text);
650
704
  } catch {
705
+ body2 = { message: errRead.text.trim() };
651
706
  }
652
707
  } else if (!errRead.ok && errRead.timedOut) {
653
708
  emitAuraEvent(client.onEvent, client.debug, { kind: "timeout", url });
654
709
  }
655
- return { data: null, error: new AuraError(res.status, body2) };
710
+ return { data: null, error: new AuraError(res.status, body2, res.headers) };
656
711
  }
657
712
  const read = await readTextBounded(res, bodyTimeoutMs);
658
713
  if (!read.ok) {
@@ -680,7 +735,11 @@ async function fetchWithAuth(url, init, client) {
680
735
  }
681
736
  const raw = read.text;
682
737
  if (raw.trim() === "") {
683
- return { data: null, error: null };
738
+ const cr2 = res.headers.get("content-range") ?? res.headers.get("Content-Range");
739
+ const totalFromCr2 = parseContentRangeTotal(cr2);
740
+ const meta2 = totalFromCr2 !== void 0 ? { total: totalFromCr2 } : void 0;
741
+ const count2 = totalFromCr2 !== void 0 ? totalFromCr2 : null;
742
+ return { data: null, error: null, meta: meta2, count: count2 };
684
743
  }
685
744
  let body;
686
745
  try {
@@ -699,11 +758,15 @@ async function fetchWithAuth(url, init, client) {
699
758
  };
700
759
  }
701
760
  const unwrapped = unwrapEnvelope(body);
702
- const meta = body !== null && typeof body === "object" && "meta" in body ? body.meta : void 0;
761
+ const cr = res.headers.get("content-range") ?? res.headers.get("Content-Range");
762
+ const totalFromCr = parseContentRangeTotal(cr);
763
+ const rawMeta = body !== null && typeof body === "object" && "meta" in body ? body.meta : void 0;
764
+ const meta = rawMeta !== void 0 ? rawMeta : totalFromCr !== void 0 ? { total: totalFromCr } : void 0;
765
+ const count = meta?.total !== void 0 ? meta.total : totalFromCr ?? null;
703
766
  if (unwrapped === null) {
704
- return { data: null, error: null, meta };
767
+ return { data: null, error: null, meta, count };
705
768
  }
706
- return { data: unwrapped, error: null, meta };
769
+ return { data: unwrapped, error: null, meta, count };
707
770
  }
708
771
  }
709
772
 
@@ -789,14 +852,15 @@ var LocalAuthStore = class extends BaseAuthStore {
789
852
  * (`clientScope`, dérivée de l'URL du projet).
790
853
  */
791
854
  _removePkceVerifiers() {
792
- if (typeof localStorage === "undefined") return;
855
+ const storage = this._getStorage();
856
+ if (!storage) return;
793
857
  try {
794
858
  const toRemove = [];
795
- for (let i = 0; i < localStorage.length; i++) {
796
- const k = localStorage.key(i);
859
+ for (let i = 0; i < storage.length; i++) {
860
+ const k = storage.key(i);
797
861
  if (k && /^aura-.*-(pkce-code-verifier|oauth-implicit-initiated)$/.test(k)) toRemove.push(k);
798
862
  }
799
- for (const k of toRemove) localStorage.removeItem(k);
863
+ for (const k of toRemove) storage.removeItem(k);
800
864
  } catch {
801
865
  this._emitStorageBlocked("removePkceVerifiers");
802
866
  }
@@ -807,17 +871,19 @@ var LocalAuthStore = class extends BaseAuthStore {
807
871
  // ne survivrait pas à ce cycle de navigation.
808
872
  setItem(key, value) {
809
873
  super.setItem(key, value);
810
- if (typeof localStorage === "undefined") return;
874
+ const storage = this._getStorage();
875
+ if (!storage) return;
811
876
  try {
812
- localStorage.setItem(key, value);
877
+ storage.setItem(key, value);
813
878
  } catch {
814
879
  this._emitStorageBlocked("setItem");
815
880
  }
816
881
  }
817
882
  getItem(key) {
818
- if (typeof localStorage === "undefined") return super.getItem(key);
883
+ const storage = this._getStorage();
884
+ if (!storage) return super.getItem(key);
819
885
  try {
820
- const v = localStorage.getItem(key);
886
+ const v = storage.getItem(key);
821
887
  if (v !== null) return v;
822
888
  } catch {
823
889
  this._emitStorageBlocked("getItem");
@@ -826,9 +892,10 @@ var LocalAuthStore = class extends BaseAuthStore {
826
892
  }
827
893
  removeItem(key) {
828
894
  super.removeItem(key);
829
- if (typeof localStorage === "undefined") return;
895
+ const storage = this._getStorage();
896
+ if (!storage) return;
830
897
  try {
831
- localStorage.removeItem(key);
898
+ storage.removeItem(key);
832
899
  } catch {
833
900
  this._emitStorageBlocked("removeItem");
834
901
  }
@@ -871,10 +938,40 @@ var LocalAuthStore = class extends BaseAuthStore {
871
938
  return parts.join("; ");
872
939
  }
873
940
  // -- Private ----------------------------------------------------------------
941
+ _getStorage() {
942
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
943
+ return window.localStorage;
944
+ }
945
+ const g = globalThis;
946
+ if (typeof g !== "undefined") {
947
+ const proc = g.process;
948
+ if (typeof proc !== "undefined") {
949
+ const env = proc.env;
950
+ const isTest = !!(env?.VITEST || env?.NODE_ENV === "test" || env?.JEST_WORKER_ID);
951
+ const execArgv = proc.execArgv;
952
+ const hasFlag = Array.isArray(execArgv) && execArgv.some((a) => typeof a === "string" && a.startsWith("--localstorage-file"));
953
+ if (isTest || hasFlag) {
954
+ try {
955
+ const s = g.localStorage;
956
+ if (s && typeof s.getItem === "function") return s;
957
+ } catch {
958
+ }
959
+ }
960
+ return null;
961
+ }
962
+ try {
963
+ const s = g.localStorage;
964
+ if (s && typeof s.getItem === "function") return s;
965
+ } catch {
966
+ }
967
+ }
968
+ return null;
969
+ }
874
970
  _loadFromStorage() {
875
- if (typeof localStorage === "undefined") return;
971
+ const storage = this._getStorage();
972
+ if (!storage) return;
876
973
  try {
877
- const raw = localStorage.getItem(this.key);
974
+ const raw = storage.getItem(this.key);
878
975
  if (!raw) return;
879
976
  const parsed = JSON.parse(raw);
880
977
  if (parsed.token && parsed.refreshToken && parsed.user) {
@@ -885,22 +982,24 @@ var LocalAuthStore = class extends BaseAuthStore {
885
982
  }
886
983
  }
887
984
  _persist() {
888
- if (typeof localStorage === "undefined") return;
985
+ const storage = this._getStorage();
986
+ if (!storage) return;
889
987
  const data = {
890
988
  token: this.token,
891
989
  refreshToken: this.refreshToken,
892
990
  user: this.user
893
991
  };
894
992
  try {
895
- localStorage.setItem(this.key, JSON.stringify(data));
993
+ storage.setItem(this.key, JSON.stringify(data));
896
994
  } catch {
897
995
  this._emitStorageBlocked("persist");
898
996
  }
899
997
  }
900
998
  _removeStorage() {
901
- if (typeof localStorage === "undefined") return;
999
+ const storage = this._getStorage();
1000
+ if (!storage) return;
902
1001
  try {
903
- localStorage.removeItem(this.key);
1002
+ storage.removeItem(this.key);
904
1003
  } catch {
905
1004
  this._emitStorageBlocked("removeStorage");
906
1005
  }
package/dist/index.d.cts CHANGED
@@ -14,15 +14,16 @@
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' | (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' | 'email_already_in_use' | 'user_not_found' | 'rate_limit_exceeded' | 'session_expired' | 'session_revoked' | (string & {});
18
18
  /**
19
19
  * Structured error thrown/returned by the Aurabase SDK.
20
- * Mirrors the backend's `AuraError` JSON shape.
20
+ * Mirrors the backend's `AuraError` JSON shape with semantic DX normalization.
21
21
  */
22
22
  declare class AuraError extends Error {
23
23
  readonly status: number;
24
24
  readonly code: AuraErrorCode;
25
25
  readonly details: unknown;
26
+ readonly retryAfter?: number;
26
27
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
27
28
  protected readonly __isAuraError = true;
28
29
  constructor(status: number, body?: {
@@ -31,7 +32,7 @@ declare class AuraError extends Error {
31
32
  message?: string;
32
33
  };
33
34
  message?: string;
34
- } | null);
35
+ } | null, headers?: Headers | Record<string, string | null | undefined>);
35
36
  get isNotFound(): boolean;
36
37
  get isUnauthorized(): boolean;
37
38
  get isForbidden(): boolean;
@@ -93,6 +94,11 @@ interface AuraSuccess<T> {
93
94
  data: T;
94
95
  error: null;
95
96
  meta?: Meta;
97
+ /**
98
+ * Nombre total de lignes correspondant à la requête (dérivé de meta.total).
99
+ * Renseigné quand un décompte explicite est demandé (.count('exact' | ...)).
100
+ */
101
+ count?: number | null;
96
102
  }
97
103
  /**
98
104
  * Réponse en SUCCÈS SANS contenu — `data` ET `error` nuls.
@@ -117,6 +123,10 @@ interface AuraNoContent {
117
123
  data: null;
118
124
  error: null;
119
125
  meta?: Meta;
126
+ /**
127
+ * Nombre total de lignes (dérivé de meta.total).
128
+ */
129
+ count?: number | null;
120
130
  }
121
131
  /**
122
132
  * Réponse en ÉCHEC. `data` y est `null` par construction — aucun producteur du
@@ -126,6 +136,7 @@ interface AuraFailure {
126
136
  data: null;
127
137
  error: AuraError;
128
138
  meta?: Meta;
139
+ count?: number | null;
129
140
  }
130
141
  /**
131
142
  * Enveloppe de réponse du SDK : union à TROIS membres.
@@ -175,19 +186,47 @@ interface User {
175
186
  created_at: string;
176
187
  last_sign_in_at?: string | null;
177
188
  }
189
+ interface Session {
190
+ access_token: string;
191
+ refresh_token: string;
192
+ /** Alias camelCase pour parité DX Supabase/JS */
193
+ accessToken?: string;
194
+ /** Alias camelCase pour parité DX Supabase/JS */
195
+ refreshToken?: string;
196
+ token_type: string;
197
+ expires_in: number;
198
+ expires_at?: number;
199
+ user: User;
200
+ provider_token?: string | null;
201
+ provider_refresh_token?: string | null;
202
+ }
178
203
  interface TokenPair {
179
204
  access_token: string;
180
205
  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;
181
210
  token_type: string;
182
211
  expires_in: number;
183
212
  user: User;
184
213
  provider_token?: string | null;
185
214
  provider_refresh_token?: string | null;
215
+ /** Sous-objet session pour parité DX Supabase (`data.session.access_token`). */
216
+ session?: Session;
217
+ mfaChallenge?: undefined;
186
218
  }
187
219
  interface MfaChallenge {
188
220
  mfa_required: true;
189
221
  mfa_token: string;
190
222
  mfa_setup_required?: boolean;
223
+ session?: undefined;
224
+ /** Alias ergonomique aligné sur la documentation officielle */
225
+ mfaChallenge?: {
226
+ mfaRequired: boolean;
227
+ mfaToken: string;
228
+ mfaSetupRequired?: boolean;
229
+ };
191
230
  }
192
231
  type LoginResponse = TokenPair | MfaChallenge;
193
232
  type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
@@ -204,6 +243,8 @@ interface AuthChangePayload {
204
243
  event: AuthEvent;
205
244
  user: User | null;
206
245
  accessToken: string | null;
246
+ /** Session complète pour parité DX Supabase */
247
+ session?: Session | null;
207
248
  /** Présent uniquement si `event === 'MFA_CHALLENGE'`. */
208
249
  mfaToken?: string;
209
250
  /** Présent uniquement si `event === 'MFA_CHALLENGE'`. */
@@ -1771,9 +1812,10 @@ declare class LocalAuthStore extends BaseAuthStore {
1771
1812
  * Serialize current auth state into a `Set-Cookie` value.
1772
1813
  */
1773
1814
  exportToCookie(options?: CookieOptions): string;
1815
+ private _getStorage;
1774
1816
  private _loadFromStorage;
1775
1817
  private _persist;
1776
1818
  private _removeStorage;
1777
1819
  }
1778
1820
 
1779
- export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, 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 CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, 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 NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationStats, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeEvent, type RealtimeListenType, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationRequest, type SerializeCookieOptions, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type SessionInfo, type SignInRequest, type SignUpRequest, type StorageBucket, type SubscribeCallback, type TokenPair, type UpdateUserRequest, type UploadResult, type User, type UserStats, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
1821
+ export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, 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 CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, 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 NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationStats, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeEvent, type RealtimeListenType, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationRequest, type SerializeCookieOptions, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SignInRequest, type SignUpRequest, type StorageBucket, type SubscribeCallback, type TokenPair, type UpdateUserRequest, type UploadResult, type User, type UserStats, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
package/dist/index.d.ts CHANGED
@@ -14,15 +14,16 @@
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' | (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' | 'email_already_in_use' | 'user_not_found' | 'rate_limit_exceeded' | 'session_expired' | 'session_revoked' | (string & {});
18
18
  /**
19
19
  * Structured error thrown/returned by the Aurabase SDK.
20
- * Mirrors the backend's `AuraError` JSON shape.
20
+ * Mirrors the backend's `AuraError` JSON shape with semantic DX normalization.
21
21
  */
22
22
  declare class AuraError extends Error {
23
23
  readonly status: number;
24
24
  readonly code: AuraErrorCode;
25
25
  readonly details: unknown;
26
+ readonly retryAfter?: number;
26
27
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
27
28
  protected readonly __isAuraError = true;
28
29
  constructor(status: number, body?: {
@@ -31,7 +32,7 @@ declare class AuraError extends Error {
31
32
  message?: string;
32
33
  };
33
34
  message?: string;
34
- } | null);
35
+ } | null, headers?: Headers | Record<string, string | null | undefined>);
35
36
  get isNotFound(): boolean;
36
37
  get isUnauthorized(): boolean;
37
38
  get isForbidden(): boolean;
@@ -93,6 +94,11 @@ interface AuraSuccess<T> {
93
94
  data: T;
94
95
  error: null;
95
96
  meta?: Meta;
97
+ /**
98
+ * Nombre total de lignes correspondant à la requête (dérivé de meta.total).
99
+ * Renseigné quand un décompte explicite est demandé (.count('exact' | ...)).
100
+ */
101
+ count?: number | null;
96
102
  }
97
103
  /**
98
104
  * Réponse en SUCCÈS SANS contenu — `data` ET `error` nuls.
@@ -117,6 +123,10 @@ interface AuraNoContent {
117
123
  data: null;
118
124
  error: null;
119
125
  meta?: Meta;
126
+ /**
127
+ * Nombre total de lignes (dérivé de meta.total).
128
+ */
129
+ count?: number | null;
120
130
  }
121
131
  /**
122
132
  * Réponse en ÉCHEC. `data` y est `null` par construction — aucun producteur du
@@ -126,6 +136,7 @@ interface AuraFailure {
126
136
  data: null;
127
137
  error: AuraError;
128
138
  meta?: Meta;
139
+ count?: number | null;
129
140
  }
130
141
  /**
131
142
  * Enveloppe de réponse du SDK : union à TROIS membres.
@@ -175,19 +186,47 @@ interface User {
175
186
  created_at: string;
176
187
  last_sign_in_at?: string | null;
177
188
  }
189
+ interface Session {
190
+ access_token: string;
191
+ refresh_token: string;
192
+ /** Alias camelCase pour parité DX Supabase/JS */
193
+ accessToken?: string;
194
+ /** Alias camelCase pour parité DX Supabase/JS */
195
+ refreshToken?: string;
196
+ token_type: string;
197
+ expires_in: number;
198
+ expires_at?: number;
199
+ user: User;
200
+ provider_token?: string | null;
201
+ provider_refresh_token?: string | null;
202
+ }
178
203
  interface TokenPair {
179
204
  access_token: string;
180
205
  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;
181
210
  token_type: string;
182
211
  expires_in: number;
183
212
  user: User;
184
213
  provider_token?: string | null;
185
214
  provider_refresh_token?: string | null;
215
+ /** Sous-objet session pour parité DX Supabase (`data.session.access_token`). */
216
+ session?: Session;
217
+ mfaChallenge?: undefined;
186
218
  }
187
219
  interface MfaChallenge {
188
220
  mfa_required: true;
189
221
  mfa_token: string;
190
222
  mfa_setup_required?: boolean;
223
+ session?: undefined;
224
+ /** Alias ergonomique aligné sur la documentation officielle */
225
+ mfaChallenge?: {
226
+ mfaRequired: boolean;
227
+ mfaToken: string;
228
+ mfaSetupRequired?: boolean;
229
+ };
191
230
  }
192
231
  type LoginResponse = TokenPair | MfaChallenge;
193
232
  type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
@@ -204,6 +243,8 @@ interface AuthChangePayload {
204
243
  event: AuthEvent;
205
244
  user: User | null;
206
245
  accessToken: string | null;
246
+ /** Session complète pour parité DX Supabase */
247
+ session?: Session | null;
207
248
  /** Présent uniquement si `event === 'MFA_CHALLENGE'`. */
208
249
  mfaToken?: string;
209
250
  /** Présent uniquement si `event === 'MFA_CHALLENGE'`. */
@@ -1771,9 +1812,10 @@ declare class LocalAuthStore extends BaseAuthStore {
1771
1812
  * Serialize current auth state into a `Set-Cookie` value.
1772
1813
  */
1773
1814
  exportToCookie(options?: CookieOptions): string;
1815
+ private _getStorage;
1774
1816
  private _loadFromStorage;
1775
1817
  private _persist;
1776
1818
  private _removeStorage;
1777
1819
  }
1778
1820
 
1779
- export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, 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 CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, 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 NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationStats, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeEvent, type RealtimeListenType, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationRequest, type SerializeCookieOptions, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type SessionInfo, type SignInRequest, type SignUpRequest, type StorageBucket, type SubscribeCallback, type TokenPair, type UpdateUserRequest, type UploadResult, type User, type UserStats, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
1821
+ export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, 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 CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, 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 NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationStats, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeEvent, type RealtimeListenType, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationRequest, type SerializeCookieOptions, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SignInRequest, type SignUpRequest, type StorageBucket, type SubscribeCallback, type TokenPair, type UpdateUserRequest, type UploadResult, type User, type UserStats, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
package/dist/index.js CHANGED
@@ -3,15 +3,60 @@ var AuraError = class _AuraError extends Error {
3
3
  status;
4
4
  code;
5
5
  details;
6
+ retryAfter;
6
7
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
7
8
  __isAuraError = true;
8
- constructor(status, body) {
9
- const message = body?.error?.message ?? body?.message ?? `HTTP ${status}`;
10
- super(message);
9
+ constructor(status, body, headers) {
10
+ let rawMessage = body?.error?.message ?? body?.message ?? (status === 429 ? "Trop de requ\xEAtes, veuillez patienter avant de r\xE9essayer." : `HTTP ${status}`);
11
+ let retryAfterSec;
12
+ if (headers) {
13
+ const getHeader = (name) => {
14
+ if (typeof headers.get === "function") {
15
+ return headers.get(name);
16
+ }
17
+ const record = headers;
18
+ return record[name] ?? record[name.toLowerCase()];
19
+ };
20
+ const ra = getHeader("retry-after") ?? getHeader("x-ratelimit-after");
21
+ if (ra) {
22
+ const sec = parseInt(ra, 10);
23
+ if (!isNaN(sec)) {
24
+ retryAfterSec = sec;
25
+ if (status === 429) {
26
+ rawMessage = `Trop de requ\xEAtes, veuillez patienter ${sec} seconde${sec > 1 ? "s" : ""} avant de r\xE9essayer.`;
27
+ }
28
+ }
29
+ }
30
+ }
31
+ super(rawMessage);
11
32
  this.name = "AuraError";
12
33
  this.status = status;
13
- this.code = body?.error?.code ?? `http_${status}`;
14
34
  this.details = body;
35
+ if (retryAfterSec !== void 0) {
36
+ this.retryAfter = retryAfterSec;
37
+ }
38
+ const rawCode = body?.error?.code;
39
+ const lowerMsg = rawMessage.toLowerCase();
40
+ const isGenericHttpCode = typeof rawCode !== "string" || rawCode === "UNAUTHORIZED" || rawCode === "BAD_REQUEST" || rawCode === "CONFLICT" || rawCode === "RATE_LIMITED" || rawCode.startsWith("http_");
41
+ if (!isGenericHttpCode) {
42
+ this.code = rawCode;
43
+ } else if (status === 429 || rawCode === "RATE_LIMITED" || rawCode === "http_429") {
44
+ this.code = "rate_limit_exceeded";
45
+ } else if (status === 401 && (lowerMsg.includes("identifiants") || lowerMsg.includes("credentials") || lowerMsg.includes("mot de passe incorrect"))) {
46
+ this.code = "invalid_credentials";
47
+ } else if (status === 401 && lowerMsg.includes("r\xE9voqu\xE9e")) {
48
+ this.code = "session_revoked";
49
+ } else if (status === 401 && lowerMsg.includes("expir\xE9")) {
50
+ this.code = "session_expired";
51
+ } else if (status === 400 && (lowerMsg.includes("mot de passe") || lowerMsg.includes("password"))) {
52
+ this.code = "weak_password";
53
+ } else if (status === 409 && (lowerMsg.includes("d\xE9j\xE0 utilis\xE9") || lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
54
+ this.code = "email_already_in_use";
55
+ } else if (status === 404 && lowerMsg.includes("utilisateur")) {
56
+ this.code = "user_not_found";
57
+ } else {
58
+ this.code = rawCode ?? `http_${status}`;
59
+ }
15
60
  Object.setPrototypeOf(this, _AuraError.prototype);
16
61
  }
17
62
  get isNotFound() {
@@ -298,6 +343,15 @@ function unwrapEnvelope(body) {
298
343
  }
299
344
  return body;
300
345
  }
346
+ function parseContentRangeTotal(headerVal) {
347
+ if (!headerVal) return void 0;
348
+ const parts = headerVal.split("/");
349
+ if (parts.length === 2 && parts[1] !== "*") {
350
+ const n = parseInt(parts[1], 10);
351
+ if (!Number.isNaN(n)) return n;
352
+ }
353
+ return void 0;
354
+ }
301
355
  async function readTextBounded(res, timeoutMs) {
302
356
  const body = res.body;
303
357
  if (!body || typeof body.getReader !== "function" || !(timeoutMs > 0)) {
@@ -646,11 +700,12 @@ async function fetchWithAuth(url, init, client) {
646
700
  try {
647
701
  body2 = JSON.parse(errRead.text);
648
702
  } catch {
703
+ body2 = { message: errRead.text.trim() };
649
704
  }
650
705
  } else if (!errRead.ok && errRead.timedOut) {
651
706
  emitAuraEvent(client.onEvent, client.debug, { kind: "timeout", url });
652
707
  }
653
- return { data: null, error: new AuraError(res.status, body2) };
708
+ return { data: null, error: new AuraError(res.status, body2, res.headers) };
654
709
  }
655
710
  const read = await readTextBounded(res, bodyTimeoutMs);
656
711
  if (!read.ok) {
@@ -678,7 +733,11 @@ async function fetchWithAuth(url, init, client) {
678
733
  }
679
734
  const raw = read.text;
680
735
  if (raw.trim() === "") {
681
- return { data: null, error: null };
736
+ const cr2 = res.headers.get("content-range") ?? res.headers.get("Content-Range");
737
+ const totalFromCr2 = parseContentRangeTotal(cr2);
738
+ const meta2 = totalFromCr2 !== void 0 ? { total: totalFromCr2 } : void 0;
739
+ const count2 = totalFromCr2 !== void 0 ? totalFromCr2 : null;
740
+ return { data: null, error: null, meta: meta2, count: count2 };
682
741
  }
683
742
  let body;
684
743
  try {
@@ -697,11 +756,15 @@ async function fetchWithAuth(url, init, client) {
697
756
  };
698
757
  }
699
758
  const unwrapped = unwrapEnvelope(body);
700
- const meta = body !== null && typeof body === "object" && "meta" in body ? body.meta : void 0;
759
+ const cr = res.headers.get("content-range") ?? res.headers.get("Content-Range");
760
+ const totalFromCr = parseContentRangeTotal(cr);
761
+ const rawMeta = body !== null && typeof body === "object" && "meta" in body ? body.meta : void 0;
762
+ const meta = rawMeta !== void 0 ? rawMeta : totalFromCr !== void 0 ? { total: totalFromCr } : void 0;
763
+ const count = meta?.total !== void 0 ? meta.total : totalFromCr ?? null;
701
764
  if (unwrapped === null) {
702
- return { data: null, error: null, meta };
765
+ return { data: null, error: null, meta, count };
703
766
  }
704
- return { data: unwrapped, error: null, meta };
767
+ return { data: unwrapped, error: null, meta, count };
705
768
  }
706
769
  }
707
770
 
@@ -787,14 +850,15 @@ var LocalAuthStore = class extends BaseAuthStore {
787
850
  * (`clientScope`, dérivée de l'URL du projet).
788
851
  */
789
852
  _removePkceVerifiers() {
790
- if (typeof localStorage === "undefined") return;
853
+ const storage = this._getStorage();
854
+ if (!storage) return;
791
855
  try {
792
856
  const toRemove = [];
793
- for (let i = 0; i < localStorage.length; i++) {
794
- const k = localStorage.key(i);
857
+ for (let i = 0; i < storage.length; i++) {
858
+ const k = storage.key(i);
795
859
  if (k && /^aura-.*-(pkce-code-verifier|oauth-implicit-initiated)$/.test(k)) toRemove.push(k);
796
860
  }
797
- for (const k of toRemove) localStorage.removeItem(k);
861
+ for (const k of toRemove) storage.removeItem(k);
798
862
  } catch {
799
863
  this._emitStorageBlocked("removePkceVerifiers");
800
864
  }
@@ -805,17 +869,19 @@ var LocalAuthStore = class extends BaseAuthStore {
805
869
  // ne survivrait pas à ce cycle de navigation.
806
870
  setItem(key, value) {
807
871
  super.setItem(key, value);
808
- if (typeof localStorage === "undefined") return;
872
+ const storage = this._getStorage();
873
+ if (!storage) return;
809
874
  try {
810
- localStorage.setItem(key, value);
875
+ storage.setItem(key, value);
811
876
  } catch {
812
877
  this._emitStorageBlocked("setItem");
813
878
  }
814
879
  }
815
880
  getItem(key) {
816
- if (typeof localStorage === "undefined") return super.getItem(key);
881
+ const storage = this._getStorage();
882
+ if (!storage) return super.getItem(key);
817
883
  try {
818
- const v = localStorage.getItem(key);
884
+ const v = storage.getItem(key);
819
885
  if (v !== null) return v;
820
886
  } catch {
821
887
  this._emitStorageBlocked("getItem");
@@ -824,9 +890,10 @@ var LocalAuthStore = class extends BaseAuthStore {
824
890
  }
825
891
  removeItem(key) {
826
892
  super.removeItem(key);
827
- if (typeof localStorage === "undefined") return;
893
+ const storage = this._getStorage();
894
+ if (!storage) return;
828
895
  try {
829
- localStorage.removeItem(key);
896
+ storage.removeItem(key);
830
897
  } catch {
831
898
  this._emitStorageBlocked("removeItem");
832
899
  }
@@ -869,10 +936,40 @@ var LocalAuthStore = class extends BaseAuthStore {
869
936
  return parts.join("; ");
870
937
  }
871
938
  // -- Private ----------------------------------------------------------------
939
+ _getStorage() {
940
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
941
+ return window.localStorage;
942
+ }
943
+ const g = globalThis;
944
+ if (typeof g !== "undefined") {
945
+ const proc = g.process;
946
+ if (typeof proc !== "undefined") {
947
+ const env = proc.env;
948
+ const isTest = !!(env?.VITEST || env?.NODE_ENV === "test" || env?.JEST_WORKER_ID);
949
+ const execArgv = proc.execArgv;
950
+ const hasFlag = Array.isArray(execArgv) && execArgv.some((a) => typeof a === "string" && a.startsWith("--localstorage-file"));
951
+ if (isTest || hasFlag) {
952
+ try {
953
+ const s = g.localStorage;
954
+ if (s && typeof s.getItem === "function") return s;
955
+ } catch {
956
+ }
957
+ }
958
+ return null;
959
+ }
960
+ try {
961
+ const s = g.localStorage;
962
+ if (s && typeof s.getItem === "function") return s;
963
+ } catch {
964
+ }
965
+ }
966
+ return null;
967
+ }
872
968
  _loadFromStorage() {
873
- if (typeof localStorage === "undefined") return;
969
+ const storage = this._getStorage();
970
+ if (!storage) return;
874
971
  try {
875
- const raw = localStorage.getItem(this.key);
972
+ const raw = storage.getItem(this.key);
876
973
  if (!raw) return;
877
974
  const parsed = JSON.parse(raw);
878
975
  if (parsed.token && parsed.refreshToken && parsed.user) {
@@ -883,22 +980,24 @@ var LocalAuthStore = class extends BaseAuthStore {
883
980
  }
884
981
  }
885
982
  _persist() {
886
- if (typeof localStorage === "undefined") return;
983
+ const storage = this._getStorage();
984
+ if (!storage) return;
887
985
  const data = {
888
986
  token: this.token,
889
987
  refreshToken: this.refreshToken,
890
988
  user: this.user
891
989
  };
892
990
  try {
893
- localStorage.setItem(this.key, JSON.stringify(data));
991
+ storage.setItem(this.key, JSON.stringify(data));
894
992
  } catch {
895
993
  this._emitStorageBlocked("persist");
896
994
  }
897
995
  }
898
996
  _removeStorage() {
899
- if (typeof localStorage === "undefined") return;
997
+ const storage = this._getStorage();
998
+ if (!storage) return;
900
999
  try {
901
- localStorage.removeItem(this.key);
1000
+ storage.removeItem(this.key);
902
1001
  } catch {
903
1002
  this._emitStorageBlocked("removeStorage");
904
1003
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurabase/core",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
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",