@aurabase/aurabase-js 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AuraClient-K3hRdh9J.d.cts → AuraClient-5jDiXjrO.d.cts} +1 -1
- package/dist/{AuraClient-K3hRdh9J.d.ts → AuraClient-5jDiXjrO.d.ts} +1 -1
- package/dist/index.cjs +18 -3
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -4
- package/dist/nextjs.cjs +389 -0
- package/dist/nextjs.d.cts +126 -0
- package/dist/nextjs.d.ts +126 -0
- package/dist/nextjs.js +383 -0
- package/dist/react.cjs +150 -0
- package/dist/react.d.cts +82 -0
- package/dist/react.d.ts +82 -0
- package/dist/react.js +143 -0
- package/dist/ssr.cjs +6 -3
- package/dist/ssr.d.cts +1 -1
- package/dist/ssr.d.ts +1 -1
- package/dist/ssr.js +6 -3
- package/package.json +29 -9
package/dist/nextjs.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { A as AuraClient } from './AuraClient-5jDiXjrO.js';
|
|
2
|
+
import { User, Session } from '@aurabase/core';
|
|
3
|
+
import '@aurabase/ai';
|
|
4
|
+
import '@aurabase/auth';
|
|
5
|
+
import '@aurabase/db';
|
|
6
|
+
import '@aurabase/functions';
|
|
7
|
+
import '@aurabase/notifications';
|
|
8
|
+
import '@aurabase/realtime';
|
|
9
|
+
import '@aurabase/storage';
|
|
10
|
+
|
|
11
|
+
interface NextCookieItem {
|
|
12
|
+
name: string;
|
|
13
|
+
value: string;
|
|
14
|
+
options?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
interface NextRequestCookies {
|
|
17
|
+
getAll(): NextCookieItem[];
|
|
18
|
+
set(name: string, value: string): void;
|
|
19
|
+
}
|
|
20
|
+
interface NextUrlLike {
|
|
21
|
+
pathname: string;
|
|
22
|
+
}
|
|
23
|
+
interface NextRequestLike {
|
|
24
|
+
cookies: NextRequestCookies;
|
|
25
|
+
nextUrl: NextUrlLike;
|
|
26
|
+
url: string;
|
|
27
|
+
}
|
|
28
|
+
interface NextResponseCookies {
|
|
29
|
+
set(name: string, value: string, options?: Record<string, unknown>): void;
|
|
30
|
+
}
|
|
31
|
+
interface NextResponseLike {
|
|
32
|
+
cookies: NextResponseCookies;
|
|
33
|
+
headers?: unknown;
|
|
34
|
+
}
|
|
35
|
+
interface NextServerModule {
|
|
36
|
+
NextResponse: {
|
|
37
|
+
next(init?: {
|
|
38
|
+
request?: unknown;
|
|
39
|
+
}): NextResponseLike;
|
|
40
|
+
redirect(url: string | URL): NextResponseLike;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
interface ReadonlyRequestCookiesLike {
|
|
44
|
+
getAll(): NextCookieItem[];
|
|
45
|
+
set?(name: string, value: string, options?: Record<string, unknown>): void;
|
|
46
|
+
}
|
|
47
|
+
interface NextHeadersModule {
|
|
48
|
+
cookies(): Promise<ReadonlyRequestCookiesLike> | ReadonlyRequestCookiesLike;
|
|
49
|
+
}
|
|
50
|
+
interface AuthContextParam {
|
|
51
|
+
user: User | null;
|
|
52
|
+
session: Session | null;
|
|
53
|
+
request: NextRequestLike;
|
|
54
|
+
}
|
|
55
|
+
interface AuthMiddlewareOptions {
|
|
56
|
+
/** Project URL (defaults to process.env.NEXT_PUBLIC_AURABASE_URL or process.env.AURABASE_URL). */
|
|
57
|
+
projectUrl?: string;
|
|
58
|
+
/** Anon API Key (defaults to process.env.NEXT_PUBLIC_AURABASE_ANON_KEY or process.env.AURABASE_ANON_KEY). */
|
|
59
|
+
anonKey?: string;
|
|
60
|
+
/** List of route patterns that do not require authentication (e.g. ['/', '/login', '/signup', '/auth/*']). */
|
|
61
|
+
publicRoutes?: string[];
|
|
62
|
+
/** URL to redirect unauthenticated users to (default: '/login'). */
|
|
63
|
+
loginUrl?: string;
|
|
64
|
+
/** Custom handler executed after session evaluation. */
|
|
65
|
+
onAuthenticated?: (authContext: AuthContextParam) => Promise<NextResponseLike | undefined | null | void> | NextResponseLike | undefined | null | void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a standard Next.js middleware that validates sessions and protects private routes.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* // middleware.ts
|
|
73
|
+
* import { createAuthMiddleware } from '@aurabase/aurabase-js/nextjs'
|
|
74
|
+
*
|
|
75
|
+
* export default createAuthMiddleware({
|
|
76
|
+
* publicRoutes: ['/', '/login', '/signup', '/api/public'],
|
|
77
|
+
* loginUrl: '/login',
|
|
78
|
+
* })
|
|
79
|
+
*
|
|
80
|
+
* export const config = {
|
|
81
|
+
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
declare function createAuthMiddleware(options?: AuthMiddlewareOptions): (request: NextRequestLike) => Promise<NextResponseLike>;
|
|
86
|
+
/**
|
|
87
|
+
* Creates an Aurabase client optimized for React Server Components (RSC).
|
|
88
|
+
* Safe in read-only RSC context: prevents Next.js errors when evaluating tokens.
|
|
89
|
+
*/
|
|
90
|
+
declare function createClientForServerComponent(cookieStore: ReadonlyRequestCookiesLike, projectUrl?: string, apiKey?: string): AuraClient<any, any>;
|
|
91
|
+
/**
|
|
92
|
+
* Creates an Aurabase client for Server Actions and Route Handlers.
|
|
93
|
+
* Full read-write cookie access for transparent session management.
|
|
94
|
+
*/
|
|
95
|
+
declare function createClientForServerAction(cookieStore: ReadonlyRequestCookiesLike, projectUrl?: string, apiKey?: string): AuraClient<any, any>;
|
|
96
|
+
/**
|
|
97
|
+
* Server Component helper (Clerk-like API) to get the current authentication state.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* import { auth } from '@aurabase/aurabase-js/nextjs'
|
|
102
|
+
*
|
|
103
|
+
* export default async function Page() {
|
|
104
|
+
* const { userId, user } = await auth()
|
|
105
|
+
* if (!userId) return <div>Non connecté</div>
|
|
106
|
+
* return <div>Connecté en tant que {user?.email}</div>
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function auth(options?: {
|
|
111
|
+
projectUrl?: string;
|
|
112
|
+
apiKey?: string;
|
|
113
|
+
}): Promise<{
|
|
114
|
+
userId: string | null;
|
|
115
|
+
user: User | null;
|
|
116
|
+
session: Session | null;
|
|
117
|
+
}>;
|
|
118
|
+
/**
|
|
119
|
+
* Server Component helper to get the currently logged-in user profile.
|
|
120
|
+
*/
|
|
121
|
+
declare function currentUser(options?: {
|
|
122
|
+
projectUrl?: string;
|
|
123
|
+
apiKey?: string;
|
|
124
|
+
}): Promise<User | null>;
|
|
125
|
+
|
|
126
|
+
export { type AuthContextParam, type AuthMiddlewareOptions, type NextCookieItem, type NextHeadersModule, type NextRequestCookies, type NextRequestLike, type NextResponseCookies, type NextResponseLike, type NextServerModule, type NextUrlLike, type ReadonlyRequestCookiesLike, auth, createAuthMiddleware, createClientForServerAction, createClientForServerComponent, currentUser };
|
package/dist/nextjs.js
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import { clientScope, LocalAuthStore, DEFAULT_MAX_RETRIES, BaseAuthStore } from '@aurabase/core';
|
|
2
|
+
import { AiService } from '@aurabase/ai';
|
|
3
|
+
import { AuthService, AuthAdminService } from '@aurabase/auth';
|
|
4
|
+
import { DatabaseService } from '@aurabase/db';
|
|
5
|
+
import { FunctionsService } from '@aurabase/functions';
|
|
6
|
+
import { NotificationsService } from '@aurabase/notifications';
|
|
7
|
+
import { RealtimeService } from '@aurabase/realtime';
|
|
8
|
+
import { StorageService } from '@aurabase/storage';
|
|
9
|
+
|
|
10
|
+
// src/ssr.ts
|
|
11
|
+
function isBrowserContext() {
|
|
12
|
+
if (typeof window !== "undefined") return true;
|
|
13
|
+
const g = globalThis;
|
|
14
|
+
if (typeof g.DedicatedWorkerGlobalScope !== "undefined") return true;
|
|
15
|
+
if (typeof g.SharedWorkerGlobalScope !== "undefined") return true;
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
var SERVICE_ROLE_KEY_PREFIX = "aura_sk_";
|
|
19
|
+
var AuraClient = class {
|
|
20
|
+
/** URL du projet (`https://<slug>.aurabase.cloud`), sans barre finale. */
|
|
21
|
+
baseUrl;
|
|
22
|
+
apiKey;
|
|
23
|
+
fetchFn;
|
|
24
|
+
authStore;
|
|
25
|
+
retryConfig;
|
|
26
|
+
/** Timeout par défaut (ms) des requêtes JSON sans signal. `undefined` → défaut core (30s). */
|
|
27
|
+
requestTimeoutMs;
|
|
28
|
+
/** Hook d'observabilité (LOT 3) — voir `AuraClientOptions.onEvent`. */
|
|
29
|
+
onEvent;
|
|
30
|
+
/** Journalise chaque `AuraObservabilityEvent` via `console.debug` — voir `AuraClientOptions.debug`. */
|
|
31
|
+
debug;
|
|
32
|
+
// Lazy-initialised service instances
|
|
33
|
+
_auth = null;
|
|
34
|
+
_db = null;
|
|
35
|
+
_storage = null;
|
|
36
|
+
_realtime = null;
|
|
37
|
+
_functions = null;
|
|
38
|
+
_ai = null;
|
|
39
|
+
_notifications = null;
|
|
40
|
+
_authAdmin = null;
|
|
41
|
+
_disposed = false;
|
|
42
|
+
_persistSession;
|
|
43
|
+
_autoRefresh;
|
|
44
|
+
_detectSessionInUrl;
|
|
45
|
+
/**
|
|
46
|
+
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
47
|
+
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
48
|
+
*/
|
|
49
|
+
constructor(baseUrl, apiKey, options) {
|
|
50
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
51
|
+
const resolvedOptions = options;
|
|
52
|
+
this.apiKey = apiKey || null;
|
|
53
|
+
this.fetchFn = resolvedOptions?.fetch ?? globalThis.fetch.bind(globalThis);
|
|
54
|
+
const r = resolvedOptions?.retry;
|
|
55
|
+
this.retryConfig = r === false ? { enabled: false, maxRetries: 0 } : r === void 0 || r === true ? { enabled: true, maxRetries: DEFAULT_MAX_RETRIES } : { enabled: r.enabled ?? true, maxRetries: r.maxRetries ?? DEFAULT_MAX_RETRIES };
|
|
56
|
+
this.requestTimeoutMs = resolvedOptions?.requestTimeoutMs;
|
|
57
|
+
this.onEvent = resolvedOptions?.onEvent;
|
|
58
|
+
this.debug = resolvedOptions?.debug;
|
|
59
|
+
if (!this.apiKey && typeof console !== "undefined") {
|
|
60
|
+
console.warn(
|
|
61
|
+
"[aurabase] No API key provided. Most operations require an API key (apikey header). Only public auth routes (register, login, refresh) will work without one."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
65
|
+
console.warn(
|
|
66
|
+
"[aurabase] Attention : en local, l'URL du projet doit inclure le sous-domaine (ex: http://<slug>.localhost:8080) pour permettre la r\xE9solution automatique du projet par la passerelle."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
70
|
+
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
71
|
+
const message = "[aurabase] S\xC9CURIT\xC9 : une cl\xE9 service_role (aura_sk_\u2026) est fournie \xE0 createClient() dans un contexte navigateur. Cette cl\xE9 \xE0 privil\xE8ges \xE9lev\xE9s NE DOIT JAMAIS \xEAtre expos\xE9e c\xF4t\xE9 client (elle fuiterait dans le bundle). Utilisez une cl\xE9 anon (aura_anon_\u2026) c\xF4t\xE9 client, et createAdminClient() c\xF4t\xE9 serveur pour les op\xE9rations d'administration.";
|
|
72
|
+
if (refuse) {
|
|
73
|
+
throw new Error(message);
|
|
74
|
+
} else if (typeof console !== "undefined") {
|
|
75
|
+
console.warn(message);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (resolvedOptions?.auth?.storage) {
|
|
79
|
+
this.authStore = resolvedOptions.auth.storage;
|
|
80
|
+
} else if (resolvedOptions?.auth?.persistSession === false) {
|
|
81
|
+
this.authStore = new BaseAuthStore();
|
|
82
|
+
} else if (isBrowserContext() && typeof window.localStorage !== "undefined" || typeof globalThis !== "undefined" && (() => {
|
|
83
|
+
const g = globalThis;
|
|
84
|
+
const proc = g?.process;
|
|
85
|
+
const isTest = !!(proc?.env?.VITEST || proc?.env?.NODE_ENV === "test" || proc?.env?.JEST_WORKER_ID);
|
|
86
|
+
return isTest && !!g?.localStorage && typeof g.localStorage.getItem === "function";
|
|
87
|
+
})()) {
|
|
88
|
+
this.authStore = new LocalAuthStore(`aura-${clientScope(this.baseUrl)}-auth`);
|
|
89
|
+
} else {
|
|
90
|
+
this.authStore = new BaseAuthStore();
|
|
91
|
+
}
|
|
92
|
+
this.authStore.setObservabilityHook(this.onEvent, this.debug);
|
|
93
|
+
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
94
|
+
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
95
|
+
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
96
|
+
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
97
|
+
void this.auth;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Démonte le client : arrête le refresh proactif (ticker + visibilité + BroadcastChannel),
|
|
102
|
+
* déconnecte le realtime, vide les listeners d'auth. Idempotent. À appeler en teardown
|
|
103
|
+
* (React Strict Mode / HMR / tests).
|
|
104
|
+
*/
|
|
105
|
+
dispose() {
|
|
106
|
+
if (this._disposed) return;
|
|
107
|
+
this._disposed = true;
|
|
108
|
+
this._auth?.dispose();
|
|
109
|
+
this._realtime?.disconnect();
|
|
110
|
+
}
|
|
111
|
+
// -- Lazy service getters ---------------------------------------------------
|
|
112
|
+
get auth() {
|
|
113
|
+
if (!this._auth) {
|
|
114
|
+
this._auth = new AuthService(this, {
|
|
115
|
+
autoRefresh: this._autoRefresh,
|
|
116
|
+
persistSession: this._persistSession,
|
|
117
|
+
detectSessionInUrl: this._detectSessionInUrl
|
|
118
|
+
});
|
|
119
|
+
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
120
|
+
if (this._realtime) {
|
|
121
|
+
if (accessToken) {
|
|
122
|
+
this._realtime.setAuth(accessToken);
|
|
123
|
+
} else if (event === "SIGNED_OUT") {
|
|
124
|
+
this._realtime.setAuth("");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return this._auth;
|
|
130
|
+
}
|
|
131
|
+
get authAdmin() {
|
|
132
|
+
if (isBrowserContext()) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
"[aurabase] S\xC9CURIT\xC9 : authAdmin est inaccessible dans un contexte navigateur. L'API admin requiert une cl\xE9 service_role qui ne doit JAMAIS \xEAtre expos\xE9e c\xF4t\xE9 client (elle fuiterait dans le bundle). Utilisez createAdminClient() c\xF4t\xE9 serveur uniquement."
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (!this._authAdmin) this._authAdmin = new AuthAdminService(this);
|
|
138
|
+
return this._authAdmin;
|
|
139
|
+
}
|
|
140
|
+
get db() {
|
|
141
|
+
if (!this._db) this._db = new DatabaseService(this);
|
|
142
|
+
return this._db;
|
|
143
|
+
}
|
|
144
|
+
get storage() {
|
|
145
|
+
if (!this._storage) this._storage = new StorageService(this);
|
|
146
|
+
return this._storage;
|
|
147
|
+
}
|
|
148
|
+
get realtime() {
|
|
149
|
+
if (!this._realtime) this._realtime = new RealtimeService(this);
|
|
150
|
+
return this._realtime;
|
|
151
|
+
}
|
|
152
|
+
get functions() {
|
|
153
|
+
if (!this._functions) this._functions = new FunctionsService(this);
|
|
154
|
+
return this._functions;
|
|
155
|
+
}
|
|
156
|
+
get ai() {
|
|
157
|
+
if (!this._ai) this._ai = new AiService(this);
|
|
158
|
+
return this._ai;
|
|
159
|
+
}
|
|
160
|
+
get notifications() {
|
|
161
|
+
if (!this._notifications) this._notifications = new NotificationsService(this);
|
|
162
|
+
return this._notifications;
|
|
163
|
+
}
|
|
164
|
+
from(table) {
|
|
165
|
+
return this.db.from(table);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Shortcut: call a stored procedure / PostgreSQL function via RPC (Supabase-compatible API).
|
|
169
|
+
* Equivalent to `aura.db.rpc(fn, args, options)`.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* const { data, error } = await aura.rpc('echo_test', { message: 'hello' })
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
rpc(fn, args, options) {
|
|
177
|
+
return this.db.rpc(fn, args, options);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Shortcut: create a realtime channel with Supabase-compatible API.
|
|
181
|
+
* Equivalent to `aura.realtime.channel(name)`.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* const channel = aura.channel('room-1')
|
|
186
|
+
* .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, cb)
|
|
187
|
+
* .subscribe()
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
channel(name, options) {
|
|
191
|
+
return this.realtime.channel(name, options);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Shortcut: remove a realtime channel by name or AuraChannel instance.
|
|
195
|
+
* Equivalent to `aura.realtime.removeChannel(channel)`.
|
|
196
|
+
*/
|
|
197
|
+
removeChannel(channel) {
|
|
198
|
+
return this.realtime.removeChannel(channel);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Shortcut: remove all realtime channels and unsubscribe.
|
|
202
|
+
* Equivalent to `aura.realtime.removeAllChannels()`.
|
|
203
|
+
*/
|
|
204
|
+
removeAllChannels() {
|
|
205
|
+
return this.realtime.removeAllChannels();
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Shortcut: list all active realtime channels.
|
|
209
|
+
* Equivalent to `aura.realtime.getChannels()`.
|
|
210
|
+
*/
|
|
211
|
+
getChannels() {
|
|
212
|
+
return this.realtime.getChannels();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
var MAX_CHUNK_SIZE = 3600;
|
|
216
|
+
function createServerClient(baseUrl, apiKey, options) {
|
|
217
|
+
const cookieName = `aura-${clientScope(baseUrl)}-auth`;
|
|
218
|
+
const store = new LocalAuthStore(cookieName);
|
|
219
|
+
const idxRe = new RegExp(`^${cookieName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.(\\d+)$`);
|
|
220
|
+
const incoming = options.cookies.getAll();
|
|
221
|
+
const numbered = incoming.filter((c) => idxRe.test(c.name)).sort((a, b) => Number(a.name.match(idxRe)[1]) - Number(b.name.match(idxRe)[1]));
|
|
222
|
+
const base = incoming.find((c) => c.name === cookieName);
|
|
223
|
+
const decodedValue = numbered.length > 0 ? numbered.map((c) => c.value).join("") : base?.value;
|
|
224
|
+
if (decodedValue) {
|
|
225
|
+
store.loadFromCookie(`${cookieName}=${encodeURIComponent(decodedValue)}`);
|
|
226
|
+
}
|
|
227
|
+
const initialNames = incoming.filter((c) => c.name === cookieName || idxRe.test(c.name)).map((c) => c.name);
|
|
228
|
+
const defaultCookieOpts = {
|
|
229
|
+
path: "/",
|
|
230
|
+
secure: baseUrl.startsWith("https://"),
|
|
231
|
+
sameSite: "Lax",
|
|
232
|
+
httpOnly: true,
|
|
233
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
234
|
+
// 30 days
|
|
235
|
+
...options.cookieOptions
|
|
236
|
+
};
|
|
237
|
+
store.onChange(() => {
|
|
238
|
+
const toSet = [];
|
|
239
|
+
const used = /* @__PURE__ */ new Set();
|
|
240
|
+
if (store.token) {
|
|
241
|
+
const cookieStr = store.exportToCookie();
|
|
242
|
+
const eqIdx = cookieStr.indexOf("=");
|
|
243
|
+
const rawEncoded = eqIdx >= 0 ? cookieStr.slice(eqIdx + 1).split(";")[0] : "";
|
|
244
|
+
const decoded = rawEncoded ? decodeURIComponent(rawEncoded) : "";
|
|
245
|
+
if (decoded.length <= MAX_CHUNK_SIZE) {
|
|
246
|
+
toSet.push({ name: cookieName, value: decoded, options: defaultCookieOpts });
|
|
247
|
+
used.add(cookieName);
|
|
248
|
+
} else {
|
|
249
|
+
let idx = 0;
|
|
250
|
+
for (let i = 0; i < decoded.length; i += MAX_CHUNK_SIZE, idx++) {
|
|
251
|
+
const name = `${cookieName}.${idx}`;
|
|
252
|
+
toSet.push({
|
|
253
|
+
name,
|
|
254
|
+
value: decoded.slice(i, i + MAX_CHUNK_SIZE),
|
|
255
|
+
options: defaultCookieOpts
|
|
256
|
+
});
|
|
257
|
+
used.add(name);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const expireOpts = { ...defaultCookieOpts, maxAge: 0 };
|
|
262
|
+
for (const name of initialNames) {
|
|
263
|
+
if (!used.has(name)) toSet.push({ name, value: "", options: expireOpts });
|
|
264
|
+
}
|
|
265
|
+
if (toSet.length > 0) options.cookies.setAll(toSet);
|
|
266
|
+
});
|
|
267
|
+
return new AuraClient(baseUrl, apiKey, {
|
|
268
|
+
auth: { persistSession: false, storage: store }
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/nextjs.ts
|
|
273
|
+
async function loadNextModule(specifier) {
|
|
274
|
+
try {
|
|
275
|
+
const mod = await import(
|
|
276
|
+
/* @vite-ignore */
|
|
277
|
+
specifier
|
|
278
|
+
);
|
|
279
|
+
return mod;
|
|
280
|
+
} catch {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function createAuthMiddleware(options = {}) {
|
|
285
|
+
return async function middleware(request) {
|
|
286
|
+
const nextServer = await loadNextModule("next/server");
|
|
287
|
+
if (!nextServer?.NextResponse) {
|
|
288
|
+
throw new Error(
|
|
289
|
+
"[@aurabase/nextjs] Next.js n'est pas install\xE9. createAuthMiddleware n\xE9cessite next/server."
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
const { NextResponse } = nextServer;
|
|
293
|
+
const projectUrl = options.projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? process.env.AURABASE_URL ?? "";
|
|
294
|
+
const anonKey = options.anonKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? process.env.AURABASE_ANON_KEY ?? "";
|
|
295
|
+
if (!projectUrl || !anonKey) {
|
|
296
|
+
console.warn(
|
|
297
|
+
"[@aurabase/nextjs] Variables d'environnement manquantes : NEXT_PUBLIC_AURABASE_URL ou NEXT_PUBLIC_AURABASE_ANON_KEY non d\xE9finies."
|
|
298
|
+
);
|
|
299
|
+
return NextResponse.next({ request });
|
|
300
|
+
}
|
|
301
|
+
const response = NextResponse.next({ request });
|
|
302
|
+
const cookieHandler = {
|
|
303
|
+
getAll: () => request.cookies.getAll(),
|
|
304
|
+
setAll: (cookiesToSet) => {
|
|
305
|
+
cookiesToSet.forEach(({ name, value, options: cookieOpts }) => {
|
|
306
|
+
request.cookies.set(name, value);
|
|
307
|
+
response.cookies.set(name, value, cookieOpts);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
const client = createServerClient(projectUrl, anonKey, {
|
|
312
|
+
cookies: cookieHandler
|
|
313
|
+
});
|
|
314
|
+
const { data: sessionData } = await client.auth.getSession();
|
|
315
|
+
const session = sessionData?.session ?? null;
|
|
316
|
+
const user = session?.user ?? null;
|
|
317
|
+
const pathname = request.nextUrl.pathname;
|
|
318
|
+
const publicPatterns = options.publicRoutes ?? ["/", "/login", "/signup", "/auth/callback"];
|
|
319
|
+
const isPublic = publicPatterns.some((pattern) => {
|
|
320
|
+
if (pattern.endsWith("*")) {
|
|
321
|
+
return pathname.startsWith(pattern.slice(0, -1));
|
|
322
|
+
}
|
|
323
|
+
return pathname === pattern;
|
|
324
|
+
});
|
|
325
|
+
if (!isPublic && !user) {
|
|
326
|
+
const loginUrl = new URL(options.loginUrl ?? "/login", request.url);
|
|
327
|
+
loginUrl.searchParams.set("redirectTo", pathname);
|
|
328
|
+
return NextResponse.redirect(loginUrl);
|
|
329
|
+
}
|
|
330
|
+
if (options.onAuthenticated) {
|
|
331
|
+
const customResponse = await options.onAuthenticated({ user, session, request });
|
|
332
|
+
if (customResponse) return customResponse;
|
|
333
|
+
}
|
|
334
|
+
return response;
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function createClientForServerComponent(cookieStore, projectUrl, apiKey) {
|
|
338
|
+
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? process.env.AURABASE_URL ?? "";
|
|
339
|
+
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? process.env.AURABASE_ANON_KEY ?? "";
|
|
340
|
+
return createServerClient(url, key, {
|
|
341
|
+
cookies: {
|
|
342
|
+
getAll: () => cookieStore.getAll(),
|
|
343
|
+
setAll: () => {
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
function createClientForServerAction(cookieStore, projectUrl, apiKey) {
|
|
349
|
+
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? process.env.AURABASE_URL ?? "";
|
|
350
|
+
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? process.env.AURABASE_ANON_KEY ?? "";
|
|
351
|
+
return createServerClient(url, key, {
|
|
352
|
+
cookies: {
|
|
353
|
+
getAll: () => cookieStore.getAll(),
|
|
354
|
+
setAll: (cookiesToSet) => {
|
|
355
|
+
cookiesToSet.forEach(({ name, value, options }) => {
|
|
356
|
+
cookieStore.set?.(name, value, options);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
async function auth(options) {
|
|
363
|
+
const nextHeaders = await loadNextModule("next/headers");
|
|
364
|
+
if (!nextHeaders?.cookies) {
|
|
365
|
+
throw new Error("[@aurabase/nextjs] auth() ne peut \xEAtre appel\xE9 que dans un environnement Next.js App Router.");
|
|
366
|
+
}
|
|
367
|
+
const cookieStore = await nextHeaders.cookies();
|
|
368
|
+
const client = createClientForServerComponent(cookieStore, options?.projectUrl, options?.apiKey);
|
|
369
|
+
const { data } = await client.auth.getSession();
|
|
370
|
+
const session = data?.session ?? null;
|
|
371
|
+
const user = session?.user ?? null;
|
|
372
|
+
return {
|
|
373
|
+
userId: user?.id ?? null,
|
|
374
|
+
user,
|
|
375
|
+
session
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
async function currentUser(options) {
|
|
379
|
+
const { user } = await auth(options);
|
|
380
|
+
return user;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export { auth, createAuthMiddleware, createClientForServerAction, createClientForServerComponent, currentUser };
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// src/react.ts
|
|
11
|
+
function getReact() {
|
|
12
|
+
const g = globalThis;
|
|
13
|
+
if (g.React) {
|
|
14
|
+
return g.React;
|
|
15
|
+
}
|
|
16
|
+
if (typeof __require === "function") {
|
|
17
|
+
try {
|
|
18
|
+
return __require("react");
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
var defaultAuthContextValue = {
|
|
26
|
+
client: null,
|
|
27
|
+
user: null,
|
|
28
|
+
session: null,
|
|
29
|
+
accessToken: null,
|
|
30
|
+
isLoading: true,
|
|
31
|
+
isAuthenticated: false,
|
|
32
|
+
signOut: async () => {
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var authContextInstance = null;
|
|
36
|
+
function getAuthContext() {
|
|
37
|
+
if (!authContextInstance) {
|
|
38
|
+
const React = getReact();
|
|
39
|
+
if (React?.createContext) {
|
|
40
|
+
authContextInstance = React.createContext(defaultAuthContextValue);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return authContextInstance;
|
|
44
|
+
}
|
|
45
|
+
function AuthProvider({ client, children, initialSession = null }) {
|
|
46
|
+
const React = getReact();
|
|
47
|
+
if (!React) {
|
|
48
|
+
throw new Error("[@aurabase/react] React est requis pour utiliser <AuthProvider>.");
|
|
49
|
+
}
|
|
50
|
+
const [session, setSession] = React.useState(initialSession);
|
|
51
|
+
const [user, setUser] = React.useState(initialSession?.user ?? null);
|
|
52
|
+
const [isLoading, setIsLoading] = React.useState(!initialSession);
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
let isMounted = true;
|
|
55
|
+
void client.auth.getSession().then(({ data }) => {
|
|
56
|
+
if (!isMounted) return;
|
|
57
|
+
const s = data?.session ?? null;
|
|
58
|
+
setSession(s);
|
|
59
|
+
setUser(s?.user ?? null);
|
|
60
|
+
setIsLoading(false);
|
|
61
|
+
}).catch(() => {
|
|
62
|
+
if (!isMounted) return;
|
|
63
|
+
setIsLoading(false);
|
|
64
|
+
});
|
|
65
|
+
const subscription = client.auth.onAuthStateChange(({ event, user: nextUser }) => {
|
|
66
|
+
if (!isMounted) return;
|
|
67
|
+
if (event === "SIGNED_OUT") {
|
|
68
|
+
setSession(null);
|
|
69
|
+
setUser(null);
|
|
70
|
+
} else if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED" || event === "USER_UPDATED") {
|
|
71
|
+
void client.auth.getSession().then(({ data }) => {
|
|
72
|
+
if (!isMounted) return;
|
|
73
|
+
const s = data?.session ?? null;
|
|
74
|
+
setSession(s);
|
|
75
|
+
setUser(nextUser ?? s?.user ?? null);
|
|
76
|
+
}).catch(() => {
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return () => {
|
|
81
|
+
isMounted = false;
|
|
82
|
+
subscription.unsubscribe();
|
|
83
|
+
};
|
|
84
|
+
}, [client]);
|
|
85
|
+
const value = React.useMemo(
|
|
86
|
+
() => ({
|
|
87
|
+
client,
|
|
88
|
+
user,
|
|
89
|
+
session,
|
|
90
|
+
accessToken: session?.access_token ?? null,
|
|
91
|
+
isLoading,
|
|
92
|
+
isAuthenticated: !!user,
|
|
93
|
+
signOut: async () => {
|
|
94
|
+
await client.auth.signOut();
|
|
95
|
+
setSession(null);
|
|
96
|
+
setUser(null);
|
|
97
|
+
}
|
|
98
|
+
}),
|
|
99
|
+
[client, user, session, isLoading]
|
|
100
|
+
);
|
|
101
|
+
const Context = getAuthContext();
|
|
102
|
+
if (!Context) {
|
|
103
|
+
return children;
|
|
104
|
+
}
|
|
105
|
+
return React.createElement(Context.Provider, { value }, children);
|
|
106
|
+
}
|
|
107
|
+
function useAuth() {
|
|
108
|
+
const React = getReact();
|
|
109
|
+
const Context = getAuthContext();
|
|
110
|
+
if (!React || !Context) {
|
|
111
|
+
return {
|
|
112
|
+
client: null,
|
|
113
|
+
user: null,
|
|
114
|
+
session: null,
|
|
115
|
+
accessToken: null,
|
|
116
|
+
isLoading: false,
|
|
117
|
+
isAuthenticated: false,
|
|
118
|
+
signOut: async () => {
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return React.useContext(Context);
|
|
123
|
+
}
|
|
124
|
+
function useUser() {
|
|
125
|
+
const { user } = useAuth();
|
|
126
|
+
return user;
|
|
127
|
+
}
|
|
128
|
+
function useSession() {
|
|
129
|
+
const { session } = useAuth();
|
|
130
|
+
return session;
|
|
131
|
+
}
|
|
132
|
+
function SignedIn({ children }) {
|
|
133
|
+
const React = getReact();
|
|
134
|
+
const { isAuthenticated, isLoading } = useAuth();
|
|
135
|
+
if (isLoading || !isAuthenticated || !React) return null;
|
|
136
|
+
return React.createElement(React.Fragment, null, children);
|
|
137
|
+
}
|
|
138
|
+
function SignedOut({ children }) {
|
|
139
|
+
const React = getReact();
|
|
140
|
+
const { isAuthenticated, isLoading } = useAuth();
|
|
141
|
+
if (isLoading || isAuthenticated || !React) return null;
|
|
142
|
+
return React.createElement(React.Fragment, null, children);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
exports.AuthProvider = AuthProvider;
|
|
146
|
+
exports.SignedIn = SignedIn;
|
|
147
|
+
exports.SignedOut = SignedOut;
|
|
148
|
+
exports.useAuth = useAuth;
|
|
149
|
+
exports.useSession = useSession;
|
|
150
|
+
exports.useUser = useUser;
|