aurabase-js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,769 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuraBaseClient: () => AuraBaseClient,
24
+ createClient: () => createClient,
25
+ default: () => index_default
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/QueryBuilder.ts
30
+ var QueryBuilder = class {
31
+ constructor(url, anonKey, accessToken, tableName, headers = {}) {
32
+ this.isSingle = false;
33
+ this.url = url;
34
+ this.anonKey = anonKey;
35
+ this.accessToken = accessToken;
36
+ this.tableName = tableName;
37
+ this.queryParams = new URLSearchParams();
38
+ this.headers = { ...headers };
39
+ }
40
+ /**
41
+ * Select columns
42
+ * @example
43
+ * .select('id, name, email')
44
+ * .select('*')
45
+ */
46
+ select(columns = "*") {
47
+ this.queryParams.set("select", columns);
48
+ return this;
49
+ }
50
+ /**
51
+ * Filter by column equality
52
+ * @example
53
+ * .eq('id', 1)
54
+ * .eq('status', 'active')
55
+ */
56
+ eq(column, value) {
57
+ this.queryParams.append(column, `eq.${value}`);
58
+ return this;
59
+ }
60
+ /**
61
+ * Filter by column inequality
62
+ */
63
+ neq(column, value) {
64
+ this.queryParams.append(column, `neq.${value}`);
65
+ return this;
66
+ }
67
+ /**
68
+ * Filter by greater than
69
+ */
70
+ gt(column, value) {
71
+ this.queryParams.append(column, `gt.${value}`);
72
+ return this;
73
+ }
74
+ /**
75
+ * Filter by greater than or equal
76
+ */
77
+ gte(column, value) {
78
+ this.queryParams.append(column, `gte.${value}`);
79
+ return this;
80
+ }
81
+ /**
82
+ * Filter by less than
83
+ */
84
+ lt(column, value) {
85
+ this.queryParams.append(column, `lt.${value}`);
86
+ return this;
87
+ }
88
+ /**
89
+ * Filter by less than or equal
90
+ */
91
+ lte(column, value) {
92
+ this.queryParams.append(column, `lte.${value}`);
93
+ return this;
94
+ }
95
+ /**
96
+ * Filter by like pattern
97
+ */
98
+ like(column, pattern) {
99
+ this.queryParams.append(column, `like.${pattern}`);
100
+ return this;
101
+ }
102
+ /**
103
+ * Filter by case-insensitive like pattern
104
+ */
105
+ ilike(column, pattern) {
106
+ this.queryParams.append(column, `ilike.${pattern}`);
107
+ return this;
108
+ }
109
+ /**
110
+ * Filter by array contains
111
+ */
112
+ contains(column, value) {
113
+ this.queryParams.append(column, `cs.{${value.join(",")}}`);
114
+ return this;
115
+ }
116
+ /**
117
+ * Filter by value in array
118
+ */
119
+ in(column, values) {
120
+ this.queryParams.append(column, `in.(${values.join(",")})`);
121
+ return this;
122
+ }
123
+ /**
124
+ * Filter for null values
125
+ */
126
+ isNull(column) {
127
+ this.queryParams.append(column, "is.null");
128
+ return this;
129
+ }
130
+ /**
131
+ * Filter for non-null values
132
+ */
133
+ isNotNull(column) {
134
+ this.queryParams.append(column, "is.not.null");
135
+ return this;
136
+ }
137
+ /**
138
+ * Order results
139
+ * @example
140
+ * .order('created_at', { ascending: false })
141
+ */
142
+ order(column, options = {}) {
143
+ const { ascending = true, nullsFirst } = options;
144
+ let orderStr = column;
145
+ if (!ascending) orderStr += ".desc";
146
+ if (nullsFirst !== void 0) {
147
+ orderStr += nullsFirst ? ".nullsfirst" : ".nullslast";
148
+ }
149
+ this.queryParams.append("order", orderStr);
150
+ return this;
151
+ }
152
+ /**
153
+ * Limit results
154
+ */
155
+ limit(count) {
156
+ this.queryParams.set("limit", String(count));
157
+ return this;
158
+ }
159
+ /**
160
+ * Offset results
161
+ */
162
+ offset(count) {
163
+ this.queryParams.set("offset", String(count));
164
+ return this;
165
+ }
166
+ /**
167
+ * Range of results (offset + limit)
168
+ */
169
+ range(from, to) {
170
+ this.queryParams.set("offset", String(from));
171
+ this.queryParams.set("limit", String(to - from + 1));
172
+ return this;
173
+ }
174
+ /**
175
+ * Return single result
176
+ */
177
+ single() {
178
+ this.isSingle = true;
179
+ return this;
180
+ }
181
+ /**
182
+ * Return single result or null
183
+ */
184
+ maybeSingle() {
185
+ this.isSingle = true;
186
+ return this;
187
+ }
188
+ getHeaders() {
189
+ const token = this.accessToken || this.anonKey;
190
+ return {
191
+ "Content-Type": "application/json",
192
+ "apikey": this.anonKey,
193
+ "Authorization": `Bearer ${token}`,
194
+ ...this.headers
195
+ };
196
+ }
197
+ async request(method, body) {
198
+ const queryString = this.queryParams.toString();
199
+ const fullUrl = `${this.url}/rest/v1/${this.tableName}${queryString ? `?${queryString}` : ""}`;
200
+ const options = {
201
+ method,
202
+ headers: this.getHeaders()
203
+ };
204
+ if (body && method !== "GET") {
205
+ options.body = JSON.stringify(body);
206
+ options.headers["Prefer"] = "return=representation";
207
+ }
208
+ try {
209
+ const response = await fetch(fullUrl, options);
210
+ let data = null;
211
+ let error = null;
212
+ const text = await response.text();
213
+ if (text) {
214
+ try {
215
+ const parsed = JSON.parse(text);
216
+ if (!response.ok) {
217
+ error = {
218
+ message: parsed.message || parsed.error || `HTTP ${response.status}`,
219
+ code: parsed.code,
220
+ details: parsed.details
221
+ };
222
+ } else {
223
+ data = this.isSingle && Array.isArray(parsed) ? parsed[0] ?? null : parsed;
224
+ }
225
+ } catch {
226
+ if (!response.ok) {
227
+ error = {
228
+ message: text || `HTTP ${response.status}`
229
+ };
230
+ }
231
+ }
232
+ }
233
+ return {
234
+ data,
235
+ error,
236
+ status: response.status,
237
+ statusText: response.statusText
238
+ };
239
+ } catch (err) {
240
+ return {
241
+ data: null,
242
+ error: {
243
+ message: err instanceof Error ? err.message : "Network error"
244
+ },
245
+ status: 0,
246
+ statusText: "Network Error"
247
+ };
248
+ }
249
+ }
250
+ /**
251
+ * Execute SELECT query
252
+ */
253
+ async then(resolve, reject) {
254
+ try {
255
+ const result = await this.request("GET");
256
+ await resolve(result);
257
+ } catch (err) {
258
+ if (reject) {
259
+ await reject(err);
260
+ }
261
+ }
262
+ }
263
+ /**
264
+ * Insert row(s)
265
+ */
266
+ async insert(row) {
267
+ const rows = Array.isArray(row) ? row : [row];
268
+ return this.request("POST", rows.length === 1 ? rows[0] : rows);
269
+ }
270
+ /**
271
+ * Update row(s)
272
+ */
273
+ async update(data) {
274
+ return this.request("PATCH", data);
275
+ }
276
+ /**
277
+ * Upsert row(s)
278
+ */
279
+ async upsert(row) {
280
+ const rows = Array.isArray(row) ? row : [row];
281
+ this.headers["Prefer"] = "resolution=merge-duplicates,return=representation";
282
+ return this.request("POST", rows.length === 1 ? rows[0] : rows);
283
+ }
284
+ /**
285
+ * Delete row(s)
286
+ */
287
+ async delete() {
288
+ return this.request("DELETE");
289
+ }
290
+ };
291
+
292
+ // src/Auth.ts
293
+ var AuthClient = class {
294
+ constructor(url, anonKey) {
295
+ this.listeners = /* @__PURE__ */ new Map();
296
+ this.currentSession = null;
297
+ this.storageKey = "aurabase_session";
298
+ this.url = url;
299
+ this.anonKey = anonKey;
300
+ this.loadSession();
301
+ }
302
+ loadSession() {
303
+ if (typeof window === "undefined") return;
304
+ try {
305
+ const stored = localStorage.getItem(this.storageKey);
306
+ if (stored) {
307
+ this.currentSession = JSON.parse(stored);
308
+ }
309
+ } catch {
310
+ }
311
+ }
312
+ saveSession(session) {
313
+ this.currentSession = session;
314
+ if (typeof window === "undefined") return;
315
+ if (session) {
316
+ localStorage.setItem(this.storageKey, JSON.stringify(session));
317
+ } else {
318
+ localStorage.removeItem(this.storageKey);
319
+ }
320
+ }
321
+ getHeaders() {
322
+ return {
323
+ "Content-Type": "application/json",
324
+ "apikey": this.anonKey
325
+ };
326
+ }
327
+ emitEvent(event, session) {
328
+ const listeners = this.listeners.get(event) || [];
329
+ listeners.forEach((listener) => listener(event, session));
330
+ const allListeners = this.listeners.get("*") || [];
331
+ allListeners.forEach((listener) => listener(event, session));
332
+ }
333
+ /**
334
+ * Sign in with email and password
335
+ */
336
+ async signInWithPassword(credentials) {
337
+ try {
338
+ const response = await fetch(`${this.url}/auth/login`, {
339
+ method: "POST",
340
+ headers: this.getHeaders(),
341
+ body: JSON.stringify(credentials)
342
+ });
343
+ const data = await response.json();
344
+ if (!response.ok) {
345
+ const errorMsg = typeof data.detail === "string" ? data.detail : Array.isArray(data.detail) ? data.detail.map((e) => e.msg).join(", ") : data.error || "Login failed";
346
+ return {
347
+ data: null,
348
+ error: { error: errorMsg }
349
+ };
350
+ }
351
+ const session = {
352
+ access_token: data.access_token,
353
+ token_type: "bearer",
354
+ user: data.user
355
+ };
356
+ this.saveSession(session);
357
+ this.emitEvent("SIGNED_IN", session);
358
+ return {
359
+ data: { user: data.user, session },
360
+ error: null
361
+ };
362
+ } catch (err) {
363
+ return {
364
+ data: null,
365
+ error: { error: err instanceof Error ? err.message : "Network error" }
366
+ };
367
+ }
368
+ }
369
+ /**
370
+ * Sign up with email and password
371
+ */
372
+ async signUp(credentials) {
373
+ try {
374
+ const response = await fetch(`${this.url}/auth/register`, {
375
+ method: "POST",
376
+ headers: this.getHeaders(),
377
+ body: JSON.stringify(credentials)
378
+ });
379
+ const data = await response.json();
380
+ if (!response.ok) {
381
+ return {
382
+ data: null,
383
+ error: { error: data.detail || data.error || "Registration failed" }
384
+ };
385
+ }
386
+ return {
387
+ data: { user: data.user || data },
388
+ error: null
389
+ };
390
+ } catch (err) {
391
+ return {
392
+ data: null,
393
+ error: { error: err instanceof Error ? err.message : "Network error" }
394
+ };
395
+ }
396
+ }
397
+ /**
398
+ * Sign out
399
+ */
400
+ async signOut() {
401
+ try {
402
+ const token = this.currentSession?.access_token;
403
+ if (token) {
404
+ await fetch(`${this.url}/auth/logout`, {
405
+ method: "POST",
406
+ headers: {
407
+ ...this.getHeaders(),
408
+ "Authorization": `Bearer ${token}`
409
+ }
410
+ });
411
+ }
412
+ this.saveSession(null);
413
+ this.emitEvent("SIGNED_OUT", null);
414
+ return { error: null };
415
+ } catch (err) {
416
+ return { error: { error: err instanceof Error ? err.message : "Network error" } };
417
+ }
418
+ }
419
+ /**
420
+ * Get current session
421
+ */
422
+ getSession() {
423
+ return { data: { session: this.currentSession } };
424
+ }
425
+ /**
426
+ * Get current user
427
+ */
428
+ async getUser() {
429
+ const token = this.currentSession?.access_token;
430
+ if (!token) {
431
+ return { data: { user: null }, error: null };
432
+ }
433
+ try {
434
+ const response = await fetch(`${this.url}/auth/me`, {
435
+ headers: {
436
+ ...this.getHeaders(),
437
+ "Authorization": `Bearer ${token}`
438
+ }
439
+ });
440
+ if (!response.ok) {
441
+ return {
442
+ data: { user: null },
443
+ error: { error: "Failed to get user" }
444
+ };
445
+ }
446
+ const user = await response.json();
447
+ return { data: { user }, error: null };
448
+ } catch (err) {
449
+ return {
450
+ data: { user: null },
451
+ error: { error: err instanceof Error ? err.message : "Network error" }
452
+ };
453
+ }
454
+ }
455
+ /**
456
+ * Update user
457
+ */
458
+ async updateUser(attributes) {
459
+ const token = this.currentSession?.access_token;
460
+ if (!token) {
461
+ return {
462
+ data: null,
463
+ error: { error: "Not authenticated" }
464
+ };
465
+ }
466
+ try {
467
+ const response = await fetch(`${this.url}/auth/me`, {
468
+ method: "PATCH",
469
+ headers: {
470
+ ...this.getHeaders(),
471
+ "Authorization": `Bearer ${token}`
472
+ },
473
+ body: JSON.stringify(attributes)
474
+ });
475
+ const data = await response.json();
476
+ if (!response.ok) {
477
+ return {
478
+ data: null,
479
+ error: { error: data.detail || data.error || "Update failed" }
480
+ };
481
+ }
482
+ if (this.currentSession) {
483
+ this.currentSession.user = data;
484
+ this.saveSession(this.currentSession);
485
+ }
486
+ this.emitEvent("USER_UPDATED", this.currentSession);
487
+ return { data: { user: data }, error: null };
488
+ } catch (err) {
489
+ return {
490
+ data: null,
491
+ error: { error: err instanceof Error ? err.message : "Network error" }
492
+ };
493
+ }
494
+ }
495
+ /**
496
+ * Request password reset
497
+ */
498
+ async resetPasswordForEmail(email) {
499
+ try {
500
+ const response = await fetch(`${this.url}/auth/find-password`, {
501
+ method: "POST",
502
+ headers: this.getHeaders(),
503
+ body: JSON.stringify({ email })
504
+ });
505
+ const data = await response.json();
506
+ if (!response.ok) {
507
+ return { error: { error: data.detail || data.error || "Request failed" } };
508
+ }
509
+ return { error: null };
510
+ } catch (err) {
511
+ return { error: { error: err instanceof Error ? err.message : "Network error" } };
512
+ }
513
+ }
514
+ /**
515
+ * Subscribe to auth state changes
516
+ */
517
+ onAuthStateChange(callback) {
518
+ const addListener = (event) => {
519
+ if (!this.listeners.has(event)) {
520
+ this.listeners.set(event, []);
521
+ }
522
+ this.listeners.get(event).push(callback);
523
+ };
524
+ addListener("SIGNED_IN");
525
+ addListener("SIGNED_OUT");
526
+ addListener("TOKEN_REFRESHED");
527
+ addListener("USER_UPDATED");
528
+ return {
529
+ data: {
530
+ subscription: {
531
+ unsubscribe: () => {
532
+ this.listeners.forEach((listeners) => {
533
+ const index = listeners.indexOf(callback);
534
+ if (index > -1) {
535
+ listeners.splice(index, 1);
536
+ }
537
+ });
538
+ }
539
+ }
540
+ }
541
+ };
542
+ }
543
+ };
544
+
545
+ // src/AuraBaseClient.ts
546
+ var AuraBaseClient = class {
547
+ constructor(options) {
548
+ this.accessToken = null;
549
+ this.url = options.url;
550
+ this.anonKey = options.anonKey;
551
+ this.customHeaders = options.headers || {};
552
+ this.auth = new AuthClient(this.url, this.anonKey);
553
+ }
554
+ /**
555
+ * Set access token for authenticated requests
556
+ */
557
+ setAccessToken(token) {
558
+ this.accessToken = token;
559
+ }
560
+ /**
561
+ * Get the current access token
562
+ */
563
+ getAccessToken() {
564
+ return this.accessToken;
565
+ }
566
+ /**
567
+ * Query a table
568
+ * @example
569
+ * const { data, error } = await client.from('todos').select('*')
570
+ */
571
+ from(tableName) {
572
+ return new QueryBuilder(
573
+ this.url,
574
+ this.anonKey,
575
+ this.accessToken,
576
+ tableName,
577
+ this.customHeaders
578
+ );
579
+ }
580
+ /**
581
+ * Execute raw SQL (RPC function call)
582
+ * @example
583
+ * const { data, error } = await client.rpc('my_function', { arg1: 'value' })
584
+ */
585
+ async rpc(functionName, params) {
586
+ const token = this.accessToken || this.anonKey;
587
+ try {
588
+ const response = await fetch(`${this.url}/rpc/v1/${functionName}`, {
589
+ method: "POST",
590
+ headers: {
591
+ "Content-Type": "application/json",
592
+ "apikey": this.anonKey,
593
+ "Authorization": `Bearer ${token}`,
594
+ ...this.customHeaders
595
+ },
596
+ body: JSON.stringify(params || {})
597
+ });
598
+ const text = await response.text();
599
+ let data = null;
600
+ let error = null;
601
+ if (text) {
602
+ try {
603
+ const parsed = JSON.parse(text);
604
+ if (!response.ok) {
605
+ error = { message: parsed.message || parsed.error || `HTTP ${response.status}` };
606
+ } else {
607
+ data = parsed;
608
+ }
609
+ } catch {
610
+ if (!response.ok) {
611
+ error = { message: text || `HTTP ${response.status}` };
612
+ }
613
+ }
614
+ }
615
+ return { data, error };
616
+ } catch (err) {
617
+ return {
618
+ data: null,
619
+ error: { message: err instanceof Error ? err.message : "Network error" }
620
+ };
621
+ }
622
+ }
623
+ /**
624
+ * Get storage client (if available)
625
+ */
626
+ get storage() {
627
+ return {
628
+ from: (bucket) => new StorageBucket(this.url, this.anonKey, bucket, this.accessToken)
629
+ };
630
+ }
631
+ };
632
+ var StorageBucket = class {
633
+ constructor(url, anonKey, bucket, accessToken) {
634
+ this.url = url;
635
+ this.anonKey = anonKey;
636
+ this.bucket = bucket;
637
+ this.accessToken = accessToken;
638
+ }
639
+ getHeaders() {
640
+ const token = this.accessToken || this.anonKey;
641
+ return {
642
+ "apikey": this.anonKey,
643
+ "Authorization": `Bearer ${token}`
644
+ };
645
+ }
646
+ /**
647
+ * Upload a file
648
+ */
649
+ async upload(path, file, options) {
650
+ const formData = new FormData();
651
+ formData.append("file", file);
652
+ const headers = this.getHeaders();
653
+ if (options?.contentType) {
654
+ headers["Content-Type"] = options.contentType;
655
+ }
656
+ try {
657
+ const response = await fetch(
658
+ `${this.url}/storage/v1/object/${this.bucket}/${path}`,
659
+ {
660
+ method: "POST",
661
+ headers,
662
+ body: formData
663
+ }
664
+ );
665
+ const data = await response.json();
666
+ if (!response.ok) {
667
+ return {
668
+ data: null,
669
+ error: { message: data.message || data.error || "Upload failed" }
670
+ };
671
+ }
672
+ return { data: { path: data.path || path }, error: null };
673
+ } catch (err) {
674
+ return {
675
+ data: null,
676
+ error: { message: err instanceof Error ? err.message : "Network error" }
677
+ };
678
+ }
679
+ }
680
+ /**
681
+ * Download a file
682
+ */
683
+ async download(path) {
684
+ try {
685
+ const response = await fetch(
686
+ `${this.url}/storage/v1/object/${this.bucket}/${path}`,
687
+ {
688
+ headers: this.getHeaders()
689
+ }
690
+ );
691
+ if (!response.ok) {
692
+ const data = await response.json();
693
+ return {
694
+ data: null,
695
+ error: { message: data.message || data.error || "Download failed" }
696
+ };
697
+ }
698
+ return { data: await response.blob(), error: null };
699
+ } catch (err) {
700
+ return {
701
+ data: null,
702
+ error: { message: err instanceof Error ? err.message : "Network error" }
703
+ };
704
+ }
705
+ }
706
+ /**
707
+ * Get public URL for a file
708
+ */
709
+ getPublicUrl(path) {
710
+ return `${this.url}/storage/v1/object/public/${this.bucket}/${path}`;
711
+ }
712
+ /**
713
+ * Delete a file
714
+ */
715
+ async remove(paths) {
716
+ try {
717
+ const response = await fetch(`${this.url}/storage/v1/object/${this.bucket}`, {
718
+ method: "DELETE",
719
+ headers: {
720
+ ...this.getHeaders(),
721
+ "Content-Type": "application/json"
722
+ },
723
+ body: JSON.stringify({ prefixes: paths })
724
+ });
725
+ if (!response.ok) {
726
+ const data = await response.json();
727
+ return { error: { message: data.message || data.error || "Delete failed" } };
728
+ }
729
+ return { error: null };
730
+ } catch (err) {
731
+ return { error: { message: err instanceof Error ? err.message : "Network error" } };
732
+ }
733
+ }
734
+ /**
735
+ * List files in a bucket
736
+ */
737
+ async list(prefix) {
738
+ try {
739
+ const url = prefix ? `${this.url}/storage/v1/object/list/${this.bucket}?prefix=${prefix}` : `${this.url}/storage/v1/object/list/${this.bucket}`;
740
+ const response = await fetch(url, {
741
+ headers: this.getHeaders()
742
+ });
743
+ const data = await response.json();
744
+ if (!response.ok) {
745
+ return {
746
+ data: null,
747
+ error: { message: data.message || data.error || "List failed" }
748
+ };
749
+ }
750
+ return { data, error: null };
751
+ } catch (err) {
752
+ return {
753
+ data: null,
754
+ error: { message: err instanceof Error ? err.message : "Network error" }
755
+ };
756
+ }
757
+ }
758
+ };
759
+
760
+ // src/index.ts
761
+ function createClient(options) {
762
+ return new AuraBaseClient(options);
763
+ }
764
+ var index_default = createClient;
765
+ // Annotate the CommonJS export names for ESM import in node:
766
+ 0 && (module.exports = {
767
+ AuraBaseClient,
768
+ createClient
769
+ });