@aurabase/aurabase-js 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 +13 -5
- package/dist/{AuraClient-BWdcX_k0.d.cts → AuraClient-B1OOZCSX.d.cts} +1 -0
- package/dist/{AuraClient-BWdcX_k0.d.ts → AuraClient-B1OOZCSX.d.ts} +1 -0
- package/dist/index.cjs +29 -6
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +26 -7
- package/dist/nextjs.cjs +74 -22
- package/dist/nextjs.d.cts +3 -3
- package/dist/nextjs.d.ts +3 -3
- package/dist/nextjs.js +74 -22
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/ssr.cjs +59 -7
- package/dist/ssr.d.cts +5 -3
- package/dist/ssr.d.ts +5 -3
- package/dist/ssr.js +59 -7
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -2,25 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
Client JavaScript/TypeScript officiel pour [Aurabase](https://aurabase.cloud) : la plateforme Backend-as-a-Service open-source haute performance propulsée par Rust.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@aurabase/aurabase-js) [](https://github.com/
|
|
5
|
+
[](https://www.npmjs.com/package/@aurabase/aurabase-js) [](https://github.com/Aurabase-cloud/Aurabase/blob/main/LICENSE)
|
|
6
6
|
|
|
7
7
|
🌐 **Site officiel** : [https://aurabase.cloud](https://aurabase.cloud)
|
|
8
8
|
📖 **Documentation** : [https://aurabase.cloud/docs](https://aurabase.cloud)
|
|
9
|
-
🐙 **GitHub** : [
|
|
9
|
+
🐙 **GitHub** : [Aurabase-cloud/Aurabase](https://github.com/Aurabase-cloud/Aurabase)
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npm i @aurabase/aurabase-js
|
|
15
|
+
# ou
|
|
16
|
+
pnpm add @aurabase/aurabase-js
|
|
17
|
+
yarn add @aurabase/aurabase-js
|
|
18
|
+
bun add @aurabase/aurabase-js
|
|
15
19
|
```
|
|
16
20
|
|
|
21
|
+
> **Attention au nom.** Le paquet officiel est `@aurabase/aurabase-js` (avec la portée `@aurabase/`). Le paquet `aurabase-js` sans portée n'est **pas** maintenu par Aurabase : ne l'installez pas.
|
|
22
|
+
|
|
17
23
|
## Rôle
|
|
18
24
|
|
|
19
25
|
Ce package ne réimplémente aucune logique de service : il compose `AuthService`, `DatabaseService`, `StorageService`, `RealtimeService`, `FunctionsService`, `AiService` et `NotificationsService` (chacun dans son propre package `@aurabase/*`) derrière un seul client.
|
|
20
26
|
|
|
21
27
|
- `createClient(projectUrl, apiKey, options?)` — client applicatif standard. **L'URL est le projet** : chaque projet est servi sur son propre sous-domaine (`https://<slug>.aurabase.cloud`) et la passerelle injecte elle-même le `project_id` dans le chemin. Aucun identifiant de projet dans le code client.
|
|
22
|
-
- `createAdminClient(projectUrl, serviceRoleKey, options?)` — client serveur avec `authAdmin` (clé `service_role`, jamais côté navigateur).
|
|
23
|
-
- `@aurabase/aurabase-js/ssr` — `createServerClient`/`createBrowserClient` pour Next.js et frameworks SSR (cookies, session partagée serveur/navigateur).
|
|
28
|
+
- `createAdminClient(projectUrl, serviceRoleKey, options?)` — client serveur avec `authAdmin` (clé `service_role`, jamais côté navigateur : gestion des utilisateurs, impersonation RFC 8693, import d'utilisateurs bcrypt/Argon2id).
|
|
29
|
+
- `@aurabase/aurabase-js/ssr` — `createServerClient`/`createBrowserClient` pour Next.js et frameworks SSR (cookies légers, session partagée serveur/navigateur).
|
|
30
|
+
- `@aurabase/aurabase-js/react` — Hooks React (`useAuraSession`, `useAuraUser`) et contexte pour applications React / Next.js Client Components.
|
|
31
|
+
- `@aurabase/aurabase-js/nextjs` — Helpers pour Next.js App Router (Middleware de rafraîchissement de session, Server Actions).
|
|
24
32
|
|
|
25
33
|
## Quick Start
|
|
26
34
|
|
|
@@ -33,7 +41,7 @@ const { data, error } = await aura.db
|
|
|
33
41
|
.from('posts')
|
|
34
42
|
.select('id,title,published')
|
|
35
43
|
.eq('published', true)
|
|
36
|
-
.order('created_at',
|
|
44
|
+
.order('created_at', { ascending: false })
|
|
37
45
|
.limit(10)
|
|
38
46
|
|
|
39
47
|
if (error) {
|
|
@@ -65,6 +65,7 @@ declare class AuraClient<Database = any, Schema extends GenericSchema = Database
|
|
|
65
65
|
private readonly _persistSession;
|
|
66
66
|
private readonly _autoRefresh;
|
|
67
67
|
private readonly _detectSessionInUrl;
|
|
68
|
+
private readonly _flowType;
|
|
68
69
|
/**
|
|
69
70
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
70
71
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
@@ -65,6 +65,7 @@ declare class AuraClient<Database = any, Schema extends GenericSchema = Database
|
|
|
65
65
|
private readonly _persistSession;
|
|
66
66
|
private readonly _autoRefresh;
|
|
67
67
|
private readonly _detectSessionInUrl;
|
|
68
|
+
private readonly _flowType;
|
|
68
69
|
/**
|
|
69
70
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
70
71
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
package/dist/index.cjs
CHANGED
|
@@ -56,11 +56,27 @@ var AuraClient = class {
|
|
|
56
56
|
_persistSession;
|
|
57
57
|
_autoRefresh;
|
|
58
58
|
_detectSessionInUrl;
|
|
59
|
+
_flowType;
|
|
59
60
|
/**
|
|
60
61
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
61
62
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
62
63
|
*/
|
|
63
64
|
constructor(baseUrl, apiKey, options) {
|
|
65
|
+
if (typeof baseUrl !== "string" || baseUrl.trim() === "") {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"[aurabase] Project URL is required: set NEXT_PUBLIC_AURABASE_URL to the project URL shown in Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080), then pass it to createClient(url, key)."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (!/^https?:\/\//i.test(baseUrl.trim())) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`[aurabase] baseUrl must start with http:// or https:// (got "${baseUrl}"): copy the project URL from Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080).`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (apiKey === void 0 || apiKey === null) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"[aurabase] API key is required: set NEXT_PUBLIC_AURABASE_ANON_KEY (browser) or AURABASE_SERVICE_ROLE_KEY (server only) to a key shown in Studio \u203A Settings \u203A Connection, then pass it to createClient(url, key)."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
64
80
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
65
81
|
const resolvedOptions = options;
|
|
66
82
|
this.apiKey = apiKey || null;
|
|
@@ -72,17 +88,18 @@ var AuraClient = class {
|
|
|
72
88
|
this.debug = resolvedOptions?.debug;
|
|
73
89
|
if (!this.apiKey && typeof console !== "undefined") {
|
|
74
90
|
console.warn(
|
|
75
|
-
|
|
91
|
+
// AUTH-041 — la passerelle refuse TOUTE requête sans clé (401), y compris register/login.
|
|
92
|
+
"[aurabase] No API key provided: every request will be refused (401). Pass the anon key shown in Studio \u203A Settings \u203A Connection."
|
|
76
93
|
);
|
|
77
94
|
}
|
|
78
95
|
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
79
96
|
console.warn(
|
|
80
|
-
"[aurabase]
|
|
97
|
+
"[aurabase] Warning: locally, the project URL must include the sub-domain (e.g. http://<slug>.localhost:8080) so that the gateway can resolve the project automatically."
|
|
81
98
|
);
|
|
82
99
|
}
|
|
83
100
|
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
84
101
|
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
85
|
-
const message = "[aurabase]
|
|
102
|
+
const message = "[aurabase] SECURITY: a service_role key (aura_sk_\u2026) is passed to createClient() in a browser context. This high-privilege key MUST NEVER be exposed client-side (it would leak into the bundle). Use an anon key (aura_anon_\u2026) on the client, and createAdminClient() on the server for administration operations.";
|
|
86
103
|
if (refuse) {
|
|
87
104
|
throw new Error(message);
|
|
88
105
|
} else if (typeof console !== "undefined") {
|
|
@@ -107,6 +124,7 @@ var AuraClient = class {
|
|
|
107
124
|
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
108
125
|
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
109
126
|
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
127
|
+
this._flowType = resolvedOptions?.auth?.flowType;
|
|
110
128
|
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
111
129
|
void this.auth;
|
|
112
130
|
}
|
|
@@ -131,7 +149,8 @@ var AuraClient = class {
|
|
|
131
149
|
this._auth = new auth.AuthService(this, {
|
|
132
150
|
autoRefresh: this._autoRefresh,
|
|
133
151
|
persistSession: this._persistSession,
|
|
134
|
-
detectSessionInUrl: this._detectSessionInUrl
|
|
152
|
+
detectSessionInUrl: this._detectSessionInUrl,
|
|
153
|
+
flowType: this._flowType
|
|
135
154
|
});
|
|
136
155
|
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
137
156
|
if (this._realtime) {
|
|
@@ -152,7 +171,7 @@ var AuraClient = class {
|
|
|
152
171
|
get authAdmin() {
|
|
153
172
|
if (isBrowserContext()) {
|
|
154
173
|
throw new Error(
|
|
155
|
-
"[aurabase]
|
|
174
|
+
"[aurabase] SECURITY: authAdmin is not available in a browser context. The admin API requires a service_role key, which must NEVER be exposed client-side (it would leak into the bundle). Use createAdminClient() on the server only."
|
|
156
175
|
);
|
|
157
176
|
}
|
|
158
177
|
if (!this._authAdmin) this._authAdmin = new auth.AuthAdminService(this);
|
|
@@ -255,7 +274,7 @@ function createClient(baseUrl, apiKey, options) {
|
|
|
255
274
|
function createAdminClient(baseUrl, serviceRoleKey, options) {
|
|
256
275
|
if (isBrowserContext()) {
|
|
257
276
|
throw new Error(
|
|
258
|
-
"[aurabase] createAdminClient()
|
|
277
|
+
"[aurabase] createAdminClient() must never be called in a browser: the service_role key would be exposed in the bundle. Use it on the server only."
|
|
259
278
|
);
|
|
260
279
|
}
|
|
261
280
|
return new AuraClient(baseUrl, serviceRoleKey, options);
|
|
@@ -333,6 +352,10 @@ Object.defineProperty(exports, "RealtimeService", {
|
|
|
333
352
|
enumerable: true,
|
|
334
353
|
get: function () { return realtime.RealtimeService; }
|
|
335
354
|
});
|
|
355
|
+
Object.defineProperty(exports, "StorageBucketClient", {
|
|
356
|
+
enumerable: true,
|
|
357
|
+
get: function () { return storage.StorageBucketClient; }
|
|
358
|
+
});
|
|
336
359
|
Object.defineProperty(exports, "StorageService", {
|
|
337
360
|
enumerable: true,
|
|
338
361
|
get: function () { return storage.StorageService; }
|
package/dist/index.d.cts
CHANGED
|
@@ -7,7 +7,7 @@ export { FunctionsHttpError, FunctionsRelayError, FunctionsResponseType, Functio
|
|
|
7
7
|
export { NotificationsAdminService, NotificationsService } from '@aurabase/notifications';
|
|
8
8
|
export { AuraChannel, RealtimeService } from '@aurabase/realtime';
|
|
9
9
|
export { StorageBucketClient, StorageService } from '@aurabase/storage';
|
|
10
|
-
import { A as AuraClient } from './AuraClient-
|
|
10
|
+
import { A as AuraClient } from './AuraClient-B1OOZCSX.cjs';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Create a new Aurabase client instance.
|
|
@@ -38,7 +38,7 @@ declare function createClient<Database = any>(baseUrl: string, apiKey: string, o
|
|
|
38
38
|
* @example
|
|
39
39
|
* ```ts
|
|
40
40
|
* // server-side only (API route, edge function, backend)
|
|
41
|
-
* const admin = createAdminClient(projectUrl, process.env.
|
|
41
|
+
* const admin = createAdminClient(projectUrl, process.env.AURABASE_SERVICE_ROLE_KEY!)
|
|
42
42
|
* await admin.authAdmin.listUsers()
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { FunctionsHttpError, FunctionsRelayError, FunctionsResponseType, Functio
|
|
|
7
7
|
export { NotificationsAdminService, NotificationsService } from '@aurabase/notifications';
|
|
8
8
|
export { AuraChannel, RealtimeService } from '@aurabase/realtime';
|
|
9
9
|
export { StorageBucketClient, StorageService } from '@aurabase/storage';
|
|
10
|
-
import { A as AuraClient } from './AuraClient-
|
|
10
|
+
import { A as AuraClient } from './AuraClient-B1OOZCSX.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Create a new Aurabase client instance.
|
|
@@ -38,7 +38,7 @@ declare function createClient<Database = any>(baseUrl: string, apiKey: string, o
|
|
|
38
38
|
* @example
|
|
39
39
|
* ```ts
|
|
40
40
|
* // server-side only (API route, edge function, backend)
|
|
41
|
-
* const admin = createAdminClient(projectUrl, process.env.
|
|
41
|
+
* const admin = createAdminClient(projectUrl, process.env.AURABASE_SERVICE_ROLE_KEY!)
|
|
42
42
|
* await admin.authAdmin.listUsers()
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ export { NotificationsAdminService, NotificationsService } from '@aurabase/notif
|
|
|
13
13
|
import { RealtimeService } from '@aurabase/realtime';
|
|
14
14
|
export { AuraChannel, RealtimeService } from '@aurabase/realtime';
|
|
15
15
|
import { StorageService } from '@aurabase/storage';
|
|
16
|
-
export { StorageService } from '@aurabase/storage';
|
|
16
|
+
export { StorageBucketClient, StorageService } from '@aurabase/storage';
|
|
17
17
|
|
|
18
18
|
// src/index.ts
|
|
19
19
|
function isBrowserContext() {
|
|
@@ -62,11 +62,27 @@ var AuraClient = class {
|
|
|
62
62
|
_persistSession;
|
|
63
63
|
_autoRefresh;
|
|
64
64
|
_detectSessionInUrl;
|
|
65
|
+
_flowType;
|
|
65
66
|
/**
|
|
66
67
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
67
68
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
68
69
|
*/
|
|
69
70
|
constructor(baseUrl, apiKey, options) {
|
|
71
|
+
if (typeof baseUrl !== "string" || baseUrl.trim() === "") {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"[aurabase] Project URL is required: set NEXT_PUBLIC_AURABASE_URL to the project URL shown in Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080), then pass it to createClient(url, key)."
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (!/^https?:\/\//i.test(baseUrl.trim())) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`[aurabase] baseUrl must start with http:// or https:// (got "${baseUrl}"): copy the project URL from Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080).`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (apiKey === void 0 || apiKey === null) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
"[aurabase] API key is required: set NEXT_PUBLIC_AURABASE_ANON_KEY (browser) or AURABASE_SERVICE_ROLE_KEY (server only) to a key shown in Studio \u203A Settings \u203A Connection, then pass it to createClient(url, key)."
|
|
84
|
+
);
|
|
85
|
+
}
|
|
70
86
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
71
87
|
const resolvedOptions = options;
|
|
72
88
|
this.apiKey = apiKey || null;
|
|
@@ -78,17 +94,18 @@ var AuraClient = class {
|
|
|
78
94
|
this.debug = resolvedOptions?.debug;
|
|
79
95
|
if (!this.apiKey && typeof console !== "undefined") {
|
|
80
96
|
console.warn(
|
|
81
|
-
|
|
97
|
+
// AUTH-041 — la passerelle refuse TOUTE requête sans clé (401), y compris register/login.
|
|
98
|
+
"[aurabase] No API key provided: every request will be refused (401). Pass the anon key shown in Studio \u203A Settings \u203A Connection."
|
|
82
99
|
);
|
|
83
100
|
}
|
|
84
101
|
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
85
102
|
console.warn(
|
|
86
|
-
"[aurabase]
|
|
103
|
+
"[aurabase] Warning: locally, the project URL must include the sub-domain (e.g. http://<slug>.localhost:8080) so that the gateway can resolve the project automatically."
|
|
87
104
|
);
|
|
88
105
|
}
|
|
89
106
|
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
90
107
|
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
91
|
-
const message = "[aurabase]
|
|
108
|
+
const message = "[aurabase] SECURITY: a service_role key (aura_sk_\u2026) is passed to createClient() in a browser context. This high-privilege key MUST NEVER be exposed client-side (it would leak into the bundle). Use an anon key (aura_anon_\u2026) on the client, and createAdminClient() on the server for administration operations.";
|
|
92
109
|
if (refuse) {
|
|
93
110
|
throw new Error(message);
|
|
94
111
|
} else if (typeof console !== "undefined") {
|
|
@@ -113,6 +130,7 @@ var AuraClient = class {
|
|
|
113
130
|
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
114
131
|
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
115
132
|
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
133
|
+
this._flowType = resolvedOptions?.auth?.flowType;
|
|
116
134
|
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
117
135
|
void this.auth;
|
|
118
136
|
}
|
|
@@ -137,7 +155,8 @@ var AuraClient = class {
|
|
|
137
155
|
this._auth = new AuthService(this, {
|
|
138
156
|
autoRefresh: this._autoRefresh,
|
|
139
157
|
persistSession: this._persistSession,
|
|
140
|
-
detectSessionInUrl: this._detectSessionInUrl
|
|
158
|
+
detectSessionInUrl: this._detectSessionInUrl,
|
|
159
|
+
flowType: this._flowType
|
|
141
160
|
});
|
|
142
161
|
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
143
162
|
if (this._realtime) {
|
|
@@ -158,7 +177,7 @@ var AuraClient = class {
|
|
|
158
177
|
get authAdmin() {
|
|
159
178
|
if (isBrowserContext()) {
|
|
160
179
|
throw new Error(
|
|
161
|
-
"[aurabase]
|
|
180
|
+
"[aurabase] SECURITY: authAdmin is not available in a browser context. The admin API requires a service_role key, which must NEVER be exposed client-side (it would leak into the bundle). Use createAdminClient() on the server only."
|
|
162
181
|
);
|
|
163
182
|
}
|
|
164
183
|
if (!this._authAdmin) this._authAdmin = new AuthAdminService(this);
|
|
@@ -261,7 +280,7 @@ function createClient(baseUrl, apiKey, options) {
|
|
|
261
280
|
function createAdminClient(baseUrl, serviceRoleKey, options) {
|
|
262
281
|
if (isBrowserContext()) {
|
|
263
282
|
throw new Error(
|
|
264
|
-
"[aurabase] createAdminClient()
|
|
283
|
+
"[aurabase] createAdminClient() must never be called in a browser: the service_role key would be exposed in the bundle. Use it on the server only."
|
|
265
284
|
);
|
|
266
285
|
}
|
|
267
286
|
return new AuraClient(baseUrl, serviceRoleKey, options);
|
package/dist/nextjs.cjs
CHANGED
|
@@ -56,11 +56,27 @@ var AuraClient = class {
|
|
|
56
56
|
_persistSession;
|
|
57
57
|
_autoRefresh;
|
|
58
58
|
_detectSessionInUrl;
|
|
59
|
+
_flowType;
|
|
59
60
|
/**
|
|
60
61
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
61
62
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
62
63
|
*/
|
|
63
64
|
constructor(baseUrl, apiKey, options) {
|
|
65
|
+
if (typeof baseUrl !== "string" || baseUrl.trim() === "") {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"[aurabase] Project URL is required: set NEXT_PUBLIC_AURABASE_URL to the project URL shown in Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080), then pass it to createClient(url, key)."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (!/^https?:\/\//i.test(baseUrl.trim())) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`[aurabase] baseUrl must start with http:// or https:// (got "${baseUrl}"): copy the project URL from Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080).`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (apiKey === void 0 || apiKey === null) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"[aurabase] API key is required: set NEXT_PUBLIC_AURABASE_ANON_KEY (browser) or AURABASE_SERVICE_ROLE_KEY (server only) to a key shown in Studio \u203A Settings \u203A Connection, then pass it to createClient(url, key)."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
64
80
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
65
81
|
const resolvedOptions = options;
|
|
66
82
|
this.apiKey = apiKey || null;
|
|
@@ -72,17 +88,18 @@ var AuraClient = class {
|
|
|
72
88
|
this.debug = resolvedOptions?.debug;
|
|
73
89
|
if (!this.apiKey && typeof console !== "undefined") {
|
|
74
90
|
console.warn(
|
|
75
|
-
|
|
91
|
+
// AUTH-041 — la passerelle refuse TOUTE requête sans clé (401), y compris register/login.
|
|
92
|
+
"[aurabase] No API key provided: every request will be refused (401). Pass the anon key shown in Studio \u203A Settings \u203A Connection."
|
|
76
93
|
);
|
|
77
94
|
}
|
|
78
95
|
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
79
96
|
console.warn(
|
|
80
|
-
"[aurabase]
|
|
97
|
+
"[aurabase] Warning: locally, the project URL must include the sub-domain (e.g. http://<slug>.localhost:8080) so that the gateway can resolve the project automatically."
|
|
81
98
|
);
|
|
82
99
|
}
|
|
83
100
|
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
84
101
|
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
85
|
-
const message = "[aurabase]
|
|
102
|
+
const message = "[aurabase] SECURITY: a service_role key (aura_sk_\u2026) is passed to createClient() in a browser context. This high-privilege key MUST NEVER be exposed client-side (it would leak into the bundle). Use an anon key (aura_anon_\u2026) on the client, and createAdminClient() on the server for administration operations.";
|
|
86
103
|
if (refuse) {
|
|
87
104
|
throw new Error(message);
|
|
88
105
|
} else if (typeof console !== "undefined") {
|
|
@@ -107,6 +124,7 @@ var AuraClient = class {
|
|
|
107
124
|
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
108
125
|
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
109
126
|
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
127
|
+
this._flowType = resolvedOptions?.auth?.flowType;
|
|
110
128
|
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
111
129
|
void this.auth;
|
|
112
130
|
}
|
|
@@ -131,7 +149,8 @@ var AuraClient = class {
|
|
|
131
149
|
this._auth = new auth$1.AuthService(this, {
|
|
132
150
|
autoRefresh: this._autoRefresh,
|
|
133
151
|
persistSession: this._persistSession,
|
|
134
|
-
detectSessionInUrl: this._detectSessionInUrl
|
|
152
|
+
detectSessionInUrl: this._detectSessionInUrl,
|
|
153
|
+
flowType: this._flowType
|
|
135
154
|
});
|
|
136
155
|
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
137
156
|
if (this._realtime) {
|
|
@@ -152,7 +171,7 @@ var AuraClient = class {
|
|
|
152
171
|
get authAdmin() {
|
|
153
172
|
if (isBrowserContext()) {
|
|
154
173
|
throw new Error(
|
|
155
|
-
"[aurabase]
|
|
174
|
+
"[aurabase] SECURITY: authAdmin is not available in a browser context. The admin API requires a service_role key, which must NEVER be exposed client-side (it would leak into the bundle). Use createAdminClient() on the server only."
|
|
156
175
|
);
|
|
157
176
|
}
|
|
158
177
|
if (!this._authAdmin) this._authAdmin = new auth$1.AuthAdminService(this);
|
|
@@ -248,6 +267,7 @@ var AuraClient = class {
|
|
|
248
267
|
}
|
|
249
268
|
};
|
|
250
269
|
var MAX_CHUNK_SIZE = 3600;
|
|
270
|
+
var WARN_COOKIE_BYTES = 8 * 1024;
|
|
251
271
|
function createServerClient(baseUrl, apiKey, options) {
|
|
252
272
|
const cookieName = `aura-${core.clientScope(baseUrl)}-auth`;
|
|
253
273
|
const store = new core.LocalAuthStore(cookieName);
|
|
@@ -263,12 +283,13 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
263
283
|
const defaultCookieOpts = {
|
|
264
284
|
path: "/",
|
|
265
285
|
secure: baseUrl.startsWith("https://"),
|
|
266
|
-
sameSite: "
|
|
286
|
+
sameSite: "lax",
|
|
267
287
|
httpOnly: true,
|
|
268
288
|
maxAge: 60 * 60 * 24 * 30,
|
|
269
289
|
// 30 days
|
|
270
290
|
...options.cookieOptions
|
|
271
291
|
};
|
|
292
|
+
let tailleAvertie = false;
|
|
272
293
|
store.onChange(() => {
|
|
273
294
|
const toSet = [];
|
|
274
295
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -293,15 +314,46 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
293
314
|
}
|
|
294
315
|
}
|
|
295
316
|
}
|
|
317
|
+
const total = toSet.filter((c) => used.has(c.name)).reduce((n, c) => n + c.name.length + encodeURIComponent(c.value).length, 0);
|
|
318
|
+
if (total > WARN_COOKIE_BYTES && !tailleAvertie) {
|
|
319
|
+
tailleAvertie = true;
|
|
320
|
+
console.warn(
|
|
321
|
+
`[aurabase] The session cookie is ${total} bytes (more than 8 KB): servers and proxies often reject requests above that size (431). The access token carries user_metadata: store less in user_metadata and keep large data in your own tables.`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
296
324
|
const expireOpts = { ...defaultCookieOpts, maxAge: 0 };
|
|
297
325
|
for (const name of initialNames) {
|
|
298
326
|
if (!used.has(name)) toSet.push({ name, value: "", options: expireOpts });
|
|
299
327
|
}
|
|
300
328
|
if (toSet.length > 0) options.cookies.setAll(toSet);
|
|
301
329
|
});
|
|
302
|
-
|
|
330
|
+
const client = new AuraClient(baseUrl, apiKey, {
|
|
303
331
|
auth: { persistSession: false, storage: store }
|
|
304
332
|
});
|
|
333
|
+
const getUser = client.auth.getUser.bind(client.auth);
|
|
334
|
+
const getSession = client.auth.getSession.bind(client.auth);
|
|
335
|
+
let verifie = null;
|
|
336
|
+
let averti = false;
|
|
337
|
+
client.auth.getUser = (async (...args) => {
|
|
338
|
+
const r = await getUser(...args);
|
|
339
|
+
verifie = !r.error && r.data ? r.data : null;
|
|
340
|
+
return r;
|
|
341
|
+
});
|
|
342
|
+
client.auth.getSession = (async () => {
|
|
343
|
+
const r = await getSession();
|
|
344
|
+
if (verifie) {
|
|
345
|
+
if (r.data.session) r.data.session = { ...r.data.session, user: verifie };
|
|
346
|
+
return { ...r, user: r.data.session ? verifie : null };
|
|
347
|
+
}
|
|
348
|
+
if (!averti) {
|
|
349
|
+
averti = true;
|
|
350
|
+
console.warn(
|
|
351
|
+
"[aurabase] getSession() on the server returns the session read from the cookie without verifying it: never use it to authorize a request. Call auth.getUser() (verified by the server) first."
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return r;
|
|
355
|
+
});
|
|
356
|
+
return client;
|
|
305
357
|
}
|
|
306
358
|
|
|
307
359
|
// src/nextjs.ts
|
|
@@ -321,15 +373,15 @@ function createAuthMiddleware(options = {}) {
|
|
|
321
373
|
const nextServer = await loadNextModule("next/server");
|
|
322
374
|
if (!nextServer?.NextResponse) {
|
|
323
375
|
throw new Error(
|
|
324
|
-
"[@aurabase/nextjs] Next.js
|
|
376
|
+
"[@aurabase/nextjs] Next.js is not installed. createAuthMiddleware requires next/server."
|
|
325
377
|
);
|
|
326
378
|
}
|
|
327
379
|
const { NextResponse } = nextServer;
|
|
328
|
-
const projectUrl = options.projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ??
|
|
329
|
-
const anonKey = options.anonKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ??
|
|
380
|
+
const projectUrl = options.projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? "";
|
|
381
|
+
const anonKey = options.anonKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? "";
|
|
330
382
|
if (!projectUrl || !anonKey) {
|
|
331
383
|
console.warn(
|
|
332
|
-
"[@aurabase/nextjs]
|
|
384
|
+
"[@aurabase/nextjs] Missing environment variables: NEXT_PUBLIC_AURABASE_URL or NEXT_PUBLIC_AURABASE_ANON_KEY is not set."
|
|
333
385
|
);
|
|
334
386
|
return NextResponse.next({ request });
|
|
335
387
|
}
|
|
@@ -346,9 +398,9 @@ function createAuthMiddleware(options = {}) {
|
|
|
346
398
|
const client = createServerClient(projectUrl, anonKey, {
|
|
347
399
|
cookies: cookieHandler
|
|
348
400
|
});
|
|
349
|
-
const { data:
|
|
350
|
-
const
|
|
351
|
-
const
|
|
401
|
+
const { data: verifiedUser } = await client.auth.getUser();
|
|
402
|
+
const user = verifiedUser ?? null;
|
|
403
|
+
const session = user ? (await client.auth.getSession()).data?.session ?? null : null;
|
|
352
404
|
const pathname = request.nextUrl.pathname;
|
|
353
405
|
const publicPatterns = options.publicRoutes ?? ["/", "/login", "/signup", "/auth/callback"];
|
|
354
406
|
const isPublic = publicPatterns.some((pattern) => {
|
|
@@ -370,8 +422,8 @@ function createAuthMiddleware(options = {}) {
|
|
|
370
422
|
};
|
|
371
423
|
}
|
|
372
424
|
function createClientForServerComponent(cookieStore, projectUrl, apiKey) {
|
|
373
|
-
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ??
|
|
374
|
-
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ??
|
|
425
|
+
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? "";
|
|
426
|
+
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? "";
|
|
375
427
|
return createServerClient(url, key, {
|
|
376
428
|
cookies: {
|
|
377
429
|
getAll: () => cookieStore.getAll(),
|
|
@@ -381,8 +433,8 @@ function createClientForServerComponent(cookieStore, projectUrl, apiKey) {
|
|
|
381
433
|
});
|
|
382
434
|
}
|
|
383
435
|
function createClientForServerAction(cookieStore, projectUrl, apiKey) {
|
|
384
|
-
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ??
|
|
385
|
-
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ??
|
|
436
|
+
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? "";
|
|
437
|
+
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? "";
|
|
386
438
|
return createServerClient(url, key, {
|
|
387
439
|
cookies: {
|
|
388
440
|
getAll: () => cookieStore.getAll(),
|
|
@@ -397,13 +449,13 @@ function createClientForServerAction(cookieStore, projectUrl, apiKey) {
|
|
|
397
449
|
async function auth(options) {
|
|
398
450
|
const nextHeaders = await loadNextModule("next/headers");
|
|
399
451
|
if (!nextHeaders?.cookies) {
|
|
400
|
-
throw new Error("[@aurabase/nextjs] auth()
|
|
452
|
+
throw new Error("[@aurabase/nextjs] auth() can only be called in a Next.js App Router environment.");
|
|
401
453
|
}
|
|
402
454
|
const cookieStore = await nextHeaders.cookies();
|
|
403
455
|
const client = createClientForServerComponent(cookieStore, options?.projectUrl, options?.apiKey);
|
|
404
|
-
const { data } = await client.auth.
|
|
405
|
-
const
|
|
406
|
-
const
|
|
456
|
+
const { data: verifiedUser } = await client.auth.getUser();
|
|
457
|
+
const user = verifiedUser ?? null;
|
|
458
|
+
const session = user ? (await client.auth.getSession()).data?.session ?? null : null;
|
|
407
459
|
return {
|
|
408
460
|
userId: user?.id ?? null,
|
|
409
461
|
user,
|
package/dist/nextjs.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AuraClient } from './AuraClient-
|
|
1
|
+
import { A as AuraClient } from './AuraClient-B1OOZCSX.cjs';
|
|
2
2
|
import { User, Session } from '@aurabase/core';
|
|
3
3
|
import '@aurabase/ai';
|
|
4
4
|
import '@aurabase/auth';
|
|
@@ -53,9 +53,9 @@ interface AuthContextParam {
|
|
|
53
53
|
request: NextRequestLike;
|
|
54
54
|
}
|
|
55
55
|
interface AuthMiddlewareOptions {
|
|
56
|
-
/** Project URL (defaults to process.env.NEXT_PUBLIC_AURABASE_URL
|
|
56
|
+
/** Project URL (defaults to process.env.NEXT_PUBLIC_AURABASE_URL, the only variable name read). */
|
|
57
57
|
projectUrl?: string;
|
|
58
|
-
/** Anon API Key (defaults to process.env.NEXT_PUBLIC_AURABASE_ANON_KEY
|
|
58
|
+
/** Anon API Key (defaults to process.env.NEXT_PUBLIC_AURABASE_ANON_KEY, the only variable name read). */
|
|
59
59
|
anonKey?: string;
|
|
60
60
|
/** List of route patterns that do not require authentication (e.g. ['/', '/login', '/signup', '/auth/*']). */
|
|
61
61
|
publicRoutes?: string[];
|
package/dist/nextjs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AuraClient } from './AuraClient-
|
|
1
|
+
import { A as AuraClient } from './AuraClient-B1OOZCSX.js';
|
|
2
2
|
import { User, Session } from '@aurabase/core';
|
|
3
3
|
import '@aurabase/ai';
|
|
4
4
|
import '@aurabase/auth';
|
|
@@ -53,9 +53,9 @@ interface AuthContextParam {
|
|
|
53
53
|
request: NextRequestLike;
|
|
54
54
|
}
|
|
55
55
|
interface AuthMiddlewareOptions {
|
|
56
|
-
/** Project URL (defaults to process.env.NEXT_PUBLIC_AURABASE_URL
|
|
56
|
+
/** Project URL (defaults to process.env.NEXT_PUBLIC_AURABASE_URL, the only variable name read). */
|
|
57
57
|
projectUrl?: string;
|
|
58
|
-
/** Anon API Key (defaults to process.env.NEXT_PUBLIC_AURABASE_ANON_KEY
|
|
58
|
+
/** Anon API Key (defaults to process.env.NEXT_PUBLIC_AURABASE_ANON_KEY, the only variable name read). */
|
|
59
59
|
anonKey?: string;
|
|
60
60
|
/** List of route patterns that do not require authentication (e.g. ['/', '/login', '/signup', '/auth/*']). */
|
|
61
61
|
publicRoutes?: string[];
|
package/dist/nextjs.js
CHANGED
|
@@ -54,11 +54,27 @@ var AuraClient = class {
|
|
|
54
54
|
_persistSession;
|
|
55
55
|
_autoRefresh;
|
|
56
56
|
_detectSessionInUrl;
|
|
57
|
+
_flowType;
|
|
57
58
|
/**
|
|
58
59
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
59
60
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
60
61
|
*/
|
|
61
62
|
constructor(baseUrl, apiKey, options) {
|
|
63
|
+
if (typeof baseUrl !== "string" || baseUrl.trim() === "") {
|
|
64
|
+
throw new Error(
|
|
65
|
+
"[aurabase] Project URL is required: set NEXT_PUBLIC_AURABASE_URL to the project URL shown in Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080), then pass it to createClient(url, key)."
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (!/^https?:\/\//i.test(baseUrl.trim())) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`[aurabase] baseUrl must start with http:// or https:// (got "${baseUrl}"): copy the project URL from Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080).`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (apiKey === void 0 || apiKey === null) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
"[aurabase] API key is required: set NEXT_PUBLIC_AURABASE_ANON_KEY (browser) or AURABASE_SERVICE_ROLE_KEY (server only) to a key shown in Studio \u203A Settings \u203A Connection, then pass it to createClient(url, key)."
|
|
76
|
+
);
|
|
77
|
+
}
|
|
62
78
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
63
79
|
const resolvedOptions = options;
|
|
64
80
|
this.apiKey = apiKey || null;
|
|
@@ -70,17 +86,18 @@ var AuraClient = class {
|
|
|
70
86
|
this.debug = resolvedOptions?.debug;
|
|
71
87
|
if (!this.apiKey && typeof console !== "undefined") {
|
|
72
88
|
console.warn(
|
|
73
|
-
|
|
89
|
+
// AUTH-041 — la passerelle refuse TOUTE requête sans clé (401), y compris register/login.
|
|
90
|
+
"[aurabase] No API key provided: every request will be refused (401). Pass the anon key shown in Studio \u203A Settings \u203A Connection."
|
|
74
91
|
);
|
|
75
92
|
}
|
|
76
93
|
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
77
94
|
console.warn(
|
|
78
|
-
"[aurabase]
|
|
95
|
+
"[aurabase] Warning: locally, the project URL must include the sub-domain (e.g. http://<slug>.localhost:8080) so that the gateway can resolve the project automatically."
|
|
79
96
|
);
|
|
80
97
|
}
|
|
81
98
|
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
82
99
|
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
83
|
-
const message = "[aurabase]
|
|
100
|
+
const message = "[aurabase] SECURITY: a service_role key (aura_sk_\u2026) is passed to createClient() in a browser context. This high-privilege key MUST NEVER be exposed client-side (it would leak into the bundle). Use an anon key (aura_anon_\u2026) on the client, and createAdminClient() on the server for administration operations.";
|
|
84
101
|
if (refuse) {
|
|
85
102
|
throw new Error(message);
|
|
86
103
|
} else if (typeof console !== "undefined") {
|
|
@@ -105,6 +122,7 @@ var AuraClient = class {
|
|
|
105
122
|
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
106
123
|
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
107
124
|
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
125
|
+
this._flowType = resolvedOptions?.auth?.flowType;
|
|
108
126
|
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
109
127
|
void this.auth;
|
|
110
128
|
}
|
|
@@ -129,7 +147,8 @@ var AuraClient = class {
|
|
|
129
147
|
this._auth = new AuthService(this, {
|
|
130
148
|
autoRefresh: this._autoRefresh,
|
|
131
149
|
persistSession: this._persistSession,
|
|
132
|
-
detectSessionInUrl: this._detectSessionInUrl
|
|
150
|
+
detectSessionInUrl: this._detectSessionInUrl,
|
|
151
|
+
flowType: this._flowType
|
|
133
152
|
});
|
|
134
153
|
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
135
154
|
if (this._realtime) {
|
|
@@ -150,7 +169,7 @@ var AuraClient = class {
|
|
|
150
169
|
get authAdmin() {
|
|
151
170
|
if (isBrowserContext()) {
|
|
152
171
|
throw new Error(
|
|
153
|
-
"[aurabase]
|
|
172
|
+
"[aurabase] SECURITY: authAdmin is not available in a browser context. The admin API requires a service_role key, which must NEVER be exposed client-side (it would leak into the bundle). Use createAdminClient() on the server only."
|
|
154
173
|
);
|
|
155
174
|
}
|
|
156
175
|
if (!this._authAdmin) this._authAdmin = new AuthAdminService(this);
|
|
@@ -246,6 +265,7 @@ var AuraClient = class {
|
|
|
246
265
|
}
|
|
247
266
|
};
|
|
248
267
|
var MAX_CHUNK_SIZE = 3600;
|
|
268
|
+
var WARN_COOKIE_BYTES = 8 * 1024;
|
|
249
269
|
function createServerClient(baseUrl, apiKey, options) {
|
|
250
270
|
const cookieName = `aura-${clientScope(baseUrl)}-auth`;
|
|
251
271
|
const store = new LocalAuthStore(cookieName);
|
|
@@ -261,12 +281,13 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
261
281
|
const defaultCookieOpts = {
|
|
262
282
|
path: "/",
|
|
263
283
|
secure: baseUrl.startsWith("https://"),
|
|
264
|
-
sameSite: "
|
|
284
|
+
sameSite: "lax",
|
|
265
285
|
httpOnly: true,
|
|
266
286
|
maxAge: 60 * 60 * 24 * 30,
|
|
267
287
|
// 30 days
|
|
268
288
|
...options.cookieOptions
|
|
269
289
|
};
|
|
290
|
+
let tailleAvertie = false;
|
|
270
291
|
store.onChange(() => {
|
|
271
292
|
const toSet = [];
|
|
272
293
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -291,15 +312,46 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
291
312
|
}
|
|
292
313
|
}
|
|
293
314
|
}
|
|
315
|
+
const total = toSet.filter((c) => used.has(c.name)).reduce((n, c) => n + c.name.length + encodeURIComponent(c.value).length, 0);
|
|
316
|
+
if (total > WARN_COOKIE_BYTES && !tailleAvertie) {
|
|
317
|
+
tailleAvertie = true;
|
|
318
|
+
console.warn(
|
|
319
|
+
`[aurabase] The session cookie is ${total} bytes (more than 8 KB): servers and proxies often reject requests above that size (431). The access token carries user_metadata: store less in user_metadata and keep large data in your own tables.`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
294
322
|
const expireOpts = { ...defaultCookieOpts, maxAge: 0 };
|
|
295
323
|
for (const name of initialNames) {
|
|
296
324
|
if (!used.has(name)) toSet.push({ name, value: "", options: expireOpts });
|
|
297
325
|
}
|
|
298
326
|
if (toSet.length > 0) options.cookies.setAll(toSet);
|
|
299
327
|
});
|
|
300
|
-
|
|
328
|
+
const client = new AuraClient(baseUrl, apiKey, {
|
|
301
329
|
auth: { persistSession: false, storage: store }
|
|
302
330
|
});
|
|
331
|
+
const getUser = client.auth.getUser.bind(client.auth);
|
|
332
|
+
const getSession = client.auth.getSession.bind(client.auth);
|
|
333
|
+
let verifie = null;
|
|
334
|
+
let averti = false;
|
|
335
|
+
client.auth.getUser = (async (...args) => {
|
|
336
|
+
const r = await getUser(...args);
|
|
337
|
+
verifie = !r.error && r.data ? r.data : null;
|
|
338
|
+
return r;
|
|
339
|
+
});
|
|
340
|
+
client.auth.getSession = (async () => {
|
|
341
|
+
const r = await getSession();
|
|
342
|
+
if (verifie) {
|
|
343
|
+
if (r.data.session) r.data.session = { ...r.data.session, user: verifie };
|
|
344
|
+
return { ...r, user: r.data.session ? verifie : null };
|
|
345
|
+
}
|
|
346
|
+
if (!averti) {
|
|
347
|
+
averti = true;
|
|
348
|
+
console.warn(
|
|
349
|
+
"[aurabase] getSession() on the server returns the session read from the cookie without verifying it: never use it to authorize a request. Call auth.getUser() (verified by the server) first."
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
return r;
|
|
353
|
+
});
|
|
354
|
+
return client;
|
|
303
355
|
}
|
|
304
356
|
|
|
305
357
|
// src/nextjs.ts
|
|
@@ -319,15 +371,15 @@ function createAuthMiddleware(options = {}) {
|
|
|
319
371
|
const nextServer = await loadNextModule("next/server");
|
|
320
372
|
if (!nextServer?.NextResponse) {
|
|
321
373
|
throw new Error(
|
|
322
|
-
"[@aurabase/nextjs] Next.js
|
|
374
|
+
"[@aurabase/nextjs] Next.js is not installed. createAuthMiddleware requires next/server."
|
|
323
375
|
);
|
|
324
376
|
}
|
|
325
377
|
const { NextResponse } = nextServer;
|
|
326
|
-
const projectUrl = options.projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ??
|
|
327
|
-
const anonKey = options.anonKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ??
|
|
378
|
+
const projectUrl = options.projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? "";
|
|
379
|
+
const anonKey = options.anonKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? "";
|
|
328
380
|
if (!projectUrl || !anonKey) {
|
|
329
381
|
console.warn(
|
|
330
|
-
"[@aurabase/nextjs]
|
|
382
|
+
"[@aurabase/nextjs] Missing environment variables: NEXT_PUBLIC_AURABASE_URL or NEXT_PUBLIC_AURABASE_ANON_KEY is not set."
|
|
331
383
|
);
|
|
332
384
|
return NextResponse.next({ request });
|
|
333
385
|
}
|
|
@@ -344,9 +396,9 @@ function createAuthMiddleware(options = {}) {
|
|
|
344
396
|
const client = createServerClient(projectUrl, anonKey, {
|
|
345
397
|
cookies: cookieHandler
|
|
346
398
|
});
|
|
347
|
-
const { data:
|
|
348
|
-
const
|
|
349
|
-
const
|
|
399
|
+
const { data: verifiedUser } = await client.auth.getUser();
|
|
400
|
+
const user = verifiedUser ?? null;
|
|
401
|
+
const session = user ? (await client.auth.getSession()).data?.session ?? null : null;
|
|
350
402
|
const pathname = request.nextUrl.pathname;
|
|
351
403
|
const publicPatterns = options.publicRoutes ?? ["/", "/login", "/signup", "/auth/callback"];
|
|
352
404
|
const isPublic = publicPatterns.some((pattern) => {
|
|
@@ -368,8 +420,8 @@ function createAuthMiddleware(options = {}) {
|
|
|
368
420
|
};
|
|
369
421
|
}
|
|
370
422
|
function createClientForServerComponent(cookieStore, projectUrl, apiKey) {
|
|
371
|
-
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ??
|
|
372
|
-
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ??
|
|
423
|
+
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? "";
|
|
424
|
+
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? "";
|
|
373
425
|
return createServerClient(url, key, {
|
|
374
426
|
cookies: {
|
|
375
427
|
getAll: () => cookieStore.getAll(),
|
|
@@ -379,8 +431,8 @@ function createClientForServerComponent(cookieStore, projectUrl, apiKey) {
|
|
|
379
431
|
});
|
|
380
432
|
}
|
|
381
433
|
function createClientForServerAction(cookieStore, projectUrl, apiKey) {
|
|
382
|
-
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ??
|
|
383
|
-
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ??
|
|
434
|
+
const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? "";
|
|
435
|
+
const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? "";
|
|
384
436
|
return createServerClient(url, key, {
|
|
385
437
|
cookies: {
|
|
386
438
|
getAll: () => cookieStore.getAll(),
|
|
@@ -395,13 +447,13 @@ function createClientForServerAction(cookieStore, projectUrl, apiKey) {
|
|
|
395
447
|
async function auth(options) {
|
|
396
448
|
const nextHeaders = await loadNextModule("next/headers");
|
|
397
449
|
if (!nextHeaders?.cookies) {
|
|
398
|
-
throw new Error("[@aurabase/nextjs] auth()
|
|
450
|
+
throw new Error("[@aurabase/nextjs] auth() can only be called in a Next.js App Router environment.");
|
|
399
451
|
}
|
|
400
452
|
const cookieStore = await nextHeaders.cookies();
|
|
401
453
|
const client = createClientForServerComponent(cookieStore, options?.projectUrl, options?.apiKey);
|
|
402
|
-
const { data } = await client.auth.
|
|
403
|
-
const
|
|
404
|
-
const
|
|
454
|
+
const { data: verifiedUser } = await client.auth.getUser();
|
|
455
|
+
const user = verifiedUser ?? null;
|
|
456
|
+
const session = user ? (await client.auth.getSession()).data?.session ?? null : null;
|
|
405
457
|
return {
|
|
406
458
|
userId: user?.id ?? null,
|
|
407
459
|
user,
|
package/dist/react.d.cts
CHANGED
package/dist/react.d.ts
CHANGED
package/dist/ssr.cjs
CHANGED
|
@@ -56,11 +56,27 @@ var AuraClient = class {
|
|
|
56
56
|
_persistSession;
|
|
57
57
|
_autoRefresh;
|
|
58
58
|
_detectSessionInUrl;
|
|
59
|
+
_flowType;
|
|
59
60
|
/**
|
|
60
61
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
61
62
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
62
63
|
*/
|
|
63
64
|
constructor(baseUrl, apiKey, options) {
|
|
65
|
+
if (typeof baseUrl !== "string" || baseUrl.trim() === "") {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"[aurabase] Project URL is required: set NEXT_PUBLIC_AURABASE_URL to the project URL shown in Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080), then pass it to createClient(url, key)."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (!/^https?:\/\//i.test(baseUrl.trim())) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`[aurabase] baseUrl must start with http:// or https:// (got "${baseUrl}"): copy the project URL from Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080).`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (apiKey === void 0 || apiKey === null) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"[aurabase] API key is required: set NEXT_PUBLIC_AURABASE_ANON_KEY (browser) or AURABASE_SERVICE_ROLE_KEY (server only) to a key shown in Studio \u203A Settings \u203A Connection, then pass it to createClient(url, key)."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
64
80
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
65
81
|
const resolvedOptions = options;
|
|
66
82
|
this.apiKey = apiKey || null;
|
|
@@ -72,17 +88,18 @@ var AuraClient = class {
|
|
|
72
88
|
this.debug = resolvedOptions?.debug;
|
|
73
89
|
if (!this.apiKey && typeof console !== "undefined") {
|
|
74
90
|
console.warn(
|
|
75
|
-
|
|
91
|
+
// AUTH-041 — la passerelle refuse TOUTE requête sans clé (401), y compris register/login.
|
|
92
|
+
"[aurabase] No API key provided: every request will be refused (401). Pass the anon key shown in Studio \u203A Settings \u203A Connection."
|
|
76
93
|
);
|
|
77
94
|
}
|
|
78
95
|
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
79
96
|
console.warn(
|
|
80
|
-
"[aurabase]
|
|
97
|
+
"[aurabase] Warning: locally, the project URL must include the sub-domain (e.g. http://<slug>.localhost:8080) so that the gateway can resolve the project automatically."
|
|
81
98
|
);
|
|
82
99
|
}
|
|
83
100
|
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
84
101
|
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
85
|
-
const message = "[aurabase]
|
|
102
|
+
const message = "[aurabase] SECURITY: a service_role key (aura_sk_\u2026) is passed to createClient() in a browser context. This high-privilege key MUST NEVER be exposed client-side (it would leak into the bundle). Use an anon key (aura_anon_\u2026) on the client, and createAdminClient() on the server for administration operations.";
|
|
86
103
|
if (refuse) {
|
|
87
104
|
throw new Error(message);
|
|
88
105
|
} else if (typeof console !== "undefined") {
|
|
@@ -107,6 +124,7 @@ var AuraClient = class {
|
|
|
107
124
|
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
108
125
|
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
109
126
|
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
127
|
+
this._flowType = resolvedOptions?.auth?.flowType;
|
|
110
128
|
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
111
129
|
void this.auth;
|
|
112
130
|
}
|
|
@@ -131,7 +149,8 @@ var AuraClient = class {
|
|
|
131
149
|
this._auth = new auth.AuthService(this, {
|
|
132
150
|
autoRefresh: this._autoRefresh,
|
|
133
151
|
persistSession: this._persistSession,
|
|
134
|
-
detectSessionInUrl: this._detectSessionInUrl
|
|
152
|
+
detectSessionInUrl: this._detectSessionInUrl,
|
|
153
|
+
flowType: this._flowType
|
|
135
154
|
});
|
|
136
155
|
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
137
156
|
if (this._realtime) {
|
|
@@ -152,7 +171,7 @@ var AuraClient = class {
|
|
|
152
171
|
get authAdmin() {
|
|
153
172
|
if (isBrowserContext()) {
|
|
154
173
|
throw new Error(
|
|
155
|
-
"[aurabase]
|
|
174
|
+
"[aurabase] SECURITY: authAdmin is not available in a browser context. The admin API requires a service_role key, which must NEVER be exposed client-side (it would leak into the bundle). Use createAdminClient() on the server only."
|
|
156
175
|
);
|
|
157
176
|
}
|
|
158
177
|
if (!this._authAdmin) this._authAdmin = new auth.AuthAdminService(this);
|
|
@@ -248,6 +267,7 @@ var AuraClient = class {
|
|
|
248
267
|
}
|
|
249
268
|
};
|
|
250
269
|
var MAX_CHUNK_SIZE = 3600;
|
|
270
|
+
var WARN_COOKIE_BYTES = 8 * 1024;
|
|
251
271
|
function createServerClient(baseUrl, apiKey, options) {
|
|
252
272
|
const cookieName = `aura-${core.clientScope(baseUrl)}-auth`;
|
|
253
273
|
const store = new core.LocalAuthStore(cookieName);
|
|
@@ -263,12 +283,13 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
263
283
|
const defaultCookieOpts = {
|
|
264
284
|
path: "/",
|
|
265
285
|
secure: baseUrl.startsWith("https://"),
|
|
266
|
-
sameSite: "
|
|
286
|
+
sameSite: "lax",
|
|
267
287
|
httpOnly: true,
|
|
268
288
|
maxAge: 60 * 60 * 24 * 30,
|
|
269
289
|
// 30 days
|
|
270
290
|
...options.cookieOptions
|
|
271
291
|
};
|
|
292
|
+
let tailleAvertie = false;
|
|
272
293
|
store.onChange(() => {
|
|
273
294
|
const toSet = [];
|
|
274
295
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -293,15 +314,46 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
293
314
|
}
|
|
294
315
|
}
|
|
295
316
|
}
|
|
317
|
+
const total = toSet.filter((c) => used.has(c.name)).reduce((n, c) => n + c.name.length + encodeURIComponent(c.value).length, 0);
|
|
318
|
+
if (total > WARN_COOKIE_BYTES && !tailleAvertie) {
|
|
319
|
+
tailleAvertie = true;
|
|
320
|
+
console.warn(
|
|
321
|
+
`[aurabase] The session cookie is ${total} bytes (more than 8 KB): servers and proxies often reject requests above that size (431). The access token carries user_metadata: store less in user_metadata and keep large data in your own tables.`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
296
324
|
const expireOpts = { ...defaultCookieOpts, maxAge: 0 };
|
|
297
325
|
for (const name of initialNames) {
|
|
298
326
|
if (!used.has(name)) toSet.push({ name, value: "", options: expireOpts });
|
|
299
327
|
}
|
|
300
328
|
if (toSet.length > 0) options.cookies.setAll(toSet);
|
|
301
329
|
});
|
|
302
|
-
|
|
330
|
+
const client = new AuraClient(baseUrl, apiKey, {
|
|
303
331
|
auth: { persistSession: false, storage: store }
|
|
304
332
|
});
|
|
333
|
+
const getUser = client.auth.getUser.bind(client.auth);
|
|
334
|
+
const getSession = client.auth.getSession.bind(client.auth);
|
|
335
|
+
let verifie = null;
|
|
336
|
+
let averti = false;
|
|
337
|
+
client.auth.getUser = (async (...args) => {
|
|
338
|
+
const r = await getUser(...args);
|
|
339
|
+
verifie = !r.error && r.data ? r.data : null;
|
|
340
|
+
return r;
|
|
341
|
+
});
|
|
342
|
+
client.auth.getSession = (async () => {
|
|
343
|
+
const r = await getSession();
|
|
344
|
+
if (verifie) {
|
|
345
|
+
if (r.data.session) r.data.session = { ...r.data.session, user: verifie };
|
|
346
|
+
return { ...r, user: r.data.session ? verifie : null };
|
|
347
|
+
}
|
|
348
|
+
if (!averti) {
|
|
349
|
+
averti = true;
|
|
350
|
+
console.warn(
|
|
351
|
+
"[aurabase] getSession() on the server returns the session read from the cookie without verifying it: never use it to authorize a request. Call auth.getUser() (verified by the server) first."
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return r;
|
|
355
|
+
});
|
|
356
|
+
return client;
|
|
305
357
|
}
|
|
306
358
|
function createBrowserClient(baseUrl, apiKey, options) {
|
|
307
359
|
return new AuraClient(baseUrl, apiKey, options);
|
package/dist/ssr.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SerializeCookieOptions, AuraClientOptions } from '@aurabase/core';
|
|
2
2
|
export { SerializeCookieOptions, parseCookieHeader, serializeCookieHeader } from '@aurabase/core';
|
|
3
|
-
import { A as AuraClient } from './AuraClient-
|
|
3
|
+
import { A as AuraClient } from './AuraClient-B1OOZCSX.cjs';
|
|
4
4
|
import '@aurabase/ai';
|
|
5
5
|
import '@aurabase/auth';
|
|
6
6
|
import '@aurabase/db';
|
|
@@ -18,7 +18,7 @@ import '@aurabase/storage';
|
|
|
18
18
|
*
|
|
19
19
|
* export async function middleware(request) {
|
|
20
20
|
* let response = NextResponse.next({ request })
|
|
21
|
-
* const client = createServerClient(
|
|
21
|
+
* const client = createServerClient(NEXT_PUBLIC_AURABASE_URL, NEXT_PUBLIC_AURABASE_ANON_KEY, {
|
|
22
22
|
* cookies: {
|
|
23
23
|
* getAll: () => request.cookies.getAll(),
|
|
24
24
|
* setAll: (cookies) => {
|
|
@@ -29,7 +29,9 @@ import '@aurabase/storage';
|
|
|
29
29
|
* },
|
|
30
30
|
* },
|
|
31
31
|
* })
|
|
32
|
-
*
|
|
32
|
+
* // getUser() renouvelle les jetons ET fait vérifier l'utilisateur par le serveur.
|
|
33
|
+
* // Ne jamais autoriser avec getSession() côté serveur : elle lit le cookie sans le vérifier.
|
|
34
|
+
* const { data: user } = await client.auth.getUser()
|
|
33
35
|
* return response
|
|
34
36
|
* }
|
|
35
37
|
* ```
|
package/dist/ssr.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SerializeCookieOptions, AuraClientOptions } from '@aurabase/core';
|
|
2
2
|
export { SerializeCookieOptions, parseCookieHeader, serializeCookieHeader } from '@aurabase/core';
|
|
3
|
-
import { A as AuraClient } from './AuraClient-
|
|
3
|
+
import { A as AuraClient } from './AuraClient-B1OOZCSX.js';
|
|
4
4
|
import '@aurabase/ai';
|
|
5
5
|
import '@aurabase/auth';
|
|
6
6
|
import '@aurabase/db';
|
|
@@ -18,7 +18,7 @@ import '@aurabase/storage';
|
|
|
18
18
|
*
|
|
19
19
|
* export async function middleware(request) {
|
|
20
20
|
* let response = NextResponse.next({ request })
|
|
21
|
-
* const client = createServerClient(
|
|
21
|
+
* const client = createServerClient(NEXT_PUBLIC_AURABASE_URL, NEXT_PUBLIC_AURABASE_ANON_KEY, {
|
|
22
22
|
* cookies: {
|
|
23
23
|
* getAll: () => request.cookies.getAll(),
|
|
24
24
|
* setAll: (cookies) => {
|
|
@@ -29,7 +29,9 @@ import '@aurabase/storage';
|
|
|
29
29
|
* },
|
|
30
30
|
* },
|
|
31
31
|
* })
|
|
32
|
-
*
|
|
32
|
+
* // getUser() renouvelle les jetons ET fait vérifier l'utilisateur par le serveur.
|
|
33
|
+
* // Ne jamais autoriser avec getSession() côté serveur : elle lit le cookie sans le vérifier.
|
|
34
|
+
* const { data: user } = await client.auth.getUser()
|
|
33
35
|
* return response
|
|
34
36
|
* }
|
|
35
37
|
* ```
|
package/dist/ssr.js
CHANGED
|
@@ -55,11 +55,27 @@ var AuraClient = class {
|
|
|
55
55
|
_persistSession;
|
|
56
56
|
_autoRefresh;
|
|
57
57
|
_detectSessionInUrl;
|
|
58
|
+
_flowType;
|
|
58
59
|
/**
|
|
59
60
|
* @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
|
|
60
61
|
* @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
|
|
61
62
|
*/
|
|
62
63
|
constructor(baseUrl, apiKey, options) {
|
|
64
|
+
if (typeof baseUrl !== "string" || baseUrl.trim() === "") {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"[aurabase] Project URL is required: set NEXT_PUBLIC_AURABASE_URL to the project URL shown in Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080), then pass it to createClient(url, key)."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (!/^https?:\/\//i.test(baseUrl.trim())) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`[aurabase] baseUrl must start with http:// or https:// (got "${baseUrl}"): copy the project URL from Studio \u203A Settings \u203A Connection (e.g. http://<slug>.localhost:8080).`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
if (apiKey === void 0 || apiKey === null) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"[aurabase] API key is required: set NEXT_PUBLIC_AURABASE_ANON_KEY (browser) or AURABASE_SERVICE_ROLE_KEY (server only) to a key shown in Studio \u203A Settings \u203A Connection, then pass it to createClient(url, key)."
|
|
77
|
+
);
|
|
78
|
+
}
|
|
63
79
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
64
80
|
const resolvedOptions = options;
|
|
65
81
|
this.apiKey = apiKey || null;
|
|
@@ -71,17 +87,18 @@ var AuraClient = class {
|
|
|
71
87
|
this.debug = resolvedOptions?.debug;
|
|
72
88
|
if (!this.apiKey && typeof console !== "undefined") {
|
|
73
89
|
console.warn(
|
|
74
|
-
|
|
90
|
+
// AUTH-041 — la passerelle refuse TOUTE requête sans clé (401), y compris register/login.
|
|
91
|
+
"[aurabase] No API key provided: every request will be refused (401). Pass the anon key shown in Studio \u203A Settings \u203A Connection."
|
|
75
92
|
);
|
|
76
93
|
}
|
|
77
94
|
if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
|
|
78
95
|
console.warn(
|
|
79
|
-
"[aurabase]
|
|
96
|
+
"[aurabase] Warning: locally, the project URL must include the sub-domain (e.g. http://<slug>.localhost:8080) so that the gateway can resolve the project automatically."
|
|
80
97
|
);
|
|
81
98
|
}
|
|
82
99
|
if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
|
|
83
100
|
const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
|
|
84
|
-
const message = "[aurabase]
|
|
101
|
+
const message = "[aurabase] SECURITY: a service_role key (aura_sk_\u2026) is passed to createClient() in a browser context. This high-privilege key MUST NEVER be exposed client-side (it would leak into the bundle). Use an anon key (aura_anon_\u2026) on the client, and createAdminClient() on the server for administration operations.";
|
|
85
102
|
if (refuse) {
|
|
86
103
|
throw new Error(message);
|
|
87
104
|
} else if (typeof console !== "undefined") {
|
|
@@ -106,6 +123,7 @@ var AuraClient = class {
|
|
|
106
123
|
this._persistSession = resolvedOptions?.auth?.persistSession !== false;
|
|
107
124
|
this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
|
|
108
125
|
this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
|
|
126
|
+
this._flowType = resolvedOptions?.auth?.flowType;
|
|
109
127
|
if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
|
|
110
128
|
void this.auth;
|
|
111
129
|
}
|
|
@@ -130,7 +148,8 @@ var AuraClient = class {
|
|
|
130
148
|
this._auth = new AuthService(this, {
|
|
131
149
|
autoRefresh: this._autoRefresh,
|
|
132
150
|
persistSession: this._persistSession,
|
|
133
|
-
detectSessionInUrl: this._detectSessionInUrl
|
|
151
|
+
detectSessionInUrl: this._detectSessionInUrl,
|
|
152
|
+
flowType: this._flowType
|
|
134
153
|
});
|
|
135
154
|
this._auth.onAuthStateChange(({ event, accessToken }) => {
|
|
136
155
|
if (this._realtime) {
|
|
@@ -151,7 +170,7 @@ var AuraClient = class {
|
|
|
151
170
|
get authAdmin() {
|
|
152
171
|
if (isBrowserContext()) {
|
|
153
172
|
throw new Error(
|
|
154
|
-
"[aurabase]
|
|
173
|
+
"[aurabase] SECURITY: authAdmin is not available in a browser context. The admin API requires a service_role key, which must NEVER be exposed client-side (it would leak into the bundle). Use createAdminClient() on the server only."
|
|
155
174
|
);
|
|
156
175
|
}
|
|
157
176
|
if (!this._authAdmin) this._authAdmin = new AuthAdminService(this);
|
|
@@ -247,6 +266,7 @@ var AuraClient = class {
|
|
|
247
266
|
}
|
|
248
267
|
};
|
|
249
268
|
var MAX_CHUNK_SIZE = 3600;
|
|
269
|
+
var WARN_COOKIE_BYTES = 8 * 1024;
|
|
250
270
|
function createServerClient(baseUrl, apiKey, options) {
|
|
251
271
|
const cookieName = `aura-${clientScope(baseUrl)}-auth`;
|
|
252
272
|
const store = new LocalAuthStore(cookieName);
|
|
@@ -262,12 +282,13 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
262
282
|
const defaultCookieOpts = {
|
|
263
283
|
path: "/",
|
|
264
284
|
secure: baseUrl.startsWith("https://"),
|
|
265
|
-
sameSite: "
|
|
285
|
+
sameSite: "lax",
|
|
266
286
|
httpOnly: true,
|
|
267
287
|
maxAge: 60 * 60 * 24 * 30,
|
|
268
288
|
// 30 days
|
|
269
289
|
...options.cookieOptions
|
|
270
290
|
};
|
|
291
|
+
let tailleAvertie = false;
|
|
271
292
|
store.onChange(() => {
|
|
272
293
|
const toSet = [];
|
|
273
294
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -292,15 +313,46 @@ function createServerClient(baseUrl, apiKey, options) {
|
|
|
292
313
|
}
|
|
293
314
|
}
|
|
294
315
|
}
|
|
316
|
+
const total = toSet.filter((c) => used.has(c.name)).reduce((n, c) => n + c.name.length + encodeURIComponent(c.value).length, 0);
|
|
317
|
+
if (total > WARN_COOKIE_BYTES && !tailleAvertie) {
|
|
318
|
+
tailleAvertie = true;
|
|
319
|
+
console.warn(
|
|
320
|
+
`[aurabase] The session cookie is ${total} bytes (more than 8 KB): servers and proxies often reject requests above that size (431). The access token carries user_metadata: store less in user_metadata and keep large data in your own tables.`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
295
323
|
const expireOpts = { ...defaultCookieOpts, maxAge: 0 };
|
|
296
324
|
for (const name of initialNames) {
|
|
297
325
|
if (!used.has(name)) toSet.push({ name, value: "", options: expireOpts });
|
|
298
326
|
}
|
|
299
327
|
if (toSet.length > 0) options.cookies.setAll(toSet);
|
|
300
328
|
});
|
|
301
|
-
|
|
329
|
+
const client = new AuraClient(baseUrl, apiKey, {
|
|
302
330
|
auth: { persistSession: false, storage: store }
|
|
303
331
|
});
|
|
332
|
+
const getUser = client.auth.getUser.bind(client.auth);
|
|
333
|
+
const getSession = client.auth.getSession.bind(client.auth);
|
|
334
|
+
let verifie = null;
|
|
335
|
+
let averti = false;
|
|
336
|
+
client.auth.getUser = (async (...args) => {
|
|
337
|
+
const r = await getUser(...args);
|
|
338
|
+
verifie = !r.error && r.data ? r.data : null;
|
|
339
|
+
return r;
|
|
340
|
+
});
|
|
341
|
+
client.auth.getSession = (async () => {
|
|
342
|
+
const r = await getSession();
|
|
343
|
+
if (verifie) {
|
|
344
|
+
if (r.data.session) r.data.session = { ...r.data.session, user: verifie };
|
|
345
|
+
return { ...r, user: r.data.session ? verifie : null };
|
|
346
|
+
}
|
|
347
|
+
if (!averti) {
|
|
348
|
+
averti = true;
|
|
349
|
+
console.warn(
|
|
350
|
+
"[aurabase] getSession() on the server returns the session read from the cookie without verifying it: never use it to authorize a request. Call auth.getUser() (verified by the server) first."
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return r;
|
|
354
|
+
});
|
|
355
|
+
return client;
|
|
304
356
|
}
|
|
305
357
|
function createBrowserClient(baseUrl, apiKey, options) {
|
|
306
358
|
return new AuraClient(baseUrl, apiKey, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurabase/aurabase-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Official JavaScript/TypeScript client for Aurabase BaaS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"default": "./dist/nextjs.cjs"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
"./package.json": "./package.json",
|
|
40
41
|
"./react": {
|
|
41
42
|
"import": {
|
|
42
43
|
"types": "./dist/react.d.ts",
|
|
@@ -61,12 +62,12 @@
|
|
|
61
62
|
"author": "Aurabase",
|
|
62
63
|
"repository": {
|
|
63
64
|
"type": "git",
|
|
64
|
-
"url": "git+https://github.com/
|
|
65
|
+
"url": "git+https://github.com/Aurabase-cloud/Aurabase.git",
|
|
65
66
|
"directory": "aurabase-js/packages/aurabase"
|
|
66
67
|
},
|
|
67
68
|
"homepage": "https://aurabase.cloud",
|
|
68
69
|
"bugs": {
|
|
69
|
-
"url": "https://github.com/
|
|
70
|
+
"url": "https://github.com/Aurabase-cloud/Aurabase/issues"
|
|
70
71
|
},
|
|
71
72
|
"keywords": [
|
|
72
73
|
"aurabase",
|
|
@@ -76,14 +77,14 @@
|
|
|
76
77
|
"client"
|
|
77
78
|
],
|
|
78
79
|
"dependencies": {
|
|
79
|
-
"@aurabase/
|
|
80
|
-
"@aurabase/
|
|
81
|
-
"@aurabase/
|
|
82
|
-
"@aurabase/
|
|
83
|
-
"@aurabase/
|
|
84
|
-
"@aurabase/
|
|
85
|
-
"@aurabase/
|
|
86
|
-
"@aurabase/
|
|
80
|
+
"@aurabase/core": "0.7.0",
|
|
81
|
+
"@aurabase/auth": "0.7.0",
|
|
82
|
+
"@aurabase/storage": "0.7.0",
|
|
83
|
+
"@aurabase/ai": "0.7.0",
|
|
84
|
+
"@aurabase/functions": "0.7.0",
|
|
85
|
+
"@aurabase/notifications": "0.7.0",
|
|
86
|
+
"@aurabase/db": "0.7.0",
|
|
87
|
+
"@aurabase/realtime": "0.7.0"
|
|
87
88
|
},
|
|
88
89
|
"devDependencies": {
|
|
89
90
|
"@types/node": "20.14.15",
|