@aurabase/core 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -149,7 +149,7 @@ function hydrateFromCookieHeader(cookieHeader: string) {
149
149
  const store = hydrateFromCookieHeader(`${CLE}=%7B%22token%22%3Anull%7D`)
150
150
 
151
151
  // Après une mutation de session, sérialiser l'état courant en Set-Cookie.
152
- const setCookieValue = store.exportToCookie({ path: '/', secure: true, sameSite: 'Lax', httpOnly: true })
152
+ const setCookieValue = store.exportToCookie({ path: '/', secure: true, sameSite: 'lax', httpOnly: true })
153
153
  ```
154
154
 
155
155
  `store.persistent` indique si le store survit à un redirect pleine page (`false` pour `BaseAuthStore`, `true` pour `LocalAuthStore`) — c'est ce flag que le flux OAuth PKCE utilise pour décider s'il peut stocker un `code_verifier` de façon fiable.
package/dist/index.cjs CHANGED
@@ -1,15 +1,51 @@
1
1
  'use strict';
2
2
 
3
3
  // src/AuraError.ts
4
+ var LEGACY_LOWERCASE_CODES = /* @__PURE__ */ new Set([
5
+ "NO_SESSION",
6
+ "TIMEOUT",
7
+ "NETWORK_ERROR",
8
+ "INVALID_RESPONSE",
9
+ "REFRESH_DISCARDED",
10
+ "UNVERIFIABLE_TOKEN",
11
+ "NO_CODE_VERIFIER",
12
+ "PKCE_GENERATION_FAILED",
13
+ "MISSING_EMAIL",
14
+ "JWKS_FETCH_FAILED",
15
+ "SIGNATURE_INVALID",
16
+ "TOKEN_EXPIRED",
17
+ "TOKEN_NOT_YET_VALID",
18
+ "INVALID_JWT",
19
+ "UNSUPPORTED_ALG",
20
+ "NO_MATCHING_KEY",
21
+ "INVALID_ISSUER",
22
+ "INVALID_AUDIENCE",
23
+ "INVALID_PATH",
24
+ "INVALID_CREDENTIALS",
25
+ "WEAK_PASSWORD",
26
+ "EMAIL_ALREADY_IN_USE",
27
+ "USER_NOT_FOUND",
28
+ "SESSION_EXPIRED",
29
+ "INVALID_OTP",
30
+ "SESSION_REVOKED"
31
+ ]);
32
+ function normalizeErrorCode(code) {
33
+ return code.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
34
+ }
4
35
  var AuraError = class _AuraError extends Error {
5
36
  status;
6
37
  code;
7
38
  details;
8
39
  retryAfter;
40
+ /**
41
+ * Piste de correction fournie par le serveur (ex. refus RLS : quelle politique créer). J1-010.
42
+ */
43
+ hint;
9
44
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
10
45
  __isAuraError = true;
11
46
  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}`);
47
+ const serverMessage = body?.error?.message ?? body?.message;
48
+ let rawMessage = serverMessage ?? (status === 429 ? "Too many requests, please wait before retrying." : `HTTP ${status}`);
13
49
  let retryAfterSec;
14
50
  if (headers) {
15
51
  const getHeader = (name) => {
@@ -24,8 +60,8 @@ var AuraError = class _AuraError extends Error {
24
60
  const sec = parseInt(ra, 10);
25
61
  if (!isNaN(sec)) {
26
62
  retryAfterSec = sec;
27
- if (status === 429) {
28
- rawMessage = `Trop de requ\xEAtes, veuillez patienter ${sec} seconde${sec > 1 ? "s" : ""} avant de r\xE9essayer.`;
63
+ if (status === 429 && !serverMessage) {
64
+ rawMessage = `Too many requests, please wait ${sec} second${sec > 1 ? "s" : ""} before retrying.`;
29
65
  }
30
66
  }
31
67
  }
@@ -37,46 +73,47 @@ var AuraError = class _AuraError extends Error {
37
73
  if (retryAfterSec !== void 0) {
38
74
  this.retryAfter = retryAfterSec;
39
75
  }
40
- const rawCode = body?.error?.code;
76
+ const hint = body?.error?.hint;
77
+ if (typeof hint === "string" && hint) {
78
+ this.hint = hint;
79
+ }
80
+ const rawCode = typeof body?.error?.code === "string" ? body.error.code : void 0;
81
+ const canonical = rawCode ? normalizeErrorCode(rawCode) : void 0;
41
82
  const lowerMsg = rawMessage.toLowerCase();
42
- if (rawCode === "INVALID_CREDENTIALS" || rawCode === "invalid_credentials") {
43
- this.code = "invalid_credentials";
44
- } else if (rawCode === "EMAIL_ALREADY_IN_USE" || rawCode === "USER_ALREADY_EXISTS" || rawCode === "email_already_in_use") {
45
- this.code = "email_already_in_use";
46
- } else if (rawCode === "WEAK_PASSWORD" || rawCode === "weak_password") {
47
- this.code = "weak_password";
48
- } else if (rawCode === "USER_NOT_FOUND" || rawCode === "user_not_found") {
49
- this.code = "user_not_found";
50
- } else if (rawCode === "SESSION_EXPIRED" || rawCode === "session_expired") {
51
- this.code = "session_expired";
52
- } else if (rawCode === "SESSION_REVOKED" || rawCode === "session_revoked") {
53
- this.code = "session_revoked";
54
- } else if (rawCode === "INVALID_OTP" || rawCode === "invalid_otp") {
55
- this.code = "invalid_otp";
56
- } else if (rawCode === "RATE_LIMITED" || rawCode === "rate_limit_exceeded" || status === 429) {
57
- this.code = "rate_limit_exceeded";
83
+ if (canonical === "USER_ALREADY_EXISTS") {
84
+ this.code = "EMAIL_ALREADY_IN_USE";
85
+ } else if (canonical === "TOKEN_EXPIRED" && status === 401) {
86
+ this.code = "SESSION_EXPIRED";
87
+ } else if (canonical === "RATE_LIMIT_EXCEEDED") {
88
+ this.code = "RATE_LIMITED";
89
+ } else if (canonical && !isGenericCode(canonical)) {
90
+ this.code = canonical;
91
+ } else if (status === 429) {
92
+ this.code = "RATE_LIMITED";
93
+ } else if (status === 401 && lowerMsg.includes("credentials")) {
94
+ this.code = "INVALID_CREDENTIALS";
95
+ } else if (status === 401 && lowerMsg.includes("revoked")) {
96
+ this.code = "SESSION_REVOKED";
97
+ } else if (status === 401 && lowerMsg.includes("expired")) {
98
+ this.code = "SESSION_EXPIRED";
99
+ } else if (status === 400 && lowerMsg.includes("password")) {
100
+ this.code = "WEAK_PASSWORD";
101
+ } else if (status === 409 && (lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
102
+ this.code = "EMAIL_ALREADY_IN_USE";
103
+ } else if (status === 404 && lowerMsg.includes("user not found")) {
104
+ this.code = "USER_NOT_FOUND";
58
105
  } else {
59
- const isGenericHttpCode = typeof rawCode !== "string" || rawCode === "UNAUTHORIZED" || rawCode === "BAD_REQUEST" || rawCode === "CONFLICT" || rawCode.startsWith("http_");
60
- if (!isGenericHttpCode) {
61
- this.code = rawCode;
62
- } else if (status === 401 && (lowerMsg.includes("identifiants") || lowerMsg.includes("credentials") || lowerMsg.includes("mot de passe incorrect"))) {
63
- this.code = "invalid_credentials";
64
- } else if (status === 401 && lowerMsg.includes("r\xE9voqu\xE9e")) {
65
- this.code = "session_revoked";
66
- } else if (status === 401 && lowerMsg.includes("expir\xE9")) {
67
- this.code = "session_expired";
68
- } else if (status === 400 && (lowerMsg.includes("mot de passe") || lowerMsg.includes("password"))) {
69
- this.code = "weak_password";
70
- } else if (status === 409 && (lowerMsg.includes("d\xE9j\xE0 utilis\xE9") || lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
71
- this.code = "email_already_in_use";
72
- } else if (status === 404 && lowerMsg.includes("utilisateur")) {
73
- this.code = "user_not_found";
74
- } else {
75
- this.code = rawCode ?? `http_${status}`;
76
- }
106
+ this.code = canonical ?? `HTTP_${status}`;
77
107
  }
78
108
  Object.setPrototypeOf(this, _AuraError.prototype);
79
109
  }
110
+ /**
111
+ * @deprecated Ancienne forme en minuscules de `code` (`invalid_credentials`, `no_session`…).
112
+ * Utilisez `error.code`, toujours en SCREAMING_SNAKE.
113
+ */
114
+ get legacyCode() {
115
+ return LEGACY_LOWERCASE_CODES.has(this.code) ? this.code.toLowerCase() : this.code;
116
+ }
80
117
  get isNotFound() {
81
118
  return this.status === 404;
82
119
  }
@@ -89,7 +126,17 @@ var AuraError = class _AuraError extends Error {
89
126
  get isRateLimited() {
90
127
  return this.status === 429;
91
128
  }
129
+ /**
130
+ * Quota mensuel du plan atteint (HTTP 403, `code: 'QUOTA_EXCEEDED'`). Le message nomme la
131
+ * métrique, l'usage, la limite et la date de remise à zéro ; ce n'est pas un refus d'autorisation.
132
+ */
133
+ get isQuotaExceeded() {
134
+ return this.code === "QUOTA_EXCEEDED";
135
+ }
92
136
  };
137
+ function isGenericCode(code) {
138
+ return code === "UNAUTHORIZED" || code === "BAD_REQUEST" || code === "CONFLICT" || code.startsWith("HTTP_");
139
+ }
93
140
  function isAuraError(error) {
94
141
  return error instanceof AuraError || typeof error === "object" && error !== null && error.__isAuraError === true;
95
142
  }
@@ -245,6 +292,24 @@ function decodeJwtPayload(token) {
245
292
  return null;
246
293
  }
247
294
  }
295
+ function userFromAccessToken(token) {
296
+ const c = decodeJwtPayload(token);
297
+ if (!c || typeof c.sub !== "string") return null;
298
+ const meta = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
299
+ const amr = Array.isArray(c.amr) ? c.amr : [];
300
+ return {
301
+ id: c.sub,
302
+ email: typeof c.email === "string" ? c.email : null,
303
+ role: "authenticated",
304
+ email_verified: false,
305
+ is_banned: false,
306
+ is_anonymous: amr.some((a) => a?.method === "anonymous"),
307
+ mfa_enabled: c.aal === "aal2",
308
+ user_metadata: meta(c.user_metadata),
309
+ app_metadata: meta(c.app_metadata),
310
+ created_at: ""
311
+ };
312
+ }
248
313
  function isTokenExpired(token, marginSec = 0) {
249
314
  const payload = decodeJwtPayload(token);
250
315
  if (!payload || typeof payload.exp !== "number") return true;
@@ -354,6 +419,17 @@ var BaseAuthStore = class {
354
419
  // src/fetch.ts
355
420
  var REFRESH_MARGIN_SEC = 30;
356
421
  var RETRY_AFTER_CAP_MS = 6e4;
422
+ function networkErrorMessage(err, url) {
423
+ const cause = err?.cause;
424
+ const reason = cause?.code ?? cause?.message ?? (err instanceof Error ? err.message : "request failed");
425
+ let target = url;
426
+ try {
427
+ const u = new URL(url);
428
+ target = `${u.origin}${u.pathname}`;
429
+ } catch {
430
+ }
431
+ return `Cannot reach ${target} (${reason}). Check the project URL (NEXT_PUBLIC_AURABASE_URL) and your network.`;
432
+ }
357
433
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
358
434
  function unwrapEnvelope(body) {
359
435
  if (body !== null && typeof body === "object" && "data" in body) {
@@ -475,7 +551,7 @@ async function doRefresh(client) {
475
551
  error: new AuraError(0, {
476
552
  error: timedOut ? { code: "timeout", message: `Refresh timed out after ${timeoutMs}ms` } : {
477
553
  code: "network_error",
478
- message: err instanceof Error ? err.message : "Network request failed"
554
+ message: networkErrorMessage(err, `${client.baseUrl}/v1/auth/refresh`)
479
555
  }
480
556
  })
481
557
  };
@@ -676,7 +752,7 @@ async function fetchWithAuth(url, init, client) {
676
752
  error: new AuraError(0, {
677
753
  error: timedOut ? { code: "timeout", message: `Request timed out after ${timeoutMs}ms` } : {
678
754
  code: "network_error",
679
- message: err instanceof Error ? err.message : "Network request failed"
755
+ message: networkErrorMessage(err, url)
680
756
  }
681
757
  })
682
758
  };
@@ -825,13 +901,16 @@ function parseCookieHeader(header) {
825
901
  }
826
902
  return result;
827
903
  }
904
+ function sameSiteAttribute(v) {
905
+ return v.charAt(0).toUpperCase() + v.slice(1);
906
+ }
828
907
  function serializeCookieHeader(name, value, options = {}) {
829
908
  const parts = [`${name}=${encodeURIComponent(value)}`];
830
909
  if (options.path) parts.push(`Path=${options.path}`);
831
910
  if (options.domain) parts.push(`Domain=${options.domain}`);
832
911
  if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
833
912
  if (options.secure) parts.push("Secure");
834
- if (options.sameSite) parts.push(`SameSite=${options.sameSite}`);
913
+ if (options.sameSite) parts.push(`SameSite=${sameSiteAttribute(options.sameSite)}`);
835
914
  if (options.httpOnly) parts.push("HttpOnly");
836
915
  return parts.join("; ");
837
916
  }
@@ -922,6 +1001,9 @@ var LocalAuthStore = class extends BaseAuthStore {
922
1001
  /**
923
1002
  * Populate the store from a raw `Cookie` header string (server-side).
924
1003
  * Looks for the key matching `this.key`.
1004
+ *
1005
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
1006
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
925
1007
  */
926
1008
  loadFromCookie(cookieString) {
927
1009
  const prefix = `${this.key}=`;
@@ -930,20 +1012,22 @@ var LocalAuthStore = class extends BaseAuthStore {
930
1012
  try {
931
1013
  const raw = decodeURIComponent(entry.slice(prefix.length));
932
1014
  const parsed = JSON.parse(raw);
933
- if (parsed.token && parsed.refreshToken && parsed.user) {
934
- super.save(parsed.token, parsed.refreshToken, parsed.user);
1015
+ const user = parsed.token ? userFromAccessToken(parsed.token) : null;
1016
+ if (parsed.token && parsed.refreshToken && user) {
1017
+ super.save(parsed.token, parsed.refreshToken, user);
935
1018
  }
936
1019
  } catch {
937
1020
  }
938
1021
  }
939
1022
  /**
940
- * Serialize current auth state into a `Set-Cookie` value.
1023
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
1024
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
1025
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
941
1026
  */
942
1027
  exportToCookie(options = {}) {
943
1028
  const data = {
944
1029
  token: this.token,
945
- refreshToken: this.refreshToken,
946
- user: this.user
1030
+ refreshToken: this.refreshToken
947
1031
  };
948
1032
  const encoded = encodeURIComponent(JSON.stringify(data));
949
1033
  const parts = [`${this.key}=${encoded}`];
@@ -951,7 +1035,7 @@ var LocalAuthStore = class extends BaseAuthStore {
951
1035
  if (options.domain) parts.push(`Domain=${options.domain}`);
952
1036
  if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
953
1037
  if (options.secure) parts.push("Secure");
954
- if (options.sameSite) parts.push(`SameSite=${options.sameSite}`);
1038
+ if (options.sameSite) parts.push(`SameSite=${sameSiteAttribute(options.sameSite)}`);
955
1039
  if (options.httpOnly) parts.push("HttpOnly");
956
1040
  return parts.join("; ");
957
1041
  }
package/dist/index.d.cts CHANGED
@@ -14,7 +14,7 @@
14
14
  * - storage/path.ts : invalid_path
15
15
  * - db/QueryBuilder.ts: PGRST116 (parité PostgREST : `.single()` sur 0/plusieurs lignes)
16
16
  */
17
- type AuraErrorCode = 'no_session' | 'timeout' | 'network_error' | 'invalid_response' | 'refresh_discarded' | 'unverifiable_token' | 'no_code_verifier' | 'pkce_generation_failed' | 'missing_email' | 'jwks_fetch_failed' | 'signature_invalid' | 'token_expired' | 'token_not_yet_valid' | 'invalid_jwt' | 'unsupported_alg' | 'no_matching_key' | 'invalid_issuer' | 'invalid_audience' | 'invalid_path' | 'PGRST116' | 'invalid_credentials' | 'weak_password' | 'email_already_in_use' | 'user_not_found' | 'rate_limit_exceeded' | 'session_expired' | 'invalid_otp' | 'session_revoked' | (string & {});
17
+ type AuraErrorCode = 'NO_SESSION' | 'TIMEOUT' | 'NETWORK_ERROR' | 'INVALID_RESPONSE' | 'REFRESH_DISCARDED' | 'UNVERIFIABLE_TOKEN' | 'NO_CODE_VERIFIER' | 'PKCE_GENERATION_FAILED' | 'MISSING_EMAIL' | 'JWKS_FETCH_FAILED' | 'SIGNATURE_INVALID' | 'TOKEN_EXPIRED' | 'TOKEN_NOT_YET_VALID' | 'INVALID_JWT' | 'UNSUPPORTED_ALG' | 'NO_MATCHING_KEY' | 'INVALID_ISSUER' | 'INVALID_AUDIENCE' | 'INVALID_PATH' | 'PGRST116' | 'INVALID_CREDENTIALS' | 'WEAK_PASSWORD' | 'PASSWORD_REQUIRED' | 'EMAIL_ALREADY_IN_USE' | 'USER_NOT_FOUND' | 'USER_BANNED' | 'EMAIL_NOT_CONFIRMED' | 'RATE_LIMITED' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'SESSION_REVOKED' | 'MFA_CODE_INVALID' | 'MFA_CODE_ALREADY_USED' | 'TOTP_CODE_REUSED' | 'MFA_CHALLENGE_EXPIRED' | (string & {});
18
18
  /**
19
19
  * Structured error thrown/returned by the Aurabase SDK.
20
20
  * Mirrors the backend's `AuraError` JSON shape with semantic DX normalization.
@@ -24,19 +24,35 @@ declare class AuraError extends Error {
24
24
  readonly code: AuraErrorCode;
25
25
  readonly details: unknown;
26
26
  readonly retryAfter?: number;
27
+ /**
28
+ * Piste de correction fournie par le serveur (ex. refus RLS : quelle politique créer). J1-010.
29
+ */
30
+ readonly hint?: string;
27
31
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
28
32
  protected readonly __isAuraError = true;
29
33
  constructor(status: number, body?: {
30
34
  error?: {
31
35
  code?: string;
32
36
  message?: string;
37
+ hint?: string;
38
+ details?: unknown;
33
39
  };
34
40
  message?: string;
35
41
  } | null, headers?: Headers | Record<string, string | null | undefined>);
42
+ /**
43
+ * @deprecated Ancienne forme en minuscules de `code` (`invalid_credentials`, `no_session`…).
44
+ * Utilisez `error.code`, toujours en SCREAMING_SNAKE.
45
+ */
46
+ get legacyCode(): string;
36
47
  get isNotFound(): boolean;
37
48
  get isUnauthorized(): boolean;
38
49
  get isForbidden(): boolean;
39
50
  get isRateLimited(): boolean;
51
+ /**
52
+ * Quota mensuel du plan atteint (HTTP 403, `code: 'QUOTA_EXCEEDED'`). Le message nomme la
53
+ * métrique, l'usage, la limite et la date de remise à zéro ; ce n'est pas un refus d'autorisation.
54
+ */
55
+ get isQuotaExceeded(): boolean;
40
56
  }
41
57
  declare function isAuraError(error: unknown): error is AuraError;
42
58
 
@@ -189,10 +205,6 @@ interface User {
189
205
  interface Session {
190
206
  access_token: string;
191
207
  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
208
  token_type: string;
197
209
  expires_in: number;
198
210
  expires_at?: number;
@@ -203,30 +215,20 @@ interface Session {
203
215
  interface TokenPair {
204
216
  access_token: string;
205
217
  refresh_token: string;
206
- /** Alias camelCase pour parité DX Supabase/JS */
207
- accessToken?: string;
208
- /** Alias camelCase pour parité DX Supabase/JS */
209
- refreshToken?: string;
210
218
  token_type: string;
211
219
  expires_in: number;
212
220
  user: User;
213
221
  provider_token?: string | null;
214
222
  provider_refresh_token?: string | null;
215
- /** Sous-objet session pour parité DX Supabase (`data.session.access_token`). */
216
- session?: Session;
217
- mfaChallenge?: undefined;
223
+ /** Sous-objet session pour parité DX Supabase (`data.session.access_token`).
224
+ * `null` après une inscription sur un projet qui exige un e-mail vérifié (AUTH-002). */
225
+ session?: Session | null;
218
226
  }
219
227
  interface MfaChallenge {
220
228
  mfa_required: true;
221
229
  mfa_token: string;
222
230
  mfa_setup_required?: boolean;
223
231
  session?: undefined;
224
- /** Alias ergonomique aligné sur la documentation officielle */
225
- mfaChallenge?: {
226
- mfaRequired: boolean;
227
- mfaToken: string;
228
- mfaSetupRequired?: boolean;
229
- };
230
232
  }
231
233
  type LoginResponse = TokenPair | MfaChallenge;
232
234
  type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
@@ -361,9 +363,35 @@ interface MfaEnrollResponse {
361
363
  otpauth_url: string;
362
364
  secret: string;
363
365
  }
364
- interface MfaVerifyRequest {
366
+ /**
367
+ * Relève un défi MFA : exactement UN facteur parmi `code` (TOTP à 6 chiffres), `recovery_code`
368
+ * (code de secours `XXXXXXXX-XXXXXXXX`) et `sms_code` (code reçu après `auth.mfa.sms.send`).
369
+ * Pour une passkey, utilisez `auth.mfa.webauthn.verify`.
370
+ */
371
+ type MfaVerifyRequest = {
365
372
  mfa_token: string;
366
373
  code: string;
374
+ } | {
375
+ mfa_token: string;
376
+ recovery_code: string;
377
+ } | {
378
+ mfa_token: string;
379
+ sms_code: string;
380
+ };
381
+ /** Facteur MFA utilisable pour relever un défi (`auth.mfa.factors`). */
382
+ type MfaFactorType = 'totp' | 'webauthn' | 'sms';
383
+ /** Passkey WebAuthn enrôlée (`auth.mfa.webauthn.list`). */
384
+ interface PasskeyInfo {
385
+ id: string;
386
+ friendly_name: string;
387
+ created_at: string;
388
+ last_used_at: string | null;
389
+ }
390
+ /** Résultat de l'enrôlement d'une passkey. `recovery_codes` n'est présent que si cette passkey est le premier facteur du compte. */
391
+ interface PasskeyRegisterResult {
392
+ id: string;
393
+ friendly_name: string;
394
+ recovery_codes?: string[];
367
395
  }
368
396
  interface SessionInfo {
369
397
  id: string;
@@ -1490,6 +1518,11 @@ interface AuraClientOptions {
1490
1518
  * Défaut : `true` en navigateur, no-op hors navigateur (SSR/Node).
1491
1519
  */
1492
1520
  detectSessionInUrl?: boolean;
1521
+ /**
1522
+ * AUTH-015 — flux OAuth par défaut de `signInWithOAuth` pour ce client (`'pkce'` recommandé
1523
+ * en navigateur). Une option `flowType` passée à l'appel reste prioritaire.
1524
+ */
1525
+ flowType?: 'pkce' | 'implicit';
1493
1526
  };
1494
1527
  fetch?: typeof globalThis.fetch;
1495
1528
  /**
@@ -1773,7 +1806,7 @@ interface AdminUpdateUserRequest {
1773
1806
  mfa_enabled?: boolean;
1774
1807
  revoke_sessions?: boolean;
1775
1808
  }
1776
- type GenerateLinkType = 'magic' | 'recovery' | 'invite';
1809
+ type GenerateLinkType = 'signup' | 'magic' | 'recovery' | 'invite';
1777
1810
  interface GenerateLinkResult {
1778
1811
  link: string;
1779
1812
  token: string;
@@ -1927,7 +1960,8 @@ interface SerializeCookieOptions {
1927
1960
  domain?: string;
1928
1961
  maxAge?: number;
1929
1962
  secure?: boolean;
1930
- sameSite?: 'Strict' | 'Lax' | 'None';
1963
+ /** Minuscules : forme acceptée par `ResponseCookie` de Next.js (`'lax' | 'strict' | 'none'`). */
1964
+ sameSite?: 'strict' | 'lax' | 'none';
1931
1965
  httpOnly?: boolean;
1932
1966
  }
1933
1967
  /**
@@ -1935,7 +1969,6 @@ interface SerializeCookieOptions {
1935
1969
  */
1936
1970
  declare function serializeCookieHeader(name: string, value: string, options?: SerializeCookieOptions): string;
1937
1971
 
1938
- /** Timeout par défaut d'une requête HTTP (borne un serveur qui « hang »). */
1939
1972
  declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
1940
1973
  /** Point d'entrée unique du refresh, dédupliqué par client (single-flight). */
1941
1974
  declare function refreshOnce(client: AuraClientLike): Promise<AuraResponse<TokenPair>>;
@@ -2010,7 +2043,7 @@ interface CookieOptions {
2010
2043
  domain?: string;
2011
2044
  maxAge?: number;
2012
2045
  secure?: boolean;
2013
- sameSite?: 'Strict' | 'Lax' | 'None';
2046
+ sameSite?: 'strict' | 'lax' | 'none';
2014
2047
  httpOnly?: boolean;
2015
2048
  }
2016
2049
  /**
@@ -2053,10 +2086,15 @@ declare class LocalAuthStore extends BaseAuthStore {
2053
2086
  /**
2054
2087
  * Populate the store from a raw `Cookie` header string (server-side).
2055
2088
  * Looks for the key matching `this.key`.
2089
+ *
2090
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
2091
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
2056
2092
  */
2057
2093
  loadFromCookie(cookieString: string): void;
2058
2094
  /**
2059
- * Serialize current auth state into a `Set-Cookie` value.
2095
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
2096
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
2097
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
2060
2098
  */
2061
2099
  exportToCookie(options?: CookieOptions): string;
2062
2100
  private _getStorage;
@@ -2065,4 +2103,4 @@ declare class LocalAuthStore extends BaseAuthStore {
2065
2103
  private _removeStorage;
2066
2104
  }
2067
2105
 
2068
- export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
2106
+ export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaFactorType, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasskeyInfo, type PasskeyRegisterResult, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * - storage/path.ts : invalid_path
15
15
  * - db/QueryBuilder.ts: PGRST116 (parité PostgREST : `.single()` sur 0/plusieurs lignes)
16
16
  */
17
- type AuraErrorCode = 'no_session' | 'timeout' | 'network_error' | 'invalid_response' | 'refresh_discarded' | 'unverifiable_token' | 'no_code_verifier' | 'pkce_generation_failed' | 'missing_email' | 'jwks_fetch_failed' | 'signature_invalid' | 'token_expired' | 'token_not_yet_valid' | 'invalid_jwt' | 'unsupported_alg' | 'no_matching_key' | 'invalid_issuer' | 'invalid_audience' | 'invalid_path' | 'PGRST116' | 'invalid_credentials' | 'weak_password' | 'email_already_in_use' | 'user_not_found' | 'rate_limit_exceeded' | 'session_expired' | 'invalid_otp' | 'session_revoked' | (string & {});
17
+ type AuraErrorCode = 'NO_SESSION' | 'TIMEOUT' | 'NETWORK_ERROR' | 'INVALID_RESPONSE' | 'REFRESH_DISCARDED' | 'UNVERIFIABLE_TOKEN' | 'NO_CODE_VERIFIER' | 'PKCE_GENERATION_FAILED' | 'MISSING_EMAIL' | 'JWKS_FETCH_FAILED' | 'SIGNATURE_INVALID' | 'TOKEN_EXPIRED' | 'TOKEN_NOT_YET_VALID' | 'INVALID_JWT' | 'UNSUPPORTED_ALG' | 'NO_MATCHING_KEY' | 'INVALID_ISSUER' | 'INVALID_AUDIENCE' | 'INVALID_PATH' | 'PGRST116' | 'INVALID_CREDENTIALS' | 'WEAK_PASSWORD' | 'PASSWORD_REQUIRED' | 'EMAIL_ALREADY_IN_USE' | 'USER_NOT_FOUND' | 'USER_BANNED' | 'EMAIL_NOT_CONFIRMED' | 'RATE_LIMITED' | 'SESSION_EXPIRED' | 'INVALID_OTP' | 'SESSION_REVOKED' | 'MFA_CODE_INVALID' | 'MFA_CODE_ALREADY_USED' | 'TOTP_CODE_REUSED' | 'MFA_CHALLENGE_EXPIRED' | (string & {});
18
18
  /**
19
19
  * Structured error thrown/returned by the Aurabase SDK.
20
20
  * Mirrors the backend's `AuraError` JSON shape with semantic DX normalization.
@@ -24,19 +24,35 @@ declare class AuraError extends Error {
24
24
  readonly code: AuraErrorCode;
25
25
  readonly details: unknown;
26
26
  readonly retryAfter?: number;
27
+ /**
28
+ * Piste de correction fournie par le serveur (ex. refus RLS : quelle politique créer). J1-010.
29
+ */
30
+ readonly hint?: string;
27
31
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
28
32
  protected readonly __isAuraError = true;
29
33
  constructor(status: number, body?: {
30
34
  error?: {
31
35
  code?: string;
32
36
  message?: string;
37
+ hint?: string;
38
+ details?: unknown;
33
39
  };
34
40
  message?: string;
35
41
  } | null, headers?: Headers | Record<string, string | null | undefined>);
42
+ /**
43
+ * @deprecated Ancienne forme en minuscules de `code` (`invalid_credentials`, `no_session`…).
44
+ * Utilisez `error.code`, toujours en SCREAMING_SNAKE.
45
+ */
46
+ get legacyCode(): string;
36
47
  get isNotFound(): boolean;
37
48
  get isUnauthorized(): boolean;
38
49
  get isForbidden(): boolean;
39
50
  get isRateLimited(): boolean;
51
+ /**
52
+ * Quota mensuel du plan atteint (HTTP 403, `code: 'QUOTA_EXCEEDED'`). Le message nomme la
53
+ * métrique, l'usage, la limite et la date de remise à zéro ; ce n'est pas un refus d'autorisation.
54
+ */
55
+ get isQuotaExceeded(): boolean;
40
56
  }
41
57
  declare function isAuraError(error: unknown): error is AuraError;
42
58
 
@@ -189,10 +205,6 @@ interface User {
189
205
  interface Session {
190
206
  access_token: string;
191
207
  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
208
  token_type: string;
197
209
  expires_in: number;
198
210
  expires_at?: number;
@@ -203,30 +215,20 @@ interface Session {
203
215
  interface TokenPair {
204
216
  access_token: string;
205
217
  refresh_token: string;
206
- /** Alias camelCase pour parité DX Supabase/JS */
207
- accessToken?: string;
208
- /** Alias camelCase pour parité DX Supabase/JS */
209
- refreshToken?: string;
210
218
  token_type: string;
211
219
  expires_in: number;
212
220
  user: User;
213
221
  provider_token?: string | null;
214
222
  provider_refresh_token?: string | null;
215
- /** Sous-objet session pour parité DX Supabase (`data.session.access_token`). */
216
- session?: Session;
217
- mfaChallenge?: undefined;
223
+ /** Sous-objet session pour parité DX Supabase (`data.session.access_token`).
224
+ * `null` après une inscription sur un projet qui exige un e-mail vérifié (AUTH-002). */
225
+ session?: Session | null;
218
226
  }
219
227
  interface MfaChallenge {
220
228
  mfa_required: true;
221
229
  mfa_token: string;
222
230
  mfa_setup_required?: boolean;
223
231
  session?: undefined;
224
- /** Alias ergonomique aligné sur la documentation officielle */
225
- mfaChallenge?: {
226
- mfaRequired: boolean;
227
- mfaToken: string;
228
- mfaSetupRequired?: boolean;
229
- };
230
232
  }
231
233
  type LoginResponse = TokenPair | MfaChallenge;
232
234
  type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
@@ -361,9 +363,35 @@ interface MfaEnrollResponse {
361
363
  otpauth_url: string;
362
364
  secret: string;
363
365
  }
364
- interface MfaVerifyRequest {
366
+ /**
367
+ * Relève un défi MFA : exactement UN facteur parmi `code` (TOTP à 6 chiffres), `recovery_code`
368
+ * (code de secours `XXXXXXXX-XXXXXXXX`) et `sms_code` (code reçu après `auth.mfa.sms.send`).
369
+ * Pour une passkey, utilisez `auth.mfa.webauthn.verify`.
370
+ */
371
+ type MfaVerifyRequest = {
365
372
  mfa_token: string;
366
373
  code: string;
374
+ } | {
375
+ mfa_token: string;
376
+ recovery_code: string;
377
+ } | {
378
+ mfa_token: string;
379
+ sms_code: string;
380
+ };
381
+ /** Facteur MFA utilisable pour relever un défi (`auth.mfa.factors`). */
382
+ type MfaFactorType = 'totp' | 'webauthn' | 'sms';
383
+ /** Passkey WebAuthn enrôlée (`auth.mfa.webauthn.list`). */
384
+ interface PasskeyInfo {
385
+ id: string;
386
+ friendly_name: string;
387
+ created_at: string;
388
+ last_used_at: string | null;
389
+ }
390
+ /** Résultat de l'enrôlement d'une passkey. `recovery_codes` n'est présent que si cette passkey est le premier facteur du compte. */
391
+ interface PasskeyRegisterResult {
392
+ id: string;
393
+ friendly_name: string;
394
+ recovery_codes?: string[];
367
395
  }
368
396
  interface SessionInfo {
369
397
  id: string;
@@ -1490,6 +1518,11 @@ interface AuraClientOptions {
1490
1518
  * Défaut : `true` en navigateur, no-op hors navigateur (SSR/Node).
1491
1519
  */
1492
1520
  detectSessionInUrl?: boolean;
1521
+ /**
1522
+ * AUTH-015 — flux OAuth par défaut de `signInWithOAuth` pour ce client (`'pkce'` recommandé
1523
+ * en navigateur). Une option `flowType` passée à l'appel reste prioritaire.
1524
+ */
1525
+ flowType?: 'pkce' | 'implicit';
1493
1526
  };
1494
1527
  fetch?: typeof globalThis.fetch;
1495
1528
  /**
@@ -1773,7 +1806,7 @@ interface AdminUpdateUserRequest {
1773
1806
  mfa_enabled?: boolean;
1774
1807
  revoke_sessions?: boolean;
1775
1808
  }
1776
- type GenerateLinkType = 'magic' | 'recovery' | 'invite';
1809
+ type GenerateLinkType = 'signup' | 'magic' | 'recovery' | 'invite';
1777
1810
  interface GenerateLinkResult {
1778
1811
  link: string;
1779
1812
  token: string;
@@ -1927,7 +1960,8 @@ interface SerializeCookieOptions {
1927
1960
  domain?: string;
1928
1961
  maxAge?: number;
1929
1962
  secure?: boolean;
1930
- sameSite?: 'Strict' | 'Lax' | 'None';
1963
+ /** Minuscules : forme acceptée par `ResponseCookie` de Next.js (`'lax' | 'strict' | 'none'`). */
1964
+ sameSite?: 'strict' | 'lax' | 'none';
1931
1965
  httpOnly?: boolean;
1932
1966
  }
1933
1967
  /**
@@ -1935,7 +1969,6 @@ interface SerializeCookieOptions {
1935
1969
  */
1936
1970
  declare function serializeCookieHeader(name: string, value: string, options?: SerializeCookieOptions): string;
1937
1971
 
1938
- /** Timeout par défaut d'une requête HTTP (borne un serveur qui « hang »). */
1939
1972
  declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
1940
1973
  /** Point d'entrée unique du refresh, dédupliqué par client (single-flight). */
1941
1974
  declare function refreshOnce(client: AuraClientLike): Promise<AuraResponse<TokenPair>>;
@@ -2010,7 +2043,7 @@ interface CookieOptions {
2010
2043
  domain?: string;
2011
2044
  maxAge?: number;
2012
2045
  secure?: boolean;
2013
- sameSite?: 'Strict' | 'Lax' | 'None';
2046
+ sameSite?: 'strict' | 'lax' | 'none';
2014
2047
  httpOnly?: boolean;
2015
2048
  }
2016
2049
  /**
@@ -2053,10 +2086,15 @@ declare class LocalAuthStore extends BaseAuthStore {
2053
2086
  /**
2054
2087
  * Populate the store from a raw `Cookie` header string (server-side).
2055
2088
  * Looks for the key matching `this.key`.
2089
+ *
2090
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
2091
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
2056
2092
  */
2057
2093
  loadFromCookie(cookieString: string): void;
2058
2094
  /**
2059
- * Serialize current auth state into a `Set-Cookie` value.
2095
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
2096
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
2097
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
2060
2098
  */
2061
2099
  exportToCookie(options?: CookieOptions): string;
2062
2100
  private _getStorage;
@@ -2065,4 +2103,4 @@ declare class LocalAuthStore extends BaseAuthStore {
2065
2103
  private _removeStorage;
2066
2104
  }
2067
2105
 
2068
- export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
2106
+ export { AUTH_SETTINGS_WRITABLE_FIELDS, type AdminCreateUserRequest, type AdminSessionInfo, type AdminUpdateUserRequest, type AdminUser, type ApnsPublicSettings, type ApnsSettingsPatch, type AuditLogEntry, type AuraClientLike, type AuraClientOptions, AuraError, type AuraErrorCode, type AuraFailure, type AuraNoContent, type AuraObservabilityEvent, type AuraResponse, type AuraSuccess, type AuthChangePayload, type AuthEvent, type AuthSettings, type AuthSettingsUpdate, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type BroadcastSendStatus, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CreateNotificationRuleRequest, type CreatePgFunctionRequest, type CreatePgTriggerRequest, type CronJob, DEFAULT_MAX_RETRIES, DEFAULT_REQUEST_TIMEOUT_MS, type EmailTemplateUpdate, type EmbedRequest, type EmbedResponse, type FcmPublicSettings, type FcmSettingsPatch, type FetchInit, type FileEntry, type FilterOp, type FunctionDef, type FunctionPermissions, type GenerateLinkResult, type GenerateLinkType, type GetClaimsResult, type IdentityInfo, type ImageTransform, type Job, type JwtClaims, LocalAuthStore, type LoginResponse, type MagicLinkRequest, type Meta, type MfaChallenge, type MfaEnrollResponse, type MfaFactorType, type MfaVerifyRequest, type Notification, type NotificationAttempt, type NotificationAttemptStatus, type NotificationChannel, type NotificationChannelStats, type NotificationDeadLetter, type NotificationEvent, type NotificationProviderLog, type NotificationQueueStats, type NotificationRule, type NotificationSettings, type NotificationSettingsPatch, type NotificationSettingsPublic, type NotificationStats, type NotificationStatsWindow, type NotificationStatus, type NotificationTemplate, type NotificationTemplatePreview, type OAuthProviderSetting, type OAuthSignInObjectOptions, type OAuthSignInOptions, type ObjectMeta, type PasskeyInfo, type PasskeyRegisterResult, type PasswordResetRequest, type PgExecutableRole, type PgFunctionInfo, type PgTriggerInfo, type PostgresChangesFilter, type PresenceFilter, type PresenceInfo, type PresenceState, type QueryFilter, type QueryOptions, type QuotaPublicSettings, type QuotaSettingsPatch, RETRYABLE_METHODS, RETRYABLE_STATUS, type RagIngestRequest, type RagIngestResponse, type RagRequest, type RagResponse, type RealtimeBroadcastEvent, type RealtimeEvent, type RealtimeListenType, type RealtimePostgresChangesBasePayload, type RealtimePostgresChangesPayload, type RealtimePostgresDeletePayload, type RealtimePostgresInsertPayload, type RealtimePostgresUpdatePayload, type RealtimeSubscribeStatus, type SchemaColumn, type SchemaEnum, type SchemaFunction, type SchemaFunctionArg, type SchemaIndex, type SchemaTable, type SemanticSearchResult, type SendNotificationItem, type SendNotificationOptions, type SendNotificationRequest, type SerializeCookieOptions, type ServerChannelRecoveredMsg, type ServerErrorMsg, type ServerEventMsg, type ServerMessage, type ServerPongMsg, type ServerPresenceStateMsg, type ServerSubscribedMsg, type ServerTokenRefreshedMsg, type Session, type SessionInfo, type SettingsSource, type SignInRequest, type SignUpRequest, type SmtpPublicSettings, type SmtpSettingsPatch, type StorageBucket, type SubscribeCallback, type TokenPair, type TwilioPublicSettings, type TwilioSettingsPatch, type UpdateNotificationRuleRequest, type UpdateUserRequest, type UploadResult, type User, type UserStats, type WebhookPublicSettings, type WebhookSettingsPatch, abortableSleep, clientScope, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };
package/dist/index.js CHANGED
@@ -1,13 +1,49 @@
1
1
  // src/AuraError.ts
2
+ var LEGACY_LOWERCASE_CODES = /* @__PURE__ */ new Set([
3
+ "NO_SESSION",
4
+ "TIMEOUT",
5
+ "NETWORK_ERROR",
6
+ "INVALID_RESPONSE",
7
+ "REFRESH_DISCARDED",
8
+ "UNVERIFIABLE_TOKEN",
9
+ "NO_CODE_VERIFIER",
10
+ "PKCE_GENERATION_FAILED",
11
+ "MISSING_EMAIL",
12
+ "JWKS_FETCH_FAILED",
13
+ "SIGNATURE_INVALID",
14
+ "TOKEN_EXPIRED",
15
+ "TOKEN_NOT_YET_VALID",
16
+ "INVALID_JWT",
17
+ "UNSUPPORTED_ALG",
18
+ "NO_MATCHING_KEY",
19
+ "INVALID_ISSUER",
20
+ "INVALID_AUDIENCE",
21
+ "INVALID_PATH",
22
+ "INVALID_CREDENTIALS",
23
+ "WEAK_PASSWORD",
24
+ "EMAIL_ALREADY_IN_USE",
25
+ "USER_NOT_FOUND",
26
+ "SESSION_EXPIRED",
27
+ "INVALID_OTP",
28
+ "SESSION_REVOKED"
29
+ ]);
30
+ function normalizeErrorCode(code) {
31
+ return code.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
32
+ }
2
33
  var AuraError = class _AuraError extends Error {
3
34
  status;
4
35
  code;
5
36
  details;
6
37
  retryAfter;
38
+ /**
39
+ * Piste de correction fournie par le serveur (ex. refus RLS : quelle politique créer). J1-010.
40
+ */
41
+ hint;
7
42
  /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
8
43
  __isAuraError = true;
9
44
  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}`);
45
+ const serverMessage = body?.error?.message ?? body?.message;
46
+ let rawMessage = serverMessage ?? (status === 429 ? "Too many requests, please wait before retrying." : `HTTP ${status}`);
11
47
  let retryAfterSec;
12
48
  if (headers) {
13
49
  const getHeader = (name) => {
@@ -22,8 +58,8 @@ var AuraError = class _AuraError extends Error {
22
58
  const sec = parseInt(ra, 10);
23
59
  if (!isNaN(sec)) {
24
60
  retryAfterSec = sec;
25
- if (status === 429) {
26
- rawMessage = `Trop de requ\xEAtes, veuillez patienter ${sec} seconde${sec > 1 ? "s" : ""} avant de r\xE9essayer.`;
61
+ if (status === 429 && !serverMessage) {
62
+ rawMessage = `Too many requests, please wait ${sec} second${sec > 1 ? "s" : ""} before retrying.`;
27
63
  }
28
64
  }
29
65
  }
@@ -35,46 +71,47 @@ var AuraError = class _AuraError extends Error {
35
71
  if (retryAfterSec !== void 0) {
36
72
  this.retryAfter = retryAfterSec;
37
73
  }
38
- const rawCode = body?.error?.code;
74
+ const hint = body?.error?.hint;
75
+ if (typeof hint === "string" && hint) {
76
+ this.hint = hint;
77
+ }
78
+ const rawCode = typeof body?.error?.code === "string" ? body.error.code : void 0;
79
+ const canonical = rawCode ? normalizeErrorCode(rawCode) : void 0;
39
80
  const lowerMsg = rawMessage.toLowerCase();
40
- if (rawCode === "INVALID_CREDENTIALS" || rawCode === "invalid_credentials") {
41
- this.code = "invalid_credentials";
42
- } else if (rawCode === "EMAIL_ALREADY_IN_USE" || rawCode === "USER_ALREADY_EXISTS" || rawCode === "email_already_in_use") {
43
- this.code = "email_already_in_use";
44
- } else if (rawCode === "WEAK_PASSWORD" || rawCode === "weak_password") {
45
- this.code = "weak_password";
46
- } else if (rawCode === "USER_NOT_FOUND" || rawCode === "user_not_found") {
47
- this.code = "user_not_found";
48
- } else if (rawCode === "SESSION_EXPIRED" || rawCode === "session_expired") {
49
- this.code = "session_expired";
50
- } else if (rawCode === "SESSION_REVOKED" || rawCode === "session_revoked") {
51
- this.code = "session_revoked";
52
- } else if (rawCode === "INVALID_OTP" || rawCode === "invalid_otp") {
53
- this.code = "invalid_otp";
54
- } else if (rawCode === "RATE_LIMITED" || rawCode === "rate_limit_exceeded" || status === 429) {
55
- this.code = "rate_limit_exceeded";
81
+ if (canonical === "USER_ALREADY_EXISTS") {
82
+ this.code = "EMAIL_ALREADY_IN_USE";
83
+ } else if (canonical === "TOKEN_EXPIRED" && status === 401) {
84
+ this.code = "SESSION_EXPIRED";
85
+ } else if (canonical === "RATE_LIMIT_EXCEEDED") {
86
+ this.code = "RATE_LIMITED";
87
+ } else if (canonical && !isGenericCode(canonical)) {
88
+ this.code = canonical;
89
+ } else if (status === 429) {
90
+ this.code = "RATE_LIMITED";
91
+ } else if (status === 401 && lowerMsg.includes("credentials")) {
92
+ this.code = "INVALID_CREDENTIALS";
93
+ } else if (status === 401 && lowerMsg.includes("revoked")) {
94
+ this.code = "SESSION_REVOKED";
95
+ } else if (status === 401 && lowerMsg.includes("expired")) {
96
+ this.code = "SESSION_EXPIRED";
97
+ } else if (status === 400 && lowerMsg.includes("password")) {
98
+ this.code = "WEAK_PASSWORD";
99
+ } else if (status === 409 && (lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
100
+ this.code = "EMAIL_ALREADY_IN_USE";
101
+ } else if (status === 404 && lowerMsg.includes("user not found")) {
102
+ this.code = "USER_NOT_FOUND";
56
103
  } else {
57
- const isGenericHttpCode = typeof rawCode !== "string" || rawCode === "UNAUTHORIZED" || rawCode === "BAD_REQUEST" || rawCode === "CONFLICT" || rawCode.startsWith("http_");
58
- if (!isGenericHttpCode) {
59
- this.code = rawCode;
60
- } else if (status === 401 && (lowerMsg.includes("identifiants") || lowerMsg.includes("credentials") || lowerMsg.includes("mot de passe incorrect"))) {
61
- this.code = "invalid_credentials";
62
- } else if (status === 401 && lowerMsg.includes("r\xE9voqu\xE9e")) {
63
- this.code = "session_revoked";
64
- } else if (status === 401 && lowerMsg.includes("expir\xE9")) {
65
- this.code = "session_expired";
66
- } else if (status === 400 && (lowerMsg.includes("mot de passe") || lowerMsg.includes("password"))) {
67
- this.code = "weak_password";
68
- } else if (status === 409 && (lowerMsg.includes("d\xE9j\xE0 utilis\xE9") || lowerMsg.includes("already exists") || lowerMsg.includes("already in use") || lowerMsg.includes("email"))) {
69
- this.code = "email_already_in_use";
70
- } else if (status === 404 && lowerMsg.includes("utilisateur")) {
71
- this.code = "user_not_found";
72
- } else {
73
- this.code = rawCode ?? `http_${status}`;
74
- }
104
+ this.code = canonical ?? `HTTP_${status}`;
75
105
  }
76
106
  Object.setPrototypeOf(this, _AuraError.prototype);
77
107
  }
108
+ /**
109
+ * @deprecated Ancienne forme en minuscules de `code` (`invalid_credentials`, `no_session`…).
110
+ * Utilisez `error.code`, toujours en SCREAMING_SNAKE.
111
+ */
112
+ get legacyCode() {
113
+ return LEGACY_LOWERCASE_CODES.has(this.code) ? this.code.toLowerCase() : this.code;
114
+ }
78
115
  get isNotFound() {
79
116
  return this.status === 404;
80
117
  }
@@ -87,7 +124,17 @@ var AuraError = class _AuraError extends Error {
87
124
  get isRateLimited() {
88
125
  return this.status === 429;
89
126
  }
127
+ /**
128
+ * Quota mensuel du plan atteint (HTTP 403, `code: 'QUOTA_EXCEEDED'`). Le message nomme la
129
+ * métrique, l'usage, la limite et la date de remise à zéro ; ce n'est pas un refus d'autorisation.
130
+ */
131
+ get isQuotaExceeded() {
132
+ return this.code === "QUOTA_EXCEEDED";
133
+ }
90
134
  };
135
+ function isGenericCode(code) {
136
+ return code === "UNAUTHORIZED" || code === "BAD_REQUEST" || code === "CONFLICT" || code.startsWith("HTTP_");
137
+ }
91
138
  function isAuraError(error) {
92
139
  return error instanceof AuraError || typeof error === "object" && error !== null && error.__isAuraError === true;
93
140
  }
@@ -243,6 +290,24 @@ function decodeJwtPayload(token) {
243
290
  return null;
244
291
  }
245
292
  }
293
+ function userFromAccessToken(token) {
294
+ const c = decodeJwtPayload(token);
295
+ if (!c || typeof c.sub !== "string") return null;
296
+ const meta = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
297
+ const amr = Array.isArray(c.amr) ? c.amr : [];
298
+ return {
299
+ id: c.sub,
300
+ email: typeof c.email === "string" ? c.email : null,
301
+ role: "authenticated",
302
+ email_verified: false,
303
+ is_banned: false,
304
+ is_anonymous: amr.some((a) => a?.method === "anonymous"),
305
+ mfa_enabled: c.aal === "aal2",
306
+ user_metadata: meta(c.user_metadata),
307
+ app_metadata: meta(c.app_metadata),
308
+ created_at: ""
309
+ };
310
+ }
246
311
  function isTokenExpired(token, marginSec = 0) {
247
312
  const payload = decodeJwtPayload(token);
248
313
  if (!payload || typeof payload.exp !== "number") return true;
@@ -352,6 +417,17 @@ var BaseAuthStore = class {
352
417
  // src/fetch.ts
353
418
  var REFRESH_MARGIN_SEC = 30;
354
419
  var RETRY_AFTER_CAP_MS = 6e4;
420
+ function networkErrorMessage(err, url) {
421
+ const cause = err?.cause;
422
+ const reason = cause?.code ?? cause?.message ?? (err instanceof Error ? err.message : "request failed");
423
+ let target = url;
424
+ try {
425
+ const u = new URL(url);
426
+ target = `${u.origin}${u.pathname}`;
427
+ } catch {
428
+ }
429
+ return `Cannot reach ${target} (${reason}). Check the project URL (NEXT_PUBLIC_AURABASE_URL) and your network.`;
430
+ }
355
431
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
356
432
  function unwrapEnvelope(body) {
357
433
  if (body !== null && typeof body === "object" && "data" in body) {
@@ -473,7 +549,7 @@ async function doRefresh(client) {
473
549
  error: new AuraError(0, {
474
550
  error: timedOut ? { code: "timeout", message: `Refresh timed out after ${timeoutMs}ms` } : {
475
551
  code: "network_error",
476
- message: err instanceof Error ? err.message : "Network request failed"
552
+ message: networkErrorMessage(err, `${client.baseUrl}/v1/auth/refresh`)
477
553
  }
478
554
  })
479
555
  };
@@ -674,7 +750,7 @@ async function fetchWithAuth(url, init, client) {
674
750
  error: new AuraError(0, {
675
751
  error: timedOut ? { code: "timeout", message: `Request timed out after ${timeoutMs}ms` } : {
676
752
  code: "network_error",
677
- message: err instanceof Error ? err.message : "Network request failed"
753
+ message: networkErrorMessage(err, url)
678
754
  }
679
755
  })
680
756
  };
@@ -823,13 +899,16 @@ function parseCookieHeader(header) {
823
899
  }
824
900
  return result;
825
901
  }
902
+ function sameSiteAttribute(v) {
903
+ return v.charAt(0).toUpperCase() + v.slice(1);
904
+ }
826
905
  function serializeCookieHeader(name, value, options = {}) {
827
906
  const parts = [`${name}=${encodeURIComponent(value)}`];
828
907
  if (options.path) parts.push(`Path=${options.path}`);
829
908
  if (options.domain) parts.push(`Domain=${options.domain}`);
830
909
  if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
831
910
  if (options.secure) parts.push("Secure");
832
- if (options.sameSite) parts.push(`SameSite=${options.sameSite}`);
911
+ if (options.sameSite) parts.push(`SameSite=${sameSiteAttribute(options.sameSite)}`);
833
912
  if (options.httpOnly) parts.push("HttpOnly");
834
913
  return parts.join("; ");
835
914
  }
@@ -920,6 +999,9 @@ var LocalAuthStore = class extends BaseAuthStore {
920
999
  /**
921
1000
  * Populate the store from a raw `Cookie` header string (server-side).
922
1001
  * Looks for the key matching `this.key`.
1002
+ *
1003
+ * Le cookie ne porte que `{ token, refreshToken }` (AUTH-036) : l'utilisateur est reconstruit à partir des
1004
+ * claims du jeton (non vérifié — `auth.getUser()` le fait vérifier par le serveur).
923
1005
  */
924
1006
  loadFromCookie(cookieString) {
925
1007
  const prefix = `${this.key}=`;
@@ -928,20 +1010,22 @@ var LocalAuthStore = class extends BaseAuthStore {
928
1010
  try {
929
1011
  const raw = decodeURIComponent(entry.slice(prefix.length));
930
1012
  const parsed = JSON.parse(raw);
931
- if (parsed.token && parsed.refreshToken && parsed.user) {
932
- super.save(parsed.token, parsed.refreshToken, parsed.user);
1013
+ const user = parsed.token ? userFromAccessToken(parsed.token) : null;
1014
+ if (parsed.token && parsed.refreshToken && user) {
1015
+ super.save(parsed.token, parsed.refreshToken, user);
933
1016
  }
934
1017
  } catch {
935
1018
  }
936
1019
  }
937
1020
  /**
938
- * Serialize current auth state into a `Set-Cookie` value.
1021
+ * Serialize the session tokens into a `Set-Cookie` value. The `user` object is NOT included: its
1022
+ * `user_metadata` is already inside the access token, and sending it twice doubled the cookie
1023
+ * (5 KB of metadata gave 4 cookies and 13 139 bytes).
939
1024
  */
940
1025
  exportToCookie(options = {}) {
941
1026
  const data = {
942
1027
  token: this.token,
943
- refreshToken: this.refreshToken,
944
- user: this.user
1028
+ refreshToken: this.refreshToken
945
1029
  };
946
1030
  const encoded = encodeURIComponent(JSON.stringify(data));
947
1031
  const parts = [`${this.key}=${encoded}`];
@@ -949,7 +1033,7 @@ var LocalAuthStore = class extends BaseAuthStore {
949
1033
  if (options.domain) parts.push(`Domain=${options.domain}`);
950
1034
  if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
951
1035
  if (options.secure) parts.push("Secure");
952
- if (options.sameSite) parts.push(`SameSite=${options.sameSite}`);
1036
+ if (options.sameSite) parts.push(`SameSite=${sameSiteAttribute(options.sameSite)}`);
953
1037
  if (options.httpOnly) parts.push("HttpOnly");
954
1038
  return parts.join("; ");
955
1039
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurabase/core",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Cœur du SDK Aurabase : fetch résilient, erreurs, stores auth, types de réponse (infrastructure interne)",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -31,12 +31,12 @@
31
31
  "author": "Aurabase",
32
32
  "repository": {
33
33
  "type": "git",
34
- "url": "git+https://github.com/daylami555/aurabase.git",
34
+ "url": "git+https://github.com/Aurabase-cloud/Aurabase.git",
35
35
  "directory": "aurabase-js/packages/core"
36
36
  },
37
37
  "homepage": "https://aurabase.cloud",
38
38
  "bugs": {
39
- "url": "https://github.com/daylami555/aurabase/issues"
39
+ "url": "https://github.com/Aurabase-cloud/Aurabase/issues"
40
40
  },
41
41
  "keywords": [
42
42
  "aurabase",