@aurabase/aurabase-js 0.5.2 → 0.5.4

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.
@@ -1,7 +1,7 @@
1
1
  import { AiService } from '@aurabase/ai';
2
2
  import { AuthService, AuthAdminService } from '@aurabase/auth';
3
3
  import { AuraClientLike, BaseAuthStore, AuraObservabilityEvent, AuraClientOptions, ChannelConfig } from '@aurabase/core';
4
- import { DatabaseService } from '@aurabase/db';
4
+ import { GenericSchema, DatabaseService, AuraQueryBuilder, AuraClientOptionsT } from '@aurabase/db';
5
5
  import { FunctionsService } from '@aurabase/functions';
6
6
  import { NotificationsService } from '@aurabase/notifications';
7
7
  import { RealtimeService, AuraChannel } from '@aurabase/realtime';
@@ -23,7 +23,9 @@ import { StorageService } from '@aurabase/storage';
23
23
  * const { data } = await aura.db.from('posts').eq('published', true)
24
24
  * ```
25
25
  */
26
- declare class AuraClient<Database = any> implements AuraClientLike {
26
+ declare class AuraClient<Database = any, Schema extends GenericSchema = Database extends {
27
+ public: infer S;
28
+ } ? S extends GenericSchema ? S : any : any> implements AuraClientLike {
27
29
  /** URL du projet (`https://<slug>.aurabase.cloud`), sans barre finale. */
28
30
  readonly baseUrl: string;
29
31
  readonly apiKey: string | null;
@@ -64,12 +66,34 @@ declare class AuraClient<Database = any> implements AuraClientLike {
64
66
  dispose(): void;
65
67
  get auth(): AuthService;
66
68
  get authAdmin(): AuthAdminService;
67
- get db(): DatabaseService<Database>;
69
+ get db(): DatabaseService<Database, Schema>;
68
70
  get storage(): StorageService;
69
71
  get realtime(): RealtimeService;
70
72
  get functions(): FunctionsService;
71
73
  get ai(): AiService;
72
74
  get notifications(): NotificationsService;
75
+ /**
76
+ * Shortcut: query a database table or view (Supabase-compatible API).
77
+ * Equivalent to `aura.db.from(table)`.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const { data, error } = await aura.from('posts').select('*').limit(10)
82
+ * ```
83
+ */
84
+ from<TableName extends string & keyof Schema['Tables'], Table extends Schema['Tables'][TableName]>(table: TableName): AuraQueryBuilder<Schema, Table, TableName, AuraClientOptionsT>;
85
+ from<ViewName extends string & keyof Schema['Views'], View extends Schema['Views'][ViewName]>(view: ViewName): AuraQueryBuilder<Schema, View, ViewName, AuraClientOptionsT>;
86
+ from(table: string): AuraQueryBuilder<any, any, any, AuraClientOptionsT>;
87
+ /**
88
+ * Shortcut: call a stored procedure / PostgreSQL function via RPC (Supabase-compatible API).
89
+ * Equivalent to `aura.db.rpc(fn, args, options)`.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const { data, error } = await aura.rpc('echo_test', { message: 'hello' })
94
+ * ```
95
+ */
96
+ rpc<FnName extends string = string, Args extends Record<string, unknown> = Record<string, unknown>>(fn: FnName, args?: Args, options?: Parameters<DatabaseService<Database, Schema>['rpc']>[2]): ReturnType<DatabaseService<Database, Schema>['rpc']>;
73
97
  /**
74
98
  * Shortcut: create a realtime channel with Supabase-compatible API.
75
99
  * Equivalent to `aura.realtime.channel(name)`.
@@ -1,7 +1,7 @@
1
1
  import { AiService } from '@aurabase/ai';
2
2
  import { AuthService, AuthAdminService } from '@aurabase/auth';
3
3
  import { AuraClientLike, BaseAuthStore, AuraObservabilityEvent, AuraClientOptions, ChannelConfig } from '@aurabase/core';
4
- import { DatabaseService } from '@aurabase/db';
4
+ import { GenericSchema, DatabaseService, AuraQueryBuilder, AuraClientOptionsT } from '@aurabase/db';
5
5
  import { FunctionsService } from '@aurabase/functions';
6
6
  import { NotificationsService } from '@aurabase/notifications';
7
7
  import { RealtimeService, AuraChannel } from '@aurabase/realtime';
@@ -23,7 +23,9 @@ import { StorageService } from '@aurabase/storage';
23
23
  * const { data } = await aura.db.from('posts').eq('published', true)
24
24
  * ```
25
25
  */
26
- declare class AuraClient<Database = any> implements AuraClientLike {
26
+ declare class AuraClient<Database = any, Schema extends GenericSchema = Database extends {
27
+ public: infer S;
28
+ } ? S extends GenericSchema ? S : any : any> implements AuraClientLike {
27
29
  /** URL du projet (`https://<slug>.aurabase.cloud`), sans barre finale. */
28
30
  readonly baseUrl: string;
29
31
  readonly apiKey: string | null;
@@ -64,12 +66,34 @@ declare class AuraClient<Database = any> implements AuraClientLike {
64
66
  dispose(): void;
65
67
  get auth(): AuthService;
66
68
  get authAdmin(): AuthAdminService;
67
- get db(): DatabaseService<Database>;
69
+ get db(): DatabaseService<Database, Schema>;
68
70
  get storage(): StorageService;
69
71
  get realtime(): RealtimeService;
70
72
  get functions(): FunctionsService;
71
73
  get ai(): AiService;
72
74
  get notifications(): NotificationsService;
75
+ /**
76
+ * Shortcut: query a database table or view (Supabase-compatible API).
77
+ * Equivalent to `aura.db.from(table)`.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const { data, error } = await aura.from('posts').select('*').limit(10)
82
+ * ```
83
+ */
84
+ from<TableName extends string & keyof Schema['Tables'], Table extends Schema['Tables'][TableName]>(table: TableName): AuraQueryBuilder<Schema, Table, TableName, AuraClientOptionsT>;
85
+ from<ViewName extends string & keyof Schema['Views'], View extends Schema['Views'][ViewName]>(view: ViewName): AuraQueryBuilder<Schema, View, ViewName, AuraClientOptionsT>;
86
+ from(table: string): AuraQueryBuilder<any, any, any, AuraClientOptionsT>;
87
+ /**
88
+ * Shortcut: call a stored procedure / PostgreSQL function via RPC (Supabase-compatible API).
89
+ * Equivalent to `aura.db.rpc(fn, args, options)`.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const { data, error } = await aura.rpc('echo_test', { message: 'hello' })
94
+ * ```
95
+ */
96
+ rpc<FnName extends string = string, Args extends Record<string, unknown> = Record<string, unknown>>(fn: FnName, args?: Args, options?: Parameters<DatabaseService<Database, Schema>['rpc']>[2]): ReturnType<DatabaseService<Database, Schema>['rpc']>;
73
97
  /**
74
98
  * Shortcut: create a realtime channel with Supabase-compatible API.
75
99
  * Equivalent to `aura.realtime.channel(name)`.
package/dist/index.cjs CHANGED
@@ -63,6 +63,11 @@ var AuraClient = class {
63
63
  "[aurabase] No API key provided. Most operations require an API key (apikey header). Only public auth routes (register, login, refresh) will work without one."
64
64
  );
65
65
  }
66
+ if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
67
+ console.warn(
68
+ "[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."
69
+ );
70
+ }
66
71
  if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
67
72
  const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
68
73
  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.";
@@ -76,7 +81,12 @@ var AuraClient = class {
76
81
  this.authStore = resolvedOptions.auth.storage;
77
82
  } else if (resolvedOptions?.auth?.persistSession === false) {
78
83
  this.authStore = new core.BaseAuthStore();
79
- } else if (typeof localStorage !== "undefined") {
84
+ } else if (isBrowserContext() && typeof window.localStorage !== "undefined" || typeof globalThis !== "undefined" && (() => {
85
+ const g = globalThis;
86
+ const proc = g?.process;
87
+ const isTest = !!(proc?.env?.VITEST || proc?.env?.NODE_ENV === "test" || proc?.env?.JEST_WORKER_ID);
88
+ return isTest && !!g?.localStorage && typeof g.localStorage.getItem === "function";
89
+ })()) {
80
90
  this.authStore = new core.LocalAuthStore(`aura-${core.clientScope(this.baseUrl)}-auth`);
81
91
  } else {
82
92
  this.authStore = new core.BaseAuthStore();
@@ -153,6 +163,21 @@ var AuraClient = class {
153
163
  if (!this._notifications) this._notifications = new notifications.NotificationsService(this);
154
164
  return this._notifications;
155
165
  }
166
+ from(table) {
167
+ return this.db.from(table);
168
+ }
169
+ /**
170
+ * Shortcut: call a stored procedure / PostgreSQL function via RPC (Supabase-compatible API).
171
+ * Equivalent to `aura.db.rpc(fn, args, options)`.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * const { data, error } = await aura.rpc('echo_test', { message: 'hello' })
176
+ * ```
177
+ */
178
+ rpc(fn, args, options) {
179
+ return this.db.rpc(fn, args, options);
180
+ }
156
181
  /**
157
182
  * Shortcut: create a realtime channel with Supabase-compatible API.
158
183
  * Equivalent to `aura.realtime.channel(name)`.
package/dist/index.d.cts CHANGED
@@ -6,8 +6,8 @@ export { DatabaseService, QueryBuilder } from '@aurabase/db';
6
6
  export { FunctionsService } from '@aurabase/functions';
7
7
  export { NotificationsAdminService, NotificationsService } from '@aurabase/notifications';
8
8
  export { AuraChannel, RealtimeService } from '@aurabase/realtime';
9
- export { StorageService } from '@aurabase/storage';
10
- import { A as AuraClient } from './AuraClient-DL7mqfNu.cjs';
9
+ export { StorageBucketClient, StorageService } from '@aurabase/storage';
10
+ import { A as AuraClient } from './AuraClient-5jDiXjrO.cjs';
11
11
 
12
12
  /**
13
13
  * Create a new Aurabase client instance.
package/dist/index.d.ts CHANGED
@@ -6,8 +6,8 @@ export { DatabaseService, QueryBuilder } from '@aurabase/db';
6
6
  export { FunctionsService } from '@aurabase/functions';
7
7
  export { NotificationsAdminService, NotificationsService } from '@aurabase/notifications';
8
8
  export { AuraChannel, RealtimeService } from '@aurabase/realtime';
9
- export { StorageService } from '@aurabase/storage';
10
- import { A as AuraClient } from './AuraClient-DL7mqfNu.js';
9
+ export { StorageBucketClient, StorageService } from '@aurabase/storage';
10
+ import { A as AuraClient } from './AuraClient-5jDiXjrO.js';
11
11
 
12
12
  /**
13
13
  * Create a new Aurabase client instance.
package/dist/index.js CHANGED
@@ -69,6 +69,11 @@ var AuraClient = class {
69
69
  "[aurabase] No API key provided. Most operations require an API key (apikey header). Only public auth routes (register, login, refresh) will work without one."
70
70
  );
71
71
  }
72
+ if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
73
+ console.warn(
74
+ "[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."
75
+ );
76
+ }
72
77
  if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
73
78
  const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
74
79
  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.";
@@ -82,7 +87,12 @@ var AuraClient = class {
82
87
  this.authStore = resolvedOptions.auth.storage;
83
88
  } else if (resolvedOptions?.auth?.persistSession === false) {
84
89
  this.authStore = new BaseAuthStore();
85
- } else if (typeof localStorage !== "undefined") {
90
+ } else if (isBrowserContext() && typeof window.localStorage !== "undefined" || typeof globalThis !== "undefined" && (() => {
91
+ const g = globalThis;
92
+ const proc = g?.process;
93
+ const isTest = !!(proc?.env?.VITEST || proc?.env?.NODE_ENV === "test" || proc?.env?.JEST_WORKER_ID);
94
+ return isTest && !!g?.localStorage && typeof g.localStorage.getItem === "function";
95
+ })()) {
86
96
  this.authStore = new LocalAuthStore(`aura-${clientScope(this.baseUrl)}-auth`);
87
97
  } else {
88
98
  this.authStore = new BaseAuthStore();
@@ -159,6 +169,21 @@ var AuraClient = class {
159
169
  if (!this._notifications) this._notifications = new NotificationsService(this);
160
170
  return this._notifications;
161
171
  }
172
+ from(table) {
173
+ return this.db.from(table);
174
+ }
175
+ /**
176
+ * Shortcut: call a stored procedure / PostgreSQL function via RPC (Supabase-compatible API).
177
+ * Equivalent to `aura.db.rpc(fn, args, options)`.
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * const { data, error } = await aura.rpc('echo_test', { message: 'hello' })
182
+ * ```
183
+ */
184
+ rpc(fn, args, options) {
185
+ return this.db.rpc(fn, args, options);
186
+ }
162
187
  /**
163
188
  * Shortcut: create a realtime channel with Supabase-compatible API.
164
189
  * Equivalent to `aura.realtime.channel(name)`.
@@ -0,0 +1,389 @@
1
+ 'use strict';
2
+
3
+ var core = require('@aurabase/core');
4
+ var ai = require('@aurabase/ai');
5
+ var auth$1 = require('@aurabase/auth');
6
+ var db = require('@aurabase/db');
7
+ var functions = require('@aurabase/functions');
8
+ var notifications = require('@aurabase/notifications');
9
+ var realtime = require('@aurabase/realtime');
10
+ var storage = require('@aurabase/storage');
11
+
12
+ // src/ssr.ts
13
+ function isBrowserContext() {
14
+ if (typeof window !== "undefined") return true;
15
+ const g = globalThis;
16
+ if (typeof g.DedicatedWorkerGlobalScope !== "undefined") return true;
17
+ if (typeof g.SharedWorkerGlobalScope !== "undefined") return true;
18
+ return false;
19
+ }
20
+ var SERVICE_ROLE_KEY_PREFIX = "aura_sk_";
21
+ var AuraClient = class {
22
+ /** URL du projet (`https://<slug>.aurabase.cloud`), sans barre finale. */
23
+ baseUrl;
24
+ apiKey;
25
+ fetchFn;
26
+ authStore;
27
+ retryConfig;
28
+ /** Timeout par défaut (ms) des requêtes JSON sans signal. `undefined` → défaut core (30s). */
29
+ requestTimeoutMs;
30
+ /** Hook d'observabilité (LOT 3) — voir `AuraClientOptions.onEvent`. */
31
+ onEvent;
32
+ /** Journalise chaque `AuraObservabilityEvent` via `console.debug` — voir `AuraClientOptions.debug`. */
33
+ debug;
34
+ // Lazy-initialised service instances
35
+ _auth = null;
36
+ _db = null;
37
+ _storage = null;
38
+ _realtime = null;
39
+ _functions = null;
40
+ _ai = null;
41
+ _notifications = null;
42
+ _authAdmin = null;
43
+ _disposed = false;
44
+ _persistSession;
45
+ _autoRefresh;
46
+ _detectSessionInUrl;
47
+ /**
48
+ * @param baseUrl URL du projet (`https://<slug>.aurabase.cloud`).
49
+ * @param apiKey Clé API du projet (`aura_anon_…`, `aura_auth_…`, `aura_sk_…`).
50
+ */
51
+ constructor(baseUrl, apiKey, options) {
52
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
53
+ const resolvedOptions = options;
54
+ this.apiKey = apiKey || null;
55
+ this.fetchFn = resolvedOptions?.fetch ?? globalThis.fetch.bind(globalThis);
56
+ const r = resolvedOptions?.retry;
57
+ this.retryConfig = r === false ? { enabled: false, maxRetries: 0 } : r === void 0 || r === true ? { enabled: true, maxRetries: core.DEFAULT_MAX_RETRIES } : { enabled: r.enabled ?? true, maxRetries: r.maxRetries ?? core.DEFAULT_MAX_RETRIES };
58
+ this.requestTimeoutMs = resolvedOptions?.requestTimeoutMs;
59
+ this.onEvent = resolvedOptions?.onEvent;
60
+ this.debug = resolvedOptions?.debug;
61
+ if (!this.apiKey && typeof console !== "undefined") {
62
+ console.warn(
63
+ "[aurabase] No API key provided. Most operations require an API key (apikey header). Only public auth routes (register, login, refresh) will work without one."
64
+ );
65
+ }
66
+ if (typeof console !== "undefined" && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?$/.test(this.baseUrl)) {
67
+ console.warn(
68
+ "[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."
69
+ );
70
+ }
71
+ if (this.apiKey?.startsWith(SERVICE_ROLE_KEY_PREFIX) && isBrowserContext()) {
72
+ const refuse = resolvedOptions?.refuseServiceRoleInBrowser ?? true;
73
+ 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.";
74
+ if (refuse) {
75
+ throw new Error(message);
76
+ } else if (typeof console !== "undefined") {
77
+ console.warn(message);
78
+ }
79
+ }
80
+ if (resolvedOptions?.auth?.storage) {
81
+ this.authStore = resolvedOptions.auth.storage;
82
+ } else if (resolvedOptions?.auth?.persistSession === false) {
83
+ this.authStore = new core.BaseAuthStore();
84
+ } else if (isBrowserContext() && typeof window.localStorage !== "undefined" || typeof globalThis !== "undefined" && (() => {
85
+ const g = globalThis;
86
+ const proc = g?.process;
87
+ const isTest = !!(proc?.env?.VITEST || proc?.env?.NODE_ENV === "test" || proc?.env?.JEST_WORKER_ID);
88
+ return isTest && !!g?.localStorage && typeof g.localStorage.getItem === "function";
89
+ })()) {
90
+ this.authStore = new core.LocalAuthStore(`aura-${core.clientScope(this.baseUrl)}-auth`);
91
+ } else {
92
+ this.authStore = new core.BaseAuthStore();
93
+ }
94
+ this.authStore.setObservabilityHook(this.onEvent, this.debug);
95
+ this._persistSession = resolvedOptions?.auth?.persistSession !== false;
96
+ this._autoRefresh = resolvedOptions?.auth?.autoRefresh ?? true;
97
+ this._detectSessionInUrl = resolvedOptions?.auth?.detectSessionInUrl;
98
+ if (this._autoRefresh && this._persistSession && typeof window !== "undefined") {
99
+ void this.auth;
100
+ }
101
+ }
102
+ /**
103
+ * Démonte le client : arrête le refresh proactif (ticker + visibilité + BroadcastChannel),
104
+ * déconnecte le realtime, vide les listeners d'auth. Idempotent. À appeler en teardown
105
+ * (React Strict Mode / HMR / tests).
106
+ */
107
+ dispose() {
108
+ if (this._disposed) return;
109
+ this._disposed = true;
110
+ this._auth?.dispose();
111
+ this._realtime?.disconnect();
112
+ }
113
+ // -- Lazy service getters ---------------------------------------------------
114
+ get auth() {
115
+ if (!this._auth) {
116
+ this._auth = new auth$1.AuthService(this, {
117
+ autoRefresh: this._autoRefresh,
118
+ persistSession: this._persistSession,
119
+ detectSessionInUrl: this._detectSessionInUrl
120
+ });
121
+ this._auth.onAuthStateChange(({ event, accessToken }) => {
122
+ if (this._realtime) {
123
+ if (accessToken) {
124
+ this._realtime.setAuth(accessToken);
125
+ } else if (event === "SIGNED_OUT") {
126
+ this._realtime.setAuth("");
127
+ }
128
+ }
129
+ });
130
+ }
131
+ return this._auth;
132
+ }
133
+ get authAdmin() {
134
+ if (isBrowserContext()) {
135
+ throw new Error(
136
+ "[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."
137
+ );
138
+ }
139
+ if (!this._authAdmin) this._authAdmin = new auth$1.AuthAdminService(this);
140
+ return this._authAdmin;
141
+ }
142
+ get db() {
143
+ if (!this._db) this._db = new db.DatabaseService(this);
144
+ return this._db;
145
+ }
146
+ get storage() {
147
+ if (!this._storage) this._storage = new storage.StorageService(this);
148
+ return this._storage;
149
+ }
150
+ get realtime() {
151
+ if (!this._realtime) this._realtime = new realtime.RealtimeService(this);
152
+ return this._realtime;
153
+ }
154
+ get functions() {
155
+ if (!this._functions) this._functions = new functions.FunctionsService(this);
156
+ return this._functions;
157
+ }
158
+ get ai() {
159
+ if (!this._ai) this._ai = new ai.AiService(this);
160
+ return this._ai;
161
+ }
162
+ get notifications() {
163
+ if (!this._notifications) this._notifications = new notifications.NotificationsService(this);
164
+ return this._notifications;
165
+ }
166
+ from(table) {
167
+ return this.db.from(table);
168
+ }
169
+ /**
170
+ * Shortcut: call a stored procedure / PostgreSQL function via RPC (Supabase-compatible API).
171
+ * Equivalent to `aura.db.rpc(fn, args, options)`.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * const { data, error } = await aura.rpc('echo_test', { message: 'hello' })
176
+ * ```
177
+ */
178
+ rpc(fn, args, options) {
179
+ return this.db.rpc(fn, args, options);
180
+ }
181
+ /**
182
+ * Shortcut: create a realtime channel with Supabase-compatible API.
183
+ * Equivalent to `aura.realtime.channel(name)`.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * const channel = aura.channel('room-1')
188
+ * .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, cb)
189
+ * .subscribe()
190
+ * ```
191
+ */
192
+ channel(name, options) {
193
+ return this.realtime.channel(name, options);
194
+ }
195
+ /**
196
+ * Shortcut: remove a realtime channel by name or AuraChannel instance.
197
+ * Equivalent to `aura.realtime.removeChannel(channel)`.
198
+ */
199
+ removeChannel(channel) {
200
+ return this.realtime.removeChannel(channel);
201
+ }
202
+ /**
203
+ * Shortcut: remove all realtime channels and unsubscribe.
204
+ * Equivalent to `aura.realtime.removeAllChannels()`.
205
+ */
206
+ removeAllChannels() {
207
+ return this.realtime.removeAllChannels();
208
+ }
209
+ /**
210
+ * Shortcut: list all active realtime channels.
211
+ * Equivalent to `aura.realtime.getChannels()`.
212
+ */
213
+ getChannels() {
214
+ return this.realtime.getChannels();
215
+ }
216
+ };
217
+ var MAX_CHUNK_SIZE = 3600;
218
+ function createServerClient(baseUrl, apiKey, options) {
219
+ const cookieName = `aura-${core.clientScope(baseUrl)}-auth`;
220
+ const store = new core.LocalAuthStore(cookieName);
221
+ const idxRe = new RegExp(`^${cookieName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.(\\d+)$`);
222
+ const incoming = options.cookies.getAll();
223
+ const numbered = incoming.filter((c) => idxRe.test(c.name)).sort((a, b) => Number(a.name.match(idxRe)[1]) - Number(b.name.match(idxRe)[1]));
224
+ const base = incoming.find((c) => c.name === cookieName);
225
+ const decodedValue = numbered.length > 0 ? numbered.map((c) => c.value).join("") : base?.value;
226
+ if (decodedValue) {
227
+ store.loadFromCookie(`${cookieName}=${encodeURIComponent(decodedValue)}`);
228
+ }
229
+ const initialNames = incoming.filter((c) => c.name === cookieName || idxRe.test(c.name)).map((c) => c.name);
230
+ const defaultCookieOpts = {
231
+ path: "/",
232
+ secure: baseUrl.startsWith("https://"),
233
+ sameSite: "Lax",
234
+ httpOnly: true,
235
+ maxAge: 60 * 60 * 24 * 30,
236
+ // 30 days
237
+ ...options.cookieOptions
238
+ };
239
+ store.onChange(() => {
240
+ const toSet = [];
241
+ const used = /* @__PURE__ */ new Set();
242
+ if (store.token) {
243
+ const cookieStr = store.exportToCookie();
244
+ const eqIdx = cookieStr.indexOf("=");
245
+ const rawEncoded = eqIdx >= 0 ? cookieStr.slice(eqIdx + 1).split(";")[0] : "";
246
+ const decoded = rawEncoded ? decodeURIComponent(rawEncoded) : "";
247
+ if (decoded.length <= MAX_CHUNK_SIZE) {
248
+ toSet.push({ name: cookieName, value: decoded, options: defaultCookieOpts });
249
+ used.add(cookieName);
250
+ } else {
251
+ let idx = 0;
252
+ for (let i = 0; i < decoded.length; i += MAX_CHUNK_SIZE, idx++) {
253
+ const name = `${cookieName}.${idx}`;
254
+ toSet.push({
255
+ name,
256
+ value: decoded.slice(i, i + MAX_CHUNK_SIZE),
257
+ options: defaultCookieOpts
258
+ });
259
+ used.add(name);
260
+ }
261
+ }
262
+ }
263
+ const expireOpts = { ...defaultCookieOpts, maxAge: 0 };
264
+ for (const name of initialNames) {
265
+ if (!used.has(name)) toSet.push({ name, value: "", options: expireOpts });
266
+ }
267
+ if (toSet.length > 0) options.cookies.setAll(toSet);
268
+ });
269
+ return new AuraClient(baseUrl, apiKey, {
270
+ auth: { persistSession: false, storage: store }
271
+ });
272
+ }
273
+
274
+ // src/nextjs.ts
275
+ async function loadNextModule(specifier) {
276
+ try {
277
+ const mod = await import(
278
+ /* @vite-ignore */
279
+ specifier
280
+ );
281
+ return mod;
282
+ } catch {
283
+ return null;
284
+ }
285
+ }
286
+ function createAuthMiddleware(options = {}) {
287
+ return async function middleware(request) {
288
+ const nextServer = await loadNextModule("next/server");
289
+ if (!nextServer?.NextResponse) {
290
+ throw new Error(
291
+ "[@aurabase/nextjs] Next.js n'est pas install\xE9. createAuthMiddleware n\xE9cessite next/server."
292
+ );
293
+ }
294
+ const { NextResponse } = nextServer;
295
+ const projectUrl = options.projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? process.env.AURABASE_URL ?? "";
296
+ const anonKey = options.anonKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? process.env.AURABASE_ANON_KEY ?? "";
297
+ if (!projectUrl || !anonKey) {
298
+ console.warn(
299
+ "[@aurabase/nextjs] Variables d'environnement manquantes : NEXT_PUBLIC_AURABASE_URL ou NEXT_PUBLIC_AURABASE_ANON_KEY non d\xE9finies."
300
+ );
301
+ return NextResponse.next({ request });
302
+ }
303
+ const response = NextResponse.next({ request });
304
+ const cookieHandler = {
305
+ getAll: () => request.cookies.getAll(),
306
+ setAll: (cookiesToSet) => {
307
+ cookiesToSet.forEach(({ name, value, options: cookieOpts }) => {
308
+ request.cookies.set(name, value);
309
+ response.cookies.set(name, value, cookieOpts);
310
+ });
311
+ }
312
+ };
313
+ const client = createServerClient(projectUrl, anonKey, {
314
+ cookies: cookieHandler
315
+ });
316
+ const { data: sessionData } = await client.auth.getSession();
317
+ const session = sessionData?.session ?? null;
318
+ const user = session?.user ?? null;
319
+ const pathname = request.nextUrl.pathname;
320
+ const publicPatterns = options.publicRoutes ?? ["/", "/login", "/signup", "/auth/callback"];
321
+ const isPublic = publicPatterns.some((pattern) => {
322
+ if (pattern.endsWith("*")) {
323
+ return pathname.startsWith(pattern.slice(0, -1));
324
+ }
325
+ return pathname === pattern;
326
+ });
327
+ if (!isPublic && !user) {
328
+ const loginUrl = new URL(options.loginUrl ?? "/login", request.url);
329
+ loginUrl.searchParams.set("redirectTo", pathname);
330
+ return NextResponse.redirect(loginUrl);
331
+ }
332
+ if (options.onAuthenticated) {
333
+ const customResponse = await options.onAuthenticated({ user, session, request });
334
+ if (customResponse) return customResponse;
335
+ }
336
+ return response;
337
+ };
338
+ }
339
+ function createClientForServerComponent(cookieStore, projectUrl, apiKey) {
340
+ const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? process.env.AURABASE_URL ?? "";
341
+ const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? process.env.AURABASE_ANON_KEY ?? "";
342
+ return createServerClient(url, key, {
343
+ cookies: {
344
+ getAll: () => cookieStore.getAll(),
345
+ setAll: () => {
346
+ }
347
+ }
348
+ });
349
+ }
350
+ function createClientForServerAction(cookieStore, projectUrl, apiKey) {
351
+ const url = projectUrl ?? process.env.NEXT_PUBLIC_AURABASE_URL ?? process.env.AURABASE_URL ?? "";
352
+ const key = apiKey ?? process.env.NEXT_PUBLIC_AURABASE_ANON_KEY ?? process.env.AURABASE_ANON_KEY ?? "";
353
+ return createServerClient(url, key, {
354
+ cookies: {
355
+ getAll: () => cookieStore.getAll(),
356
+ setAll: (cookiesToSet) => {
357
+ cookiesToSet.forEach(({ name, value, options }) => {
358
+ cookieStore.set?.(name, value, options);
359
+ });
360
+ }
361
+ }
362
+ });
363
+ }
364
+ async function auth(options) {
365
+ const nextHeaders = await loadNextModule("next/headers");
366
+ if (!nextHeaders?.cookies) {
367
+ throw new Error("[@aurabase/nextjs] auth() ne peut \xEAtre appel\xE9 que dans un environnement Next.js App Router.");
368
+ }
369
+ const cookieStore = await nextHeaders.cookies();
370
+ const client = createClientForServerComponent(cookieStore, options?.projectUrl, options?.apiKey);
371
+ const { data } = await client.auth.getSession();
372
+ const session = data?.session ?? null;
373
+ const user = session?.user ?? null;
374
+ return {
375
+ userId: user?.id ?? null,
376
+ user,
377
+ session
378
+ };
379
+ }
380
+ async function currentUser(options) {
381
+ const { user } = await auth(options);
382
+ return user;
383
+ }
384
+
385
+ exports.auth = auth;
386
+ exports.createAuthMiddleware = createAuthMiddleware;
387
+ exports.createClientForServerAction = createClientForServerAction;
388
+ exports.createClientForServerComponent = createClientForServerComponent;
389
+ exports.currentUser = currentUser;