@aurabase/core 0.5.1 → 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/README.md +2 -2
- package/dist/index.cjs +124 -25
- package/dist/index.d.cts +46 -4
- package/dist/index.d.ts +46 -4
- package/dist/index.js +124 -25
- package/package.json +8 -9
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ Cœur d'infrastructure du SDK Aurabase : type de réponse (`AuraResponse`), erre
|
|
|
4
4
|
|
|
5
5
|
 
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> Publié sur npm : [`@aurabase/core`](https://www.npmjs.com/package/@aurabase/core).
|
|
8
8
|
|
|
9
|
-
Fait partie du SDK **[aurabase](../aurabase)**. Installé automatiquement comme dépendance transitive de tous les autres packages `@aurabase/*` ; ce package n'est utile en installation directe que pour écrire une extension ou un client alternatif (voir Usage).
|
|
9
|
+
Fait partie du SDK **[@aurabase/aurabase-js](../aurabase)**. Installé automatiquement comme dépendance transitive de tous les autres packages `@aurabase/*` ; ce package n'est utile en installation directe que pour écrire une extension ou un client alternatif (voir Usage).
|
|
10
10
|
|
|
11
11
|
Ce README s'adresse aux **auteurs d'extensions** (service additionnel, client SSR maison) — pas aux utilisateurs finaux d'une application, qui doivent passer par le méta-package [`aurabase`](../aurabase).
|
|
12
12
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
855
|
+
const storage = this._getStorage();
|
|
856
|
+
if (!storage) return;
|
|
793
857
|
try {
|
|
794
858
|
const toRemove = [];
|
|
795
|
-
for (let i = 0; i <
|
|
796
|
-
const k =
|
|
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)
|
|
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
|
-
|
|
874
|
+
const storage = this._getStorage();
|
|
875
|
+
if (!storage) return;
|
|
811
876
|
try {
|
|
812
|
-
|
|
877
|
+
storage.setItem(key, value);
|
|
813
878
|
} catch {
|
|
814
879
|
this._emitStorageBlocked("setItem");
|
|
815
880
|
}
|
|
816
881
|
}
|
|
817
882
|
getItem(key) {
|
|
818
|
-
|
|
883
|
+
const storage = this._getStorage();
|
|
884
|
+
if (!storage) return super.getItem(key);
|
|
819
885
|
try {
|
|
820
|
-
const v =
|
|
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
|
-
|
|
895
|
+
const storage = this._getStorage();
|
|
896
|
+
if (!storage) return;
|
|
830
897
|
try {
|
|
831
|
-
|
|
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
|
-
|
|
971
|
+
const storage = this._getStorage();
|
|
972
|
+
if (!storage) return;
|
|
876
973
|
try {
|
|
877
|
-
const raw =
|
|
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
|
-
|
|
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
|
-
|
|
993
|
+
storage.setItem(this.key, JSON.stringify(data));
|
|
896
994
|
} catch {
|
|
897
995
|
this._emitStorageBlocked("persist");
|
|
898
996
|
}
|
|
899
997
|
}
|
|
900
998
|
_removeStorage() {
|
|
901
|
-
|
|
999
|
+
const storage = this._getStorage();
|
|
1000
|
+
if (!storage) return;
|
|
902
1001
|
try {
|
|
903
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
853
|
+
const storage = this._getStorage();
|
|
854
|
+
if (!storage) return;
|
|
791
855
|
try {
|
|
792
856
|
const toRemove = [];
|
|
793
|
-
for (let i = 0; i <
|
|
794
|
-
const k =
|
|
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)
|
|
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
|
-
|
|
872
|
+
const storage = this._getStorage();
|
|
873
|
+
if (!storage) return;
|
|
809
874
|
try {
|
|
810
|
-
|
|
875
|
+
storage.setItem(key, value);
|
|
811
876
|
} catch {
|
|
812
877
|
this._emitStorageBlocked("setItem");
|
|
813
878
|
}
|
|
814
879
|
}
|
|
815
880
|
getItem(key) {
|
|
816
|
-
|
|
881
|
+
const storage = this._getStorage();
|
|
882
|
+
if (!storage) return super.getItem(key);
|
|
817
883
|
try {
|
|
818
|
-
const v =
|
|
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
|
-
|
|
893
|
+
const storage = this._getStorage();
|
|
894
|
+
if (!storage) return;
|
|
828
895
|
try {
|
|
829
|
-
|
|
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
|
-
|
|
969
|
+
const storage = this._getStorage();
|
|
970
|
+
if (!storage) return;
|
|
874
971
|
try {
|
|
875
|
-
const raw =
|
|
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
|
-
|
|
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
|
-
|
|
991
|
+
storage.setItem(this.key, JSON.stringify(data));
|
|
894
992
|
} catch {
|
|
895
993
|
this._emitStorageBlocked("persist");
|
|
896
994
|
}
|
|
897
995
|
}
|
|
898
996
|
_removeStorage() {
|
|
899
|
-
|
|
997
|
+
const storage = this._getStorage();
|
|
998
|
+
if (!storage) return;
|
|
900
999
|
try {
|
|
901
|
-
|
|
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.
|
|
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",
|
|
@@ -44,18 +44,17 @@
|
|
|
44
44
|
"sdk",
|
|
45
45
|
"core"
|
|
46
46
|
],
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "20.14.15",
|
|
49
|
+
"tsup": "^8.0.0",
|
|
50
|
+
"typescript": "^5.5.0",
|
|
51
|
+
"vitest": "^4.1.6"
|
|
52
|
+
},
|
|
47
53
|
"scripts": {
|
|
48
54
|
"build": "tsup",
|
|
49
55
|
"test": "vitest run && tsc --noEmit -p tsconfig.test-d.json",
|
|
50
56
|
"test:types": "tsc --noEmit -p tsconfig.test-d.json",
|
|
51
57
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
|
|
52
|
-
"prepack": "pnpm build",
|
|
53
58
|
"typecheck:tests": "tsc --noEmit -p tsconfig.test.json"
|
|
54
|
-
},
|
|
55
|
-
"devDependencies": {
|
|
56
|
-
"@types/node": "catalog:",
|
|
57
|
-
"tsup": "catalog:",
|
|
58
|
-
"typescript": "catalog:",
|
|
59
|
-
"vitest": "catalog:"
|
|
60
59
|
}
|
|
61
|
-
}
|
|
60
|
+
}
|