@aurabase/core 0.4.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.
@@ -0,0 +1,1231 @@
1
+ /**
2
+ * Codes d'erreur produits par le SDK (LOT 3, finding I4 : taxonomie ad hoc non
3
+ * typée). Union fermée de tous les codes émis SDK-side (`grep new AuraError` sur
4
+ * `packages/*\/src`) + les codes backend usuels rencontrés (`PGRST116`), plus
5
+ * `(string & {})` pour rester ouvert à tout code backend arbitraire (`error.error.code`)
6
+ * sans perdre l'autocomplétion sur les codes connus (pattern "LiteralUnion").
7
+ *
8
+ * Provenance des codes SDK-side :
9
+ * - fetch.ts (core) : no_session, network_error, invalid_response, refresh_discarded, timeout
10
+ * - AuthService.ts : no_session, pkce_generation_failed, no_code_verifier, missing_email,
11
+ * unverifiable_token, invalid_issuer, invalid_audience
12
+ * - jwks.ts : jwks_fetch_failed, no_matching_key, signature_invalid, token_expired,
13
+ * token_not_yet_valid, invalid_jwt, unsupported_alg
14
+ * - storage/path.ts : invalid_path
15
+ * - db/QueryBuilder.ts: PGRST116 (parité PostgREST : `.single()` sur 0/plusieurs lignes)
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 & {});
18
+ /**
19
+ * Structured error thrown/returned by the Aurabase SDK.
20
+ * Mirrors the backend's `AuraError` JSON shape.
21
+ */
22
+ declare class AuraError extends Error {
23
+ readonly status: number;
24
+ readonly code: AuraErrorCode;
25
+ readonly details: unknown;
26
+ /** Marqueur runtime pour `isAuraError` (détection cross-realm/cross-bundle). */
27
+ protected readonly __isAuraError = true;
28
+ constructor(status: number, body?: {
29
+ error?: {
30
+ code?: string;
31
+ message?: string;
32
+ };
33
+ message?: string;
34
+ } | null);
35
+ get isNotFound(): boolean;
36
+ get isUnauthorized(): boolean;
37
+ get isForbidden(): boolean;
38
+ get isRateLimited(): boolean;
39
+ }
40
+ declare function isAuraError(error: unknown): error is AuraError;
41
+
42
+ interface Meta {
43
+ total?: number;
44
+ /**
45
+ * Curseur opaque de pagination keyset (voir `QueryBuilder.cursor()`, `@aurabase/db`).
46
+ * SPÉCIFIQUE AURA-DB : n'est émis QUE sur le chemin aura-db natif (MongoDB, ou
47
+ * PostgreSQL avec PostgREST désactivé). Absent sur le chemin PostgREST — le moteur
48
+ * NOMINAL d'un projet Postgres, qui ne supporte que `limit`/`offset` — où `.cursor()`
49
+ * échoue avec un 400 explicite plutôt que d'émettre ce champ.
50
+ */
51
+ next_cursor?: string;
52
+ }
53
+ /**
54
+ * Réponse en SUCCÈS porteuse de contenu. `error` y est `null` par construction.
55
+ */
56
+ interface AuraSuccess<T> {
57
+ data: T;
58
+ error: null;
59
+ meta?: Meta;
60
+ }
61
+ /**
62
+ * Réponse en SUCCÈS SANS contenu — `data` ET `error` nuls.
63
+ *
64
+ * Ce membre n'est PAS un artifice de typage : il décrit des producteurs bien
65
+ * réels du SDK, tous vérifiés par lecture du code (recensement complet dans
66
+ * `.superpowers/sdd/revue-finale/groupe-P-report.md`) :
67
+ * - `fetchWithAuth` sur un 204 No Content, et sur un 2xx à corps vide — pour
68
+ * N'IMPORTE QUEL `T` (le cas emblématique : `db.from(t).delete().eq(...)`
69
+ * sans `.select()` est typé `Row[]` mais PostgREST répond 204) ;
70
+ * - `AuthService.signOut()` quand il n'y a aucun refresh token à révoquer ;
71
+ * - `StorageService.remove()` en multi-clés (toutes les suppressions ont
72
+ * réussi, aucune charge utile à agréger) ;
73
+ * - `QueryBuilder.maybeSingle()` sur 0 ligne (0 ligne n'est pas une erreur).
74
+ *
75
+ * C'est précisément pour eux que `AuraResponse` N'EST PAS l'union naïve
76
+ * `{data: T, error: null} | {data: null, error: AuraError}` : celle-ci
77
+ * promettrait `T` après un simple `if (error) return`, alors que `data` vaut
78
+ * réellement `null` sur tous les cas ci-dessus. Elle serait UNSOUND.
79
+ */
80
+ interface AuraNoContent {
81
+ data: null;
82
+ error: null;
83
+ meta?: Meta;
84
+ }
85
+ /**
86
+ * Réponse en ÉCHEC. `data` y est `null` par construction — aucun producteur du
87
+ * SDK ne renvoie de données ET une erreur.
88
+ */
89
+ interface AuraFailure {
90
+ data: null;
91
+ error: AuraError;
92
+ meta?: Meta;
93
+ }
94
+ /**
95
+ * Enveloppe de réponse du SDK : union à TROIS membres.
96
+ *
97
+ * Ce qu'elle apporte par rapport à l'ancienne interface plate
98
+ * (`{data: T | null, error: AuraError | null}`) :
99
+ * - la combinaison IMPOSSIBLE `{data: T, error: AuraError}` n'est plus
100
+ * constructible (aucun producteur ne la produit, le type le dit désormais) ;
101
+ * - `data` non nul ⇒ TypeScript sait que `error` est `null` ;
102
+ * - `error` non nul ⇒ TypeScript sait que `data` est `null`.
103
+ *
104
+ * Ce qu'elle N'apporte PAS, délibérément : `data` ne se réduit pas à `T` après
105
+ * `if (error) return`, parce que `AuraNoContent` reste possible pour tout `T`
106
+ * (204). L'idiome sound côté consommateur est donc de tester `data`, pas
107
+ * `error` :
108
+ *
109
+ * ```ts
110
+ * const { data, error } = await client.db.from('users').select('*')
111
+ * if (error) return handle(error)
112
+ * if (data === null) return handleEmpty() // 204 / corps vide
113
+ * data.forEach(...) // ici `data` est bien `Row[]`
114
+ * // ou, en un seul test :
115
+ * if (data !== null) data.forEach(...)
116
+ * ```
117
+ *
118
+ * Supprimer ce troisième membre supposerait de rendre honnête le PARAMÈTRE `T`
119
+ * de chaque producteur pouvant répondre sans contenu — c'est la route suivie
120
+ * par `@supabase/postgrest-js` (`PostgrestMaybeSingleResponse<T> =
121
+ * PostgrestSingleResponse<T | null>`, et `Result = null` sur une mutation sans
122
+ * `.select()`). C'est un changement cassant du paquet `@aurabase/db`, hors du
123
+ * périmètre de ce lot : il est documenté comme suite dans le rapport.
124
+ */
125
+ type AuraResponse<T> = AuraSuccess<T> | AuraNoContent | AuraFailure;
126
+ interface User {
127
+ id: string;
128
+ email: string | null;
129
+ phone?: string | null;
130
+ role: string;
131
+ email_verified: boolean;
132
+ is_banned: boolean;
133
+ is_anonymous: boolean;
134
+ mfa_enabled: boolean;
135
+ avatar_url?: string | null;
136
+ name?: string | null;
137
+ user_metadata: Record<string, unknown>;
138
+ app_metadata: Record<string, unknown>;
139
+ created_at: string;
140
+ last_sign_in_at?: string | null;
141
+ }
142
+ interface TokenPair {
143
+ access_token: string;
144
+ refresh_token: string;
145
+ token_type: string;
146
+ expires_in: number;
147
+ user: User;
148
+ provider_token?: string | null;
149
+ provider_refresh_token?: string | null;
150
+ }
151
+ interface MfaChallenge {
152
+ mfa_required: true;
153
+ mfa_token: string;
154
+ mfa_setup_required?: boolean;
155
+ }
156
+ type LoginResponse = TokenPair | MfaChallenge;
157
+ type AuthEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'MFA_CHALLENGE' | 'PASSWORD_RECOVERY';
158
+ /**
159
+ * Payload émis par `onAuthStateChange`. NOTE (LOT 3, 3.4) : `mfaToken`/`mfaSetupRequired`
160
+ * ne sont présents QUE lorsque `event === 'MFA_CHALLENGE'` (posés par `AuthService`
161
+ * uniquement sur cet événement — voir `_emitEvent` dans `AuthService.ts`) ; sur tout
162
+ * autre `event`, ces deux champs sont `undefined`. Le type reste une interface plate
163
+ * (pas une union discriminée) pour ne pas casser les consommateurs existants qui
164
+ * déstructurent `{event, user, accessToken}` sans varier selon `event` — mais un
165
+ * consommateur qui lit `mfaToken` DOIT d'abord vérifier `event === 'MFA_CHALLENGE'`.
166
+ */
167
+ interface AuthChangePayload {
168
+ event: AuthEvent;
169
+ user: User | null;
170
+ accessToken: string | null;
171
+ /** Présent uniquement si `event === 'MFA_CHALLENGE'`. */
172
+ mfaToken?: string;
173
+ /** Présent uniquement si `event === 'MFA_CHALLENGE'`. */
174
+ mfaSetupRequired?: boolean;
175
+ /**
176
+ * Token de récupération opaque à passer à `resetPassword(token, newPassword)`.
177
+ * Présent uniquement si `event === 'PASSWORD_RECOVERY'` (extrait du lien email
178
+ * `?token=…&type=recovery` par `detectSessionInUrl`). `undefined` sur tout autre
179
+ * événement.
180
+ */
181
+ recoveryToken?: string;
182
+ }
183
+ interface SignUpRequest {
184
+ email: string;
185
+ password: string;
186
+ captcha_token?: string;
187
+ }
188
+ interface SignInRequest {
189
+ email: string;
190
+ password: string;
191
+ captcha_token?: string;
192
+ }
193
+ interface MagicLinkRequest {
194
+ email: string;
195
+ create_user?: boolean;
196
+ captcha_token?: string;
197
+ redirect_url?: string;
198
+ }
199
+ interface OAuthSignInOptions {
200
+ redirectTo?: string;
201
+ scopes?: string;
202
+ queryParams?: Record<string, string>;
203
+ /**
204
+ * Active le flux PKCE (génère + stocke un `code_verifier`, envoie
205
+ * `code_challenge`/`code_challenge_method=S256` au provider). Opt-in :
206
+ * absent ou `'implicit'` conserve le comportement existant (aucun
207
+ * paramètre PKCE) pour ne pas casser silencieusement les consommateurs
208
+ * actuels du flux implicite.
209
+ */
210
+ flowType?: 'pkce' | 'implicit';
211
+ }
212
+ interface PasswordResetRequest {
213
+ email: string;
214
+ }
215
+ interface UpdateUserRequest {
216
+ email?: string;
217
+ phone?: string;
218
+ password?: string;
219
+ current_password?: string;
220
+ data?: Record<string, unknown>;
221
+ }
222
+ interface MfaEnrollResponse {
223
+ otpauth_url: string;
224
+ secret: string;
225
+ }
226
+ interface MfaVerifyRequest {
227
+ mfa_token: string;
228
+ code: string;
229
+ }
230
+ interface SessionInfo {
231
+ id: string;
232
+ device_info?: string | null;
233
+ ip_address?: string | null;
234
+ created_at: string;
235
+ expires_at: string;
236
+ last_used_at: string;
237
+ is_current: boolean;
238
+ }
239
+ type FilterOp = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'not_in' | 'like' | 'ilike' | 'is_null' | 'is_not_null' | 'between';
240
+ interface QueryFilter {
241
+ column: string;
242
+ op: string;
243
+ value: unknown;
244
+ }
245
+ type CountMode = 'exact' | 'estimated';
246
+ interface QueryOptions {
247
+ select?: string[];
248
+ filters?: QueryFilter[];
249
+ sort_by?: string;
250
+ sort_order?: 'asc' | 'desc';
251
+ limit?: number;
252
+ offset?: number;
253
+ count?: CountMode;
254
+ }
255
+ interface SchemaColumn {
256
+ name: string;
257
+ col_type: string;
258
+ nullable: boolean;
259
+ unique: boolean;
260
+ default_val?: string | null;
261
+ references?: {
262
+ table: string;
263
+ column: string;
264
+ constraint_name?: string | null;
265
+ } | null;
266
+ }
267
+ interface SchemaIndex {
268
+ name: string;
269
+ columns: string[];
270
+ unique: boolean;
271
+ }
272
+ interface SchemaTable {
273
+ name: string;
274
+ columns: SchemaColumn[];
275
+ primary_key?: string;
276
+ indexes: SchemaIndex[];
277
+ rls_enabled: boolean;
278
+ realtime_enabled: boolean;
279
+ }
280
+ interface SchemaFunctionArg {
281
+ name: string;
282
+ data_type: string;
283
+ mode: string;
284
+ }
285
+ interface SchemaFunction {
286
+ name: string;
287
+ args: SchemaFunctionArg[];
288
+ returns: string;
289
+ is_set_returning: boolean;
290
+ }
291
+ /**
292
+ * Type enum Postgres (`pg_type.typtype='e'`) exposé par `GET /schema` (LOT B).
293
+ * `values` est ordonné (`enumsortorder`). Le générateur SDK (`@aurabase/gen`)
294
+ * en dérive une union de littéraux `Database['public']['Enums'][name]`.
295
+ */
296
+ interface SchemaEnum {
297
+ name: string;
298
+ values: string[];
299
+ }
300
+ /**
301
+ * Options de transformation d'image (vocabulaire façon Supabase) appliquées
302
+ * côté rendu backend (`GET /v1/storage/{pid}/{bucket}/{key}?width=&height=&
303
+ * fit=&format=&quality=`). Voir `renderTransformParams` (`@aurabase/storage`)
304
+ * pour le mapping vers les query params du backend.
305
+ */
306
+ interface ImageTransform {
307
+ width?: number;
308
+ height?: number;
309
+ resize?: 'cover' | 'contain' | 'fill';
310
+ quality?: number;
311
+ format?: 'origin' | 'jpeg' | 'png' | 'webp' | 'gif';
312
+ }
313
+ interface StorageBucket {
314
+ id: string;
315
+ name: string;
316
+ public: boolean;
317
+ file_size_limit?: number | null;
318
+ allowed_mime_types?: string[] | null;
319
+ created_at: string;
320
+ updated_at: string;
321
+ }
322
+ /**
323
+ * Résultat de `storage.upload()`. Forme alignée sur la réponse réelle du backend
324
+ * (`services/aura-storage/src/storage/mod.rs` `UploadResult`, renvoyée telle quelle par
325
+ * `handlers/upload.rs`) : f05 — l'ancienne déclaration promettait `mime_type` (jamais
326
+ * renvoyé, `TypeError` garanti à l'usage) et omettait `bucket`/`content_type`/`etag`
327
+ * (réellement présents).
328
+ */
329
+ interface UploadResult {
330
+ /** Clé unique de l'objet (`<uuid>.<ext>`) relative au bucket. */
331
+ key: string;
332
+ /**
333
+ * Bucket PHYSIQUE (`aura-{project_id}`), pas l'identifiant logique passé à `upload()` —
334
+ * même remarque que `FileEntry.bucket` ci-dessous.
335
+ */
336
+ bucket: string;
337
+ url: string;
338
+ size: number;
339
+ content_type: string;
340
+ etag?: string | null;
341
+ }
342
+ /**
343
+ * Entrée renvoyée par `storage.list()`. Forme alignée sur la réponse réelle du
344
+ * backend (relevée sur stack live) : l'ancienne déclaration annonçait
345
+ * `name`/`bucket_id`/`mime_type`/`created_at`, tous absents à l'exécution.
346
+ * `key` est RELATIVE au bucket (dé-préfixée par le SDK), donc directement
347
+ * réutilisable par `download`/`remove`/`getMetadata`/`copy`/`move`.
348
+ */
349
+ interface FileEntry {
350
+ key: string;
351
+ bucket: string;
352
+ size: number;
353
+ content_type: string;
354
+ etag?: string | null;
355
+ last_modified?: string | null;
356
+ metadata: Record<string, unknown>;
357
+ }
358
+ /** Métadonnées d'un objet storage — forme réelle retournée par getMetadata() */
359
+ interface ObjectMeta {
360
+ key: string;
361
+ bucket: string;
362
+ size: number;
363
+ content_type: string;
364
+ etag?: string | null;
365
+ last_modified?: string | null;
366
+ metadata: Record<string, string>;
367
+ }
368
+ /** Événement serveur brut reçu via WebSocket (union discriminée par type) */
369
+ type ServerMessage = ServerSubscribedMsg | ServerEventMsg | ServerPongMsg | ServerErrorMsg | ServerTokenRefreshedMsg | ServerPresenceStateMsg | BroadcastAckMessage;
370
+ interface ServerSubscribedMsg {
371
+ type: 'subscribed';
372
+ channel: string;
373
+ subscription_id?: string;
374
+ history: RealtimeEvent[];
375
+ ref_id?: string;
376
+ }
377
+ interface ServerEventMsg {
378
+ type: 'event';
379
+ id: string;
380
+ event: 'insert' | 'update' | 'delete' | 'broadcast' | 'presence' | 'system';
381
+ topic: string;
382
+ payload: Record<string, unknown>;
383
+ timestamp: string;
384
+ allowed_sub_ids?: string[];
385
+ }
386
+ interface ServerPongMsg {
387
+ type: 'pong';
388
+ }
389
+ interface ServerErrorMsg {
390
+ type: 'error';
391
+ message: string;
392
+ }
393
+ interface ServerTokenRefreshedMsg {
394
+ type: 'token_refreshed';
395
+ }
396
+ interface ServerPresenceStateMsg {
397
+ type: 'presence_state';
398
+ channel: string;
399
+ presences: PresenceInfo[];
400
+ }
401
+ /** Événement realtime (CDC, broadcast, presence) */
402
+ interface RealtimeEvent<T = Record<string, unknown>> {
403
+ id: string;
404
+ event: 'insert' | 'update' | 'delete' | 'broadcast' | 'presence' | 'system';
405
+ topic: string;
406
+ payload: T;
407
+ timestamp: string;
408
+ /** IDs des subscriptions autorisées par RLS. Absent = pas de filtre. */
409
+ allowed_sub_ids?: string[];
410
+ /** Ref ID corrélé à la requête client (si fourni) */
411
+ ref_id?: string;
412
+ }
413
+ /** Accusé de réception d'un broadcast (envoyé si config.broadcast.ack = true) */
414
+ interface BroadcastAckMessage {
415
+ type: 'broadcast_ack';
416
+ message_id: string;
417
+ ref_id?: string;
418
+ }
419
+ /** Payload CDC (postgres_changes) avec old_record et type d'operation */
420
+ interface CdcPayload {
421
+ schema: string;
422
+ table: string;
423
+ type: 'INSERT' | 'UPDATE' | 'DELETE';
424
+ record: Record<string, unknown>;
425
+ old_record: Record<string, unknown> | null;
426
+ _truncated?: boolean;
427
+ }
428
+ /** Status de subscription */
429
+ type RealtimeSubscribeStatus = 'SUBSCRIBED' | 'CLOSED' | 'CHANNEL_ERROR' | 'TIMED_OUT';
430
+ /** Callback de subscription */
431
+ type SubscribeCallback = (status: RealtimeSubscribeStatus, err?: Error) => void;
432
+ /** Types d'écoute supportés (pattern Supabase) */
433
+ type RealtimeListenType = 'postgres_changes' | 'broadcast' | 'presence';
434
+ /** Config pour postgres_changes */
435
+ interface PostgresChangesFilter {
436
+ event: 'INSERT' | 'UPDATE' | 'DELETE' | '*';
437
+ schema?: string;
438
+ table?: string;
439
+ /**
440
+ * Filtre sur colonne, syntaxe PostgREST/Supabase : `"column=operator.value"`.
441
+ *
442
+ * **Opérateurs supportés** : `eq, neq, lt, lte, gt, gte, in, like, ilike, is,
443
+ * match, imatch, isdistinct`.
444
+ *
445
+ * - `eq`/`neq` : égalité/inégalité (comparaison textuelle).
446
+ * - `lt`/`lte`/`gt`/`gte` : comparaison numérique (échoue — pas de match — si
447
+ * la valeur n'est pas numérique).
448
+ * - `in` : appartenance à une liste, `"status=in.(active,pending)"`.
449
+ * - `like`/`ilike` : motif SQL (`%` = sous-chaîne, `_` = 1 caractère), `ilike`
450
+ * insensible à la casse. Ex: `"name=like.jo%"`.
451
+ * - `is` : `"col=is.null"` / `"col=is.true"` / `"col=is.false"` — compare la
452
+ * valeur JSON réelle, pas sa représentation texte.
453
+ * - `match`/`imatch` : expression régulière (`imatch` insensible à la casse).
454
+ * - `isdistinct` : distinct au sens SQL — `NULL` est distinct de toute valeur
455
+ * non-NULL.
456
+ *
457
+ * **Négation** : préfixer l'opérateur par `not.`, ex: `"status=not.eq.done"`.
458
+ *
459
+ * **AND** : plusieurs conditions séparées par des virgules, ex:
460
+ * `"room_id=eq.42,qty=gt.5"` (toutes doivent matcher). Les virgules internes
461
+ * d'un `in.(a,b,c)` ne séparent PAS les conditions.
462
+ *
463
+ * **Où c'est évalué** : le serveur `aura-realtime` filtre ces conditions de
464
+ * façon **autoritaire** avant l'envoi au client — un `filter` invalide y est
465
+ * fail-closed (l'event est exclu, jamais laissé passer par défaut). Le SDK
466
+ * réévalue ensuite la même syntaxe côté client comme second rideau
467
+ * (defense-in-depth) : il ne peut que sur-filtrer, jamais faire fuiter un
468
+ * event que le serveur aurait dû exclure.
469
+ *
470
+ * **DELETE** : le prédicat est évalué sur l'**ancienne ligne** (`old_record`),
471
+ * puisque le `record` d'un DELETE est vide côté CDC. Si votre table utilise
472
+ * `REPLICA IDENTITY DEFAULT`, `old_record` ne contient que la clé primaire —
473
+ * un filtre sur une autre colonne exclura systématiquement les DELETE, **sauf
474
+ * `is.null`/`isdistinct`** qui traitent une colonne absente comme `NULL` et
475
+ * peuvent donc matcher même sans cette colonne dans `old_record`.
476
+ */
477
+ filter?: string;
478
+ }
479
+ /** Config pour broadcast */
480
+ interface BroadcastFilter {
481
+ event: string;
482
+ }
483
+ /** Config pour presence */
484
+ interface PresenceFilter {
485
+ event: 'sync' | 'join' | 'leave';
486
+ }
487
+ /** Options de channel — compatible Supabase */
488
+ interface ChannelConfig {
489
+ private?: boolean;
490
+ /** Configuration broadcast pour ce channel */
491
+ broadcast?: {
492
+ /** Si true, le serveur ACK chaque send() (résout la Promise) */
493
+ ack?: boolean;
494
+ /** Si true, le client reçoit ses propres broadcasts (self-echo) */
495
+ self?: boolean;
496
+ };
497
+ /** Configuration présence */
498
+ config?: {
499
+ presence?: {
500
+ /** Clé de présence — permet de regrouper plusieurs onglets/devices du même user */
501
+ key?: string;
502
+ };
503
+ };
504
+ }
505
+ /** Payload d'un broadcast à envoyer */
506
+ interface BroadcastPayload {
507
+ type: 'broadcast';
508
+ event: string;
509
+ payload: Record<string, unknown>;
510
+ /** Ref ID pour la corrélation request/response (optionnel) */
511
+ ref_id?: string;
512
+ }
513
+ /** Presence state (map de key → presences) */
514
+ type PresenceState = Record<string, PresenceInfo[]>;
515
+ interface PresenceInfo {
516
+ client_id: string;
517
+ user_id?: string | null;
518
+ metadata: Record<string, unknown>;
519
+ joined_at: string;
520
+ last_seen: string;
521
+ }
522
+ interface ChatMessage {
523
+ role: 'system' | 'user' | 'assistant';
524
+ content: string;
525
+ }
526
+ interface ChatResponse {
527
+ model: string;
528
+ content: string;
529
+ input_tokens?: number;
530
+ output_tokens?: number;
531
+ }
532
+ interface EmbedRequest {
533
+ text: string;
534
+ namespace: string;
535
+ metadata?: Record<string, unknown>;
536
+ }
537
+ interface EmbedResponse {
538
+ id: string;
539
+ dimensions: number;
540
+ }
541
+ interface RagRequest {
542
+ question: string;
543
+ namespace: string;
544
+ history?: ChatMessage[];
545
+ system?: string;
546
+ }
547
+ interface RagResponse {
548
+ answer: string;
549
+ sources: Array<{
550
+ id: string;
551
+ content: string;
552
+ metadata: Record<string, unknown>;
553
+ similarity: number;
554
+ }>;
555
+ model: string;
556
+ tokens?: number;
557
+ }
558
+ interface RagIngestRequest {
559
+ namespace: string;
560
+ content: string;
561
+ metadata?: Record<string, unknown>;
562
+ }
563
+ interface RagIngestResponse {
564
+ id: string;
565
+ chunks: number;
566
+ }
567
+ interface SemanticSearchResult {
568
+ id: string;
569
+ content: string;
570
+ metadata: Record<string, unknown>;
571
+ similarity: number;
572
+ }
573
+ interface FunctionDef {
574
+ id: string;
575
+ project_id: string;
576
+ name: string;
577
+ runtime: string;
578
+ code: string;
579
+ code_hash: string;
580
+ env_vars: Record<string, unknown>;
581
+ is_active: boolean;
582
+ created_at: string;
583
+ updated_at: string;
584
+ }
585
+ interface Job {
586
+ id: string;
587
+ project_id: string;
588
+ function_name: string;
589
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'dead';
590
+ payload: unknown;
591
+ attempts: number;
592
+ max_attempts: number;
593
+ error?: string | null;
594
+ scheduled_at: string;
595
+ started_at?: string | null;
596
+ created_at: string;
597
+ completed_at?: string | null;
598
+ }
599
+ interface CronJob {
600
+ id: string;
601
+ project_id: string;
602
+ name: string;
603
+ schedule: string;
604
+ function_name: string;
605
+ payload: unknown;
606
+ is_active: boolean;
607
+ last_run?: string | null;
608
+ next_run?: string | null;
609
+ created_at: string;
610
+ }
611
+ interface Notification {
612
+ id: string;
613
+ project_id?: string;
614
+ channel: 'email' | 'sms' | 'push' | 'webhook';
615
+ recipient: string;
616
+ subject?: string | null;
617
+ body: string;
618
+ status: 'queued' | 'processing' | 'sent' | 'failed' | 'delivered' | 'expired' | 'dead_lettered';
619
+ error?: string | null;
620
+ metadata?: Record<string, unknown>;
621
+ attempt_count?: number;
622
+ last_attempt_at?: string | null;
623
+ next_attempt_at?: string | null;
624
+ locked_until?: string | null;
625
+ lock_owner?: string | null;
626
+ provider_message_id?: string | null;
627
+ delivered_at?: string | null;
628
+ expires_at?: string | null;
629
+ idempotency_key?: string | null;
630
+ payload_hash?: string | null;
631
+ last_error?: string | null;
632
+ last_error_code?: string | null;
633
+ last_provider_response?: string | null;
634
+ processing_started_at?: string | null;
635
+ completed_at?: string | null;
636
+ updated_at?: string;
637
+ sent_at?: string | null;
638
+ created_at: string;
639
+ }
640
+ interface SendNotificationRequest {
641
+ channel: 'email' | 'sms' | 'push' | 'webhook';
642
+ recipient: string;
643
+ body?: string;
644
+ subject?: string;
645
+ template_id?: string;
646
+ variables?: Record<string, unknown>;
647
+ metadata?: Record<string, unknown>;
648
+ idempotency_key?: string;
649
+ }
650
+ interface BatchSendItemResult {
651
+ index: number;
652
+ status: 'queued' | 'error';
653
+ notification?: Notification | null;
654
+ error?: string | null;
655
+ }
656
+ interface BatchSendResponse {
657
+ items: BatchSendItemResult[];
658
+ }
659
+ interface NotificationTemplate {
660
+ id: string;
661
+ name: string;
662
+ channel: 'email' | 'sms' | 'push' | 'webhook';
663
+ subject?: string | null;
664
+ body: string;
665
+ variables?: string[];
666
+ created_at: string;
667
+ updated_at: string;
668
+ }
669
+ interface NotificationTemplatePreview {
670
+ subject?: string | null;
671
+ body: string;
672
+ }
673
+ interface NotificationAttempt {
674
+ id: string;
675
+ notification_id: string;
676
+ project_id: string;
677
+ channel: 'email' | 'sms' | 'push' | 'webhook';
678
+ provider: string;
679
+ attempt_number: number;
680
+ status: 'processing' | 'sent' | 'failed' | 'retry_scheduled' | 'dead_lettered';
681
+ started_at: string;
682
+ completed_at?: string | null;
683
+ duration_ms?: number | null;
684
+ error_code?: string | null;
685
+ error_message?: string | null;
686
+ provider_response?: string | null;
687
+ created_at: string;
688
+ }
689
+ interface NotificationDeadLetter {
690
+ id: string;
691
+ notification_id: string;
692
+ project_id: string;
693
+ channel: 'email' | 'sms' | 'push' | 'webhook';
694
+ recipient: string;
695
+ subject?: string | null;
696
+ body: string;
697
+ metadata?: Record<string, unknown>;
698
+ payload_hash?: string | null;
699
+ idempotency_key?: string | null;
700
+ attempt_count: number;
701
+ last_error: string;
702
+ last_error_code: string;
703
+ last_provider_response?: string | null;
704
+ failed_at: string;
705
+ created_at: string;
706
+ }
707
+ interface NotificationEvent {
708
+ id: string;
709
+ project_id: string;
710
+ subject: string;
711
+ event_type: string;
712
+ status: 'received' | 'matched' | 'ignored' | 'failed' | 'enqueued';
713
+ rule_id?: string | null;
714
+ notification_id?: string | null;
715
+ error?: string | null;
716
+ metadata?: Record<string, unknown>;
717
+ created_at: string;
718
+ }
719
+ interface NotificationProviderLog {
720
+ timestamp: string;
721
+ notification_id: string;
722
+ channel: 'email' | 'sms' | 'push' | 'webhook';
723
+ provider: string;
724
+ status: string;
725
+ duration_ms?: number | null;
726
+ error_code?: string | null;
727
+ error_message?: string | null;
728
+ provider_response?: string | null;
729
+ provider_message_id?: string | null;
730
+ }
731
+ interface NotificationQueueStats {
732
+ queued_count: number;
733
+ processing_count: number;
734
+ retry_scheduled_count: number;
735
+ expired_processing_count: number;
736
+ next_retry_at_min?: string | null;
737
+ }
738
+ interface NotificationChannelStats {
739
+ channel: 'email' | 'sms' | 'push' | 'webhook';
740
+ total: number;
741
+ sent: number;
742
+ delivered: number;
743
+ failed: number;
744
+ dead_lettered: number;
745
+ queued: number;
746
+ processing: number;
747
+ success_rate: number;
748
+ failure_rate: number;
749
+ }
750
+ interface NotificationStats {
751
+ window: string;
752
+ channel?: 'email' | 'sms' | 'push' | 'webhook' | null;
753
+ total: number;
754
+ sent: number;
755
+ delivered: number;
756
+ failed: number;
757
+ dead_lettered: number;
758
+ queued: number;
759
+ processing: number;
760
+ success_rate: number;
761
+ failure_rate: number;
762
+ by_status: Array<{
763
+ status: string;
764
+ count: number;
765
+ }>;
766
+ by_channel: NotificationChannelStats[];
767
+ timeline: Array<{
768
+ bucket: string;
769
+ total: number;
770
+ sent: number;
771
+ delivered: number;
772
+ failed: number;
773
+ dead_lettered: number;
774
+ }>;
775
+ }
776
+ interface NotificationSettings {
777
+ project_id: string;
778
+ smtp?: Record<string, unknown>;
779
+ twilio?: Record<string, unknown>;
780
+ fcm?: Record<string, unknown>;
781
+ apns?: Record<string, unknown>;
782
+ webhook?: Record<string, unknown>;
783
+ quotas?: Record<string, unknown>;
784
+ updated_at?: string | null;
785
+ }
786
+ interface NotificationRule {
787
+ id: string;
788
+ project_id: string;
789
+ name: string;
790
+ trigger_type: string;
791
+ condition: Record<string, unknown>;
792
+ template_id?: string | null;
793
+ channel: 'email' | 'sms' | 'push' | 'webhook';
794
+ recipient_expr: string;
795
+ enabled: boolean;
796
+ delay_seconds: number;
797
+ fire_count: number;
798
+ last_fired_at?: string | null;
799
+ created_at: string;
800
+ updated_at: string;
801
+ }
802
+ /**
803
+ * Événement d'observabilité interne du SDK. Émis best-effort via le hook `onEvent`
804
+ * (option client) et/ou `console.debug` (option `debug: true`) — voir `emitAuraEvent`.
805
+ * Les erreurs sont massivement avalées ailleurs dans le SDK (`catch {}` JWKS/storage/
806
+ * cookie/subscribers) : ce hook rend visibles les retries, timeouts, refresh
807
+ * silencieux et échecs JWKS/storage sans changer le contrat `AuraResponse`.
808
+ */
809
+ type AuraObservabilityEvent = {
810
+ kind: 'retry';
811
+ attempt: number;
812
+ status?: number;
813
+ url: string;
814
+ } | {
815
+ kind: 'timeout';
816
+ url: string;
817
+ } | {
818
+ kind: 'refresh-success';
819
+ } | {
820
+ kind: 'refresh-discarded';
821
+ reason: string;
822
+ } | {
823
+ kind: 'jwks-fetch-failed';
824
+ baseUrl: string;
825
+ } | {
826
+ kind: 'storage-blocked';
827
+ op: string;
828
+ };
829
+ declare function emitAuraEvent(onEvent: ((event: AuraObservabilityEvent) => void) | undefined, debug: boolean | undefined, event: AuraObservabilityEvent): void;
830
+ interface AuraClientOptions {
831
+ auth?: {
832
+ persistSession?: boolean;
833
+ storage?: BaseAuthStore;
834
+ /** Refresh proactif en arrière-plan + synchro multi-onglets (défaut true). */
835
+ autoRefresh?: boolean;
836
+ /**
837
+ * Détecte et consomme automatiquement une session présente dans l'URL au boot
838
+ * du client (callback OAuth) : fragment `#access_token=…` (flux implicit) ou
839
+ * query `?code=…` (flux PKCE), puis nettoie l'URL via `history.replaceState`.
840
+ * Défaut : `true` en navigateur, no-op hors navigateur (SSR/Node).
841
+ */
842
+ detectSessionInUrl?: boolean;
843
+ };
844
+ apiKey?: string;
845
+ fetch?: typeof globalThis.fetch;
846
+ /**
847
+ * SEC-F5 : si une clé `service_role` (`aura_sk_…`) est fournie en contexte NAVIGATEUR
848
+ * (thread principal ou Web Worker navigateur), `true` (DÉFAUT) fait ÉCHOUER la
849
+ * construction du client (`throw`) — cette clé à privilèges élevés (BYPASSRLS)
850
+ * fuiterait dans le bundle JS = compromission totale du projet. `false` rétrograde
851
+ * en simple `console.warn` (échappatoire explicite, à n'utiliser qu'en connaissance
852
+ * de cause). Sans effet côté serveur (où service_role est légitime).
853
+ */
854
+ refuseServiceRoleInBrowser?: boolean;
855
+ /** Retry transitoire des GET/HEAD (activé par défaut). `false` désactive. */
856
+ retry?: boolean | {
857
+ enabled?: boolean;
858
+ maxRetries?: number;
859
+ };
860
+ /**
861
+ * Timeout par défaut (ms) des requêtes JSON sans `signal` fourni (borne un serveur
862
+ * qui « hang »). N'affecte ni les uploads FormData ni les appels gérant leur propre
863
+ * annulation (invoke, download). `0` désactive. Défaut : 30 000 ms.
864
+ */
865
+ requestTimeoutMs?: number;
866
+ /**
867
+ * Hook d'observabilité (LOT 3, finding I8) : reçoit chaque `AuraObservabilityEvent`
868
+ * (retry transitoire, timeout, refresh de session réussi/écarté, échec fetch JWKS,
869
+ * storage bloqué). Best-effort — le SDK l'appelle dans un try/catch, ce hook ne
870
+ * peut jamais faire échouer une requête. `undefined` par défaut (aucune émission).
871
+ */
872
+ onEvent?: (event: AuraObservabilityEvent) => void;
873
+ /**
874
+ * Si `true`, chaque `AuraObservabilityEvent` est aussi journalisé via
875
+ * `console.debug('[aurabase]', event)`, en plus (ou à la place) du hook `onEvent`.
876
+ * Défaut `false`.
877
+ */
878
+ debug?: boolean;
879
+ }
880
+ interface IdentityInfo {
881
+ id: string;
882
+ provider: string;
883
+ provider_id: string;
884
+ identity_data: Record<string, unknown>;
885
+ auto_linked: boolean;
886
+ created_at: string;
887
+ }
888
+ interface AdminUser extends User {
889
+ }
890
+ interface AuditLogEntry {
891
+ id: string;
892
+ user_id?: string | null;
893
+ action: string;
894
+ ip_address?: string | null;
895
+ user_agent?: string | null;
896
+ created_at: string;
897
+ }
898
+ interface UserStats {
899
+ total: number;
900
+ verified: number;
901
+ banned: number;
902
+ mfa_enabled: number;
903
+ new_7d: number;
904
+ }
905
+ /**
906
+ * Sessions vues depuis l'admin (endpoint `admin/sessions`) : contient `user_id`
907
+ * (toutes sessions, tous utilisateurs) mais pas `is_current` (contrairement à
908
+ * `SessionInfo`, qui décrit les sessions de l'utilisateur courant).
909
+ */
910
+ interface AdminSessionInfo {
911
+ id: string;
912
+ user_id: string;
913
+ device_info?: string | null;
914
+ ip_address?: string | null;
915
+ created_at: string;
916
+ expires_at: string;
917
+ last_used_at: string;
918
+ }
919
+ interface AuthSettings {
920
+ allow_signup: boolean;
921
+ email_confirmation_required: boolean;
922
+ password_min_length: number;
923
+ mfa_enabled: boolean;
924
+ allow_anonymous_users: boolean;
925
+ jwt_expiry_seconds: number;
926
+ refresh_token_expiry_days: number;
927
+ site_url?: string | null;
928
+ oauth_providers: Record<string, {
929
+ enabled?: boolean;
930
+ client_id?: string;
931
+ client_secret?: string;
932
+ }>;
933
+ new_device_alerts_enabled: boolean;
934
+ webhook_url?: string | null;
935
+ smtp_host?: string | null;
936
+ smtp_port?: number | null;
937
+ smtp_username?: string | null;
938
+ smtp_password_set?: boolean;
939
+ smtp_from_email?: string | null;
940
+ smtp_from_name?: string | null;
941
+ oauth_credentials: Record<string, Record<string, string>>;
942
+ captcha_enabled: boolean;
943
+ captcha_provider?: string | null;
944
+ captcha_site_key?: string | null;
945
+ captcha_secret_key_set?: boolean;
946
+ password_check_hibp: boolean;
947
+ sms_provider?: string | null;
948
+ sms_api_key_set?: boolean;
949
+ sms_from_number?: string | null;
950
+ redirect_urls: string[];
951
+ session_inactivity_timeout_seconds: number;
952
+ hook_send_sms_url?: string | null;
953
+ hook_send_email_url?: string | null;
954
+ hook_mfa_verification_url?: string | null;
955
+ hook_password_verification_url?: string | null;
956
+ auto_link_by_email: boolean;
957
+ revoke_on_new_device: boolean;
958
+ enforce_ip_binding: boolean;
959
+ allowed_email_domains: string[];
960
+ blocked_email_domains: string[];
961
+ updated_at: string;
962
+ }
963
+ interface EmailTemplateUpdate {
964
+ subject: string;
965
+ html_body: string;
966
+ }
967
+ interface AdminCreateUserRequest {
968
+ email: string;
969
+ password?: string;
970
+ role?: string;
971
+ email_verified?: boolean;
972
+ user_metadata?: Record<string, unknown>;
973
+ }
974
+ interface AdminUpdateUserRequest {
975
+ password?: string;
976
+ role?: string;
977
+ is_active?: boolean;
978
+ is_banned?: boolean;
979
+ email_verified?: boolean;
980
+ user_metadata?: Record<string, unknown>;
981
+ app_metadata?: Record<string, unknown>;
982
+ mfa_enabled?: boolean;
983
+ revoke_sessions?: boolean;
984
+ }
985
+ type GenerateLinkType = 'magic' | 'recovery' | 'invite';
986
+ interface GenerateLinkResult {
987
+ link: string;
988
+ token: string;
989
+ }
990
+ interface JwtClaims {
991
+ sub: string;
992
+ exp?: number;
993
+ iat?: number;
994
+ nbf?: number;
995
+ iss?: string;
996
+ aud?: string | string[];
997
+ role?: string;
998
+ [key: string]: unknown;
999
+ }
1000
+ interface GetClaimsResult {
1001
+ claims: JwtClaims;
1002
+ header: {
1003
+ alg: string;
1004
+ kid?: string;
1005
+ typ?: string;
1006
+ };
1007
+ }
1008
+
1009
+ type AuthChangeCallback = (token: string | null, user: User | null) => void;
1010
+ /**
1011
+ * Check whether a JWT has expired (or will expire within `marginSec` seconds).
1012
+ */
1013
+ declare function isTokenExpired(token: string, marginSec?: number): boolean;
1014
+ /**
1015
+ * In-memory auth store with an event-emitter pattern.
1016
+ * Can be extended (see LocalAuthStore) for persistence.
1017
+ */
1018
+ declare class BaseAuthStore {
1019
+ /**
1020
+ * True si le store survit à un redirect pleine page (persistance disque, ex.
1021
+ * localStorage). Le store de base est en mémoire → non persistant. Exploité par
1022
+ * le flux PKCE : le `code_verifier` doit survivre au redirect OAuth.
1023
+ */
1024
+ readonly persistent: boolean;
1025
+ private _token;
1026
+ private _refreshToken;
1027
+ private _user;
1028
+ private _listeners;
1029
+ private _removalEpoch;
1030
+ /** Stockage générique clé/valeur (ex: PKCE `code_verifier`). En mémoire par défaut. */
1031
+ private _kv;
1032
+ /** Hook d'observabilité (LOT 3) — câblé par `AuraClient` via `setObservabilityHook`. */
1033
+ private _onEvent?;
1034
+ private _debug;
1035
+ /** Compteur incrémenté à chaque `clear()` — sert au commit-guard anti-race du refresh. */
1036
+ get removalEpoch(): number;
1037
+ get token(): string | null;
1038
+ get refreshToken(): string | null;
1039
+ get user(): User | null;
1040
+ /** True if a non-expired access token is present. */
1041
+ get isValid(): boolean;
1042
+ save(token: string, refreshToken: string, user: User): void;
1043
+ clear(): void;
1044
+ setItem(key: string, value: string): void;
1045
+ getItem(key: string): string | null;
1046
+ removeItem(key: string): void;
1047
+ /**
1048
+ * Câble le hook d'observabilité (appelé par `AuraClient` à la construction).
1049
+ * Permet à `LocalAuthStore` d'émettre `storage-blocked` quand `localStorage` est
1050
+ * indisponible (navigation privée Safari, quota dépassé, storage désactivé…).
1051
+ * Sans effet sur `BaseAuthStore` elle-même (en mémoire, jamais "bloquée").
1052
+ */
1053
+ setObservabilityHook(onEvent: ((event: AuraObservabilityEvent) => void) | undefined, debug: boolean | undefined): void;
1054
+ /** Émet `{kind:'storage-blocked', op}` — ne throw jamais (voir `emitAuraEvent`). */
1055
+ protected _emitStorageBlocked(op: string): void;
1056
+ /**
1057
+ * Register a callback that fires whenever the auth state changes.
1058
+ * Returns an unsubscribe function.
1059
+ */
1060
+ onChange(callback: AuthChangeCallback): () => void;
1061
+ protected _triggerChange(): void;
1062
+ }
1063
+
1064
+ /**
1065
+ * Forme minimale du client consommée par `fetchWithAuth`, `BaseService`,
1066
+ * le `QueryBuilder` et les services. Le `AuraClient` concret (meta-package)
1067
+ * satisfait cette interface structurellement — ce qui casse le cycle de
1068
+ * dépendance core → meta (les services n'importent plus la classe concrète).
1069
+ */
1070
+ interface AuraClientLike {
1071
+ readonly baseUrl: string;
1072
+ readonly projectId: string;
1073
+ readonly apiKey: string | null;
1074
+ readonly fetchFn: typeof globalThis.fetch;
1075
+ readonly authStore: BaseAuthStore;
1076
+ /** Consommé uniquement par le service realtime (refresh proactif du token). */
1077
+ readonly auth: {
1078
+ refreshSession(): Promise<AuraResponse<TokenPair>>;
1079
+ };
1080
+ /** Config du retry transitoire. Défauts appliqués si absent : enabled=true, maxRetries=3. */
1081
+ readonly retryConfig?: {
1082
+ enabled: boolean;
1083
+ maxRetries: number;
1084
+ };
1085
+ /**
1086
+ * Timeout par défaut (ms) des requêtes HTTP. Appliqué UNIQUEMENT aux requêtes
1087
+ * JSON sans `signal` fourni (donc pas aux uploads FormData ni aux appels qui
1088
+ * gèrent déjà leur propre annulation). `0` désactive. Défaut : 30 000 ms.
1089
+ */
1090
+ readonly requestTimeoutMs?: number;
1091
+ /**
1092
+ * Hook d'observabilité (LOT 3, finding I8), optionnel — n'importe quelle implémentation
1093
+ * structurelle de `AuraClientLike` reste compatible sans le fournir (pas de breaking
1094
+ * change). Consommé par `fetchWithAuth`/`refreshOnce` pour émettre retry/timeout/refresh.
1095
+ */
1096
+ readonly onEvent?: (event: AuraObservabilityEvent) => void;
1097
+ /** Si `true`, chaque `AuraObservabilityEvent` est aussi journalisé via `console.debug`. */
1098
+ readonly debug?: boolean;
1099
+ }
1100
+
1101
+ /** Point d'entrée unique du refresh, dédupliqué par client (single-flight). */
1102
+ declare function refreshOnce(client: AuraClientLike): Promise<AuraResponse<TokenPair>>;
1103
+ interface FetchInit {
1104
+ method?: string;
1105
+ headers?: Record<string, string>;
1106
+ body?: unknown;
1107
+ signal?: AbortSignal;
1108
+ skipAuthRefresh?: boolean;
1109
+ /**
1110
+ * Override explicite du `Authorization: Bearer` (LOT D). S'il est fourni, il
1111
+ * GAGNE sur `store.token` — permet de valider un token ARBITRAIRE (foreign)
1112
+ * plutôt que celui de la session courante (ex. `getUser(jwt)`). Sans lui, le
1113
+ * comportement historique s'applique (`Authorization = Bearer store.token`).
1114
+ */
1115
+ authToken?: string;
1116
+ /** Désactive le retry transitoire pour cette requête (override). */
1117
+ skipRetry?: boolean;
1118
+ /** Interne (E19) : marque une requête déjà rejouée après refresh pour borner la récursion. */
1119
+ _retried?: boolean;
1120
+ }
1121
+ /**
1122
+ * Core fetch wrapper that handles:
1123
+ * - Lazy token refresh before expiry
1124
+ * - Authorization / API key injection
1125
+ * - Content-Type defaulting
1126
+ * - Structured AuraResponse parsing
1127
+ */
1128
+ declare function fetchWithAuth<T>(url: string, init: FetchInit, client: AuraClientLike): Promise<AuraResponse<T>>;
1129
+
1130
+ /**
1131
+ * Abstract base class for all service modules.
1132
+ * Provides the shared HTTP helper and URL builder.
1133
+ */
1134
+ declare abstract class BaseService {
1135
+ protected readonly client: AuraClientLike;
1136
+ constructor(client: AuraClientLike);
1137
+ /** Build a full URL for the given path. */
1138
+ protected url(path: string): string;
1139
+ /** Convenience HTTP helper that delegates to fetchWithAuth. */
1140
+ protected request<T>(method: string, path: string, body?: unknown, options?: {
1141
+ headers?: Record<string, string>;
1142
+ signal?: AbortSignal;
1143
+ skipAuthRefresh?: boolean;
1144
+ /** Override explicite du Bearer (LOT D) — valide un token arbitraire. */
1145
+ authToken?: string;
1146
+ }): Promise<AuraResponse<T>>;
1147
+ }
1148
+
1149
+ interface CookieOptions {
1150
+ path?: string;
1151
+ domain?: string;
1152
+ maxAge?: number;
1153
+ secure?: boolean;
1154
+ sameSite?: 'Strict' | 'Lax' | 'None';
1155
+ httpOnly?: boolean;
1156
+ }
1157
+ /**
1158
+ * Auth store backed by `localStorage` (browser) with cookie helpers for SSR.
1159
+ */
1160
+ declare class LocalAuthStore extends BaseAuthStore {
1161
+ /** Persiste en localStorage → survit au redirect pleine page (cf. PKCE). */
1162
+ readonly persistent = true;
1163
+ private readonly key;
1164
+ constructor(key?: string);
1165
+ save(token: string, refreshToken: string, user: User): void;
1166
+ clear(): void;
1167
+ /**
1168
+ * Supprime de localStorage tous les artefacts d'auth éphémères sur disque :
1169
+ * - `code_verifier` PKCE (`aura-<projectId>-pkce-code-verifier`),
1170
+ * - marqueur d'initiation OAuth implicit (`aura-<projectId>-oauth-implicit-initiated`,
1171
+ * SEC-F3). Un `signOut`/`clear()` ne doit laisser aucun résidu réutilisable (parité
1172
+ * `@supabase/ssr` : ces artefacts sont éphémères). On itère les clés préfixées pour
1173
+ * couvrir un store partagé entre plusieurs projets, sans dépendre du `projectId` courant.
1174
+ */
1175
+ private _removePkceVerifiers;
1176
+ setItem(key: string, value: string): void;
1177
+ getItem(key: string): string | null;
1178
+ removeItem(key: string): void;
1179
+ /**
1180
+ * Populate the store from a raw `Cookie` header string (server-side).
1181
+ * Looks for the key matching `this.key`.
1182
+ */
1183
+ loadFromCookie(cookieString: string): void;
1184
+ /**
1185
+ * Serialize current auth state into a `Set-Cookie` value.
1186
+ */
1187
+ exportToCookie(options?: CookieOptions): string;
1188
+ private _loadFromStorage;
1189
+ private _persist;
1190
+ private _removeStorage;
1191
+ }
1192
+
1193
+ /** JSON.stringify avec support des bigint (sérialisés en string). */
1194
+ declare function serializeBody(body: unknown): string;
1195
+
1196
+ /**
1197
+ * Parse a raw Cookie header string into key-value pairs.
1198
+ */
1199
+ declare function parseCookieHeader(header: string): Record<string, string>;
1200
+ interface SerializeCookieOptions {
1201
+ path?: string;
1202
+ domain?: string;
1203
+ maxAge?: number;
1204
+ secure?: boolean;
1205
+ sameSite?: 'Strict' | 'Lax' | 'None';
1206
+ httpOnly?: boolean;
1207
+ }
1208
+ /**
1209
+ * Serialize a cookie name + value + options into a Set-Cookie header value.
1210
+ */
1211
+ declare function serializeCookieHeader(name: string, value: string, options?: SerializeCookieOptions): string;
1212
+
1213
+ /**
1214
+ * Primitives de résilience réseau (module pur, sans I/O).
1215
+ * `Math.random`/`Date.now` sont injectables pour des tests déterministes.
1216
+ */
1217
+ declare const RETRYABLE_STATUS: Set<number>;
1218
+ declare const RETRYABLE_METHODS: Set<string>;
1219
+ declare const DEFAULT_MAX_RETRIES = 3;
1220
+ declare function isRetryableStatus(status: number): boolean;
1221
+ declare function isRetryableMethod(method: string): boolean;
1222
+ /** Full jitter : random(0, min(BASE·2^attempt, CAP)). `attempt` commence à 0. */
1223
+ declare function computeBackoff(attempt: number, rand?: () => number): number;
1224
+ /** Parse un header `Retry-After` (secondes OU HTTP-date) → délai en ms, ou null. */
1225
+ declare function parseRetryAfter(header: string | null, now?: number): number | null;
1226
+ /** `sleep(ms)` qui résout tôt (sans rejeter) si `signal` s'annule. */
1227
+ declare function abortableSleep(ms: number, signal?: AbortSignal): Promise<void>;
1228
+ /** True si l'erreur `fetch` est une annulation utilisateur (jamais rejouée). */
1229
+ declare function isAbortError(err: unknown): boolean;
1230
+
1231
+ export { 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, BaseAuthStore, BaseService, type BatchSendItemResult, type BatchSendResponse, type BroadcastAckMessage, type BroadcastFilter, type BroadcastPayload, type CdcPayload, type ChannelConfig, type ChatMessage, type ChatResponse, type CountMode, type CronJob, DEFAULT_MAX_RETRIES, 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 OAuthSignInOptions, type ObjectMeta, type PasswordResetRequest, 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, computeBackoff, emitAuraEvent, fetchWithAuth, isAbortError, isAuraError, isRetryableMethod, isRetryableStatus, isTokenExpired, parseCookieHeader, parseRetryAfter, refreshOnce, serializeBody, serializeCookieHeader };