aurabase-js 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2,11 +2,6 @@
2
2
  var QueryBuilder = class {
3
3
  constructor(url, anonKey, accessToken, tableName, headers = {}) {
4
4
  this.isSingle = false;
5
- this._method = "GET";
6
- this._body = void 0;
7
- this._isUpsert = false;
8
- this._onConflict = void 0;
9
- this._idValue = void 0;
10
5
  this.url = url;
11
6
  this.anonKey = anonKey;
12
7
  this.accessToken = accessToken;
@@ -14,120 +9,101 @@ var QueryBuilder = class {
14
9
  this.queryParams = new URLSearchParams();
15
10
  this.headers = { ...headers };
16
11
  }
12
+ /**
13
+ * Select columns
14
+ * @example
15
+ * .select('id, name, email')
16
+ * .select('*')
17
+ */
17
18
  select(columns = "*") {
18
- if (columns !== "*") this.queryParams.set("select", columns.replace(/\s/g, ""));
19
+ this.queryParams.set("select", columns);
19
20
  return this;
20
21
  }
22
+ /**
23
+ * Filter by column equality
24
+ * @example
25
+ * .eq('id', 1)
26
+ * .eq('status', 'active')
27
+ */
21
28
  eq(column, value) {
22
- if (column === "id") this._idValue = value;
23
- this.queryParams.append("eq", `${column}:${value}`);
29
+ this.queryParams.append(column, `eq.${value}`);
24
30
  return this;
25
31
  }
26
32
  /**
27
33
  * Filter by column inequality
28
34
  */
29
35
  neq(column, value) {
30
- this.queryParams.append("neq", `${column}:${value}`);
36
+ this.queryParams.append(column, `neq.${value}`);
31
37
  return this;
32
38
  }
33
39
  /**
34
40
  * Filter by greater than
35
41
  */
36
42
  gt(column, value) {
37
- this.queryParams.append("gt", `${column}:${value}`);
43
+ this.queryParams.append(column, `gt.${value}`);
38
44
  return this;
39
45
  }
40
46
  /**
41
47
  * Filter by greater than or equal
42
48
  */
43
49
  gte(column, value) {
44
- this.queryParams.append("gte", `${column}:${value}`);
50
+ this.queryParams.append(column, `gte.${value}`);
45
51
  return this;
46
52
  }
47
53
  /**
48
54
  * Filter by less than
49
55
  */
50
56
  lt(column, value) {
51
- this.queryParams.append("lt", `${column}:${value}`);
57
+ this.queryParams.append(column, `lt.${value}`);
52
58
  return this;
53
59
  }
54
60
  /**
55
61
  * Filter by less than or equal
56
62
  */
57
63
  lte(column, value) {
58
- this.queryParams.append("lte", `${column}:${value}`);
64
+ this.queryParams.append(column, `lte.${value}`);
59
65
  return this;
60
66
  }
61
67
  /**
62
68
  * Filter by like pattern
63
69
  */
64
70
  like(column, pattern) {
65
- this.queryParams.append("like", `${column}:${pattern}`);
71
+ this.queryParams.append(column, `like.${pattern}`);
66
72
  return this;
67
73
  }
68
74
  /**
69
75
  * Filter by case-insensitive like pattern
70
76
  */
71
77
  ilike(column, pattern) {
72
- this.queryParams.append("ilike", `${column}:${pattern}`);
78
+ this.queryParams.append(column, `ilike.${pattern}`);
73
79
  return this;
74
80
  }
75
81
  /**
76
82
  * Filter by array contains
77
83
  */
78
84
  contains(column, value) {
79
- this.queryParams.append("contains", `${column}:${JSON.stringify(value)}`);
85
+ this.queryParams.append(column, `cs.{${value.join(",")}}`);
80
86
  return this;
81
87
  }
82
88
  /**
83
89
  * Filter by value in array
84
90
  */
85
91
  in(column, values) {
86
- this.queryParams.append("in", `${column}:${values.join(",")}`);
92
+ this.queryParams.append(column, `in.(${values.join(",")})`);
87
93
  return this;
88
94
  }
89
95
  /**
90
96
  * Filter for null values
91
97
  */
92
98
  isNull(column) {
93
- this.queryParams.append("is_null", `${column}:true`);
99
+ this.queryParams.append(column, "is.null");
94
100
  return this;
95
101
  }
96
102
  /**
97
103
  * Filter for non-null values
98
104
  */
99
105
  isNotNull(column) {
100
- this.queryParams.append("is_null", `${column}:false`);
101
- return this;
102
- }
103
- /**
104
- * Full-text search across all columns
105
- */
106
- search(query) {
107
- this.queryParams.set("search", query);
108
- return this;
109
- }
110
- /**
111
- * Negate a filter
112
- * @example .not('eq', 'category', 'Electronics')
113
- */
114
- not(operator, column, value) {
115
- this.queryParams.append("not", `${operator}:${column}:${value}`);
116
- return this;
117
- }
118
- /**
119
- * OR conditions
120
- * @example .or('category.eq.Electronics,price.lt.100000')
121
- */
122
- or(conditions) {
123
- this.queryParams.set("or", conditions);
124
- return this;
125
- }
126
- /**
127
- * Filter by array contained by
128
- */
129
- containedBy(column, value) {
130
- this.queryParams.append("contained_by", `${column}:${JSON.stringify(value)}`);
106
+ this.queryParams.append(column, "is.not.null");
131
107
  return this;
132
108
  }
133
109
  /**
@@ -142,8 +118,7 @@ var QueryBuilder = class {
142
118
  if (nullsFirst !== void 0) {
143
119
  orderStr += nullsFirst ? ".nullsfirst" : ".nullslast";
144
120
  }
145
- const existing = this.queryParams.get("order");
146
- this.queryParams.set("order", existing ? `${existing},${orderStr}` : orderStr);
121
+ this.queryParams.append("order", orderStr);
147
122
  return this;
148
123
  }
149
124
  /**
@@ -191,36 +166,28 @@ var QueryBuilder = class {
191
166
  ...this.headers
192
167
  };
193
168
  }
194
- buildUrl() {
195
- const qs = this.queryParams.toString();
196
- if (this._isUpsert) {
197
- const conflict = this._onConflict ? `?on_conflict=${this._onConflict}` : "";
198
- return `${this.url}/api/${this.tableName}/upsert${conflict}`;
199
- }
200
- if ((this._method === "PATCH" || this._method === "DELETE") && this._idValue !== void 0) {
201
- return `${this.url}/api/${this.tableName}/${this._idValue}/`;
202
- }
203
- return `${this.url}/api/${this.tableName}/${qs ? `?${qs}` : ""}`;
204
- }
205
- async execute() {
206
- const fullUrl = this.buildUrl();
207
- const reqHeaders = this.getHeaders();
208
- const options = { method: this._method, headers: reqHeaders };
209
- if (this._body !== void 0 && this._method !== "GET") {
210
- options.body = JSON.stringify(this._body);
211
- reqHeaders["Prefer"] = "return=representation";
169
+ async request(method, body) {
170
+ const queryString = this.queryParams.toString();
171
+ const fullUrl = `${this.url}/rest/v1/${this.tableName}${queryString ? `?${queryString}` : ""}`;
172
+ const options = {
173
+ method,
174
+ headers: this.getHeaders()
175
+ };
176
+ if (body && method !== "GET") {
177
+ options.body = JSON.stringify(body);
178
+ options.headers["Prefer"] = "return=representation";
212
179
  }
213
180
  try {
214
181
  const response = await fetch(fullUrl, options);
215
- const text = await response.text();
216
182
  let data = null;
217
183
  let error = null;
184
+ const text = await response.text();
218
185
  if (text) {
219
186
  try {
220
187
  const parsed = JSON.parse(text);
221
188
  if (!response.ok) {
222
189
  error = {
223
- message: parsed.message || parsed.error || parsed.detail || `HTTP ${response.status}`,
190
+ message: parsed.message || parsed.error || `HTTP ${response.status}`,
224
191
  code: parsed.code,
225
192
  details: parsed.details
226
193
  };
@@ -228,49 +195,69 @@ var QueryBuilder = class {
228
195
  data = this.isSingle && Array.isArray(parsed) ? parsed[0] ?? null : parsed;
229
196
  }
230
197
  } catch {
231
- if (!response.ok) error = { message: text || `HTTP ${response.status}` };
198
+ if (!response.ok) {
199
+ error = {
200
+ message: text || `HTTP ${response.status}`
201
+ };
202
+ }
232
203
  }
233
204
  }
234
- return { data, error, status: response.status, statusText: response.statusText };
205
+ return {
206
+ data,
207
+ error,
208
+ status: response.status,
209
+ statusText: response.statusText
210
+ };
235
211
  } catch (err) {
236
212
  return {
237
213
  data: null,
238
- error: { message: err instanceof Error ? err.message : "Network error" },
214
+ error: {
215
+ message: err instanceof Error ? err.message : "Network error"
216
+ },
239
217
  status: 0,
240
218
  statusText: "Network Error"
241
219
  };
242
220
  }
243
221
  }
222
+ /**
223
+ * Execute SELECT query
224
+ */
244
225
  async then(resolve, reject) {
245
226
  try {
246
- const result = await this.execute();
227
+ const result = await this.request("GET");
247
228
  await resolve(result);
248
229
  } catch (err) {
249
- if (reject) await reject(err);
230
+ if (reject) {
231
+ await reject(err);
232
+ }
250
233
  }
251
234
  }
252
- insert(row) {
253
- this._method = "POST";
235
+ /**
236
+ * Insert row(s)
237
+ */
238
+ async insert(row) {
254
239
  const rows = Array.isArray(row) ? row : [row];
255
- this._body = rows.length === 1 ? rows[0] : rows;
256
- return this;
240
+ return this.request("POST", rows.length === 1 ? rows[0] : rows);
257
241
  }
258
- update(data) {
259
- this._method = "PATCH";
260
- this._body = data;
261
- return this;
242
+ /**
243
+ * Update row(s)
244
+ */
245
+ async update(data) {
246
+ return this.request("PATCH", data);
262
247
  }
263
- upsert(row, options = {}) {
264
- this._method = "POST";
265
- this._isUpsert = true;
266
- this._onConflict = options.onConflict;
248
+ /**
249
+ * Upsert row(s)
250
+ */
251
+ async upsert(row) {
267
252
  const rows = Array.isArray(row) ? row : [row];
268
- this._body = rows.length === 1 ? rows[0] : rows;
269
- return this;
253
+ this.headers["Prefer"] = "resolution=merge-duplicates,return=representation";
254
+ return this.request("POST", rows.length === 1 ? rows[0] : rows);
270
255
  }
271
- delete() {
272
- this._method = "DELETE";
273
- return this;
256
+ /**
257
+ * Delete row(s)
258
+ */
259
+ async delete() {
260
+ return this.request("DELETE");
274
261
  }
275
262
  };
276
263
 
@@ -570,7 +557,7 @@ var AuraBaseClient = class {
570
557
  async rpc(functionName, params) {
571
558
  const token = this.accessToken || this.anonKey;
572
559
  try {
573
- const response = await fetch(`${this.url}/api/${functionName}/`, {
560
+ const response = await fetch(`${this.url}/rpc/v1/${functionName}`, {
574
561
  method: "POST",
575
562
  headers: {
576
563
  "Content-Type": "application/json",
@@ -744,23 +731,6 @@ var StorageBucket = class {
744
731
 
745
732
  // src/index.ts
746
733
  function createClient(options) {
747
- if (!options.url) {
748
- console.warn(
749
- "[aurabase-js] NEXT_PUBLIC_AURABASE_URL이 설정되지 않았습니다.\n" +
750
- ".env.local 파일에 다음 항목을 추가하세요:\n\n" +
751
- " NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net\n" +
752
- " NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key\n" +
753
- " NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key\n"
754
- );
755
- }
756
- if (!options.anonKey) {
757
- console.warn(
758
- "[aurabase-js] anonKey가 설정되지 않았습니다.\n" +
759
- ".env.local 파일에 다음 항목을 추가하세요:\n\n" +
760
- " NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key (클라이언트용)\n" +
761
- " NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key (서버/admin용)\n"
762
- );
763
- }
764
734
  return new AuraBaseClient(options);
765
735
  }
766
736
  var index_default = createClient;
@@ -0,0 +1,9 @@
1
+ import { createClient } from 'aurabase-js';
2
+
3
+ const AURABASE_URL = process.env.NEXT_PUBLIC_AURABASE_URL || 'https://your-project.cloudfront.net';
4
+ const AURABASE_ANON_KEY = process.env.NEXT_PUBLIC_AURABASE_ANON_KEY || '';
5
+
6
+ export const aurabase = createClient({
7
+ url: AURABASE_URL,
8
+ anonKey: AURABASE_ANON_KEY,
9
+ });
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "aurabase-js",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "AuraBase client library - Supabase-style SDK for AuraBase",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
9
- "aurabase-js": "./dist/cli.js"
9
+ "aurabase-js": "dist/cli.js"
10
10
  },
11
11
  "exports": {
12
12
  ".": {
@@ -16,17 +16,17 @@
16
16
  }
17
17
  },
18
18
  "scripts": {
19
- "build": "tsup src/index.ts --format cjs,esm --dts && tsup src/cli.ts --format cjs --no-dts",
19
+ "build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
20
20
  "dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
21
- "prepublishOnly": "echo 'skipping build - dist already compiled'"
21
+ "prepublishOnly": "npm run build",
22
+ "postinstall": "node dist/cli.js init"
22
23
  },
23
24
  "keywords": [
24
25
  "aurabase",
25
26
  "database",
26
27
  "rest",
27
28
  "client",
28
- "supabase-like",
29
- "cli"
29
+ "supabase-like"
30
30
  ],
31
31
  "author": "",
32
32
  "license": "MIT",
@@ -46,16 +46,18 @@ export class AuraBaseClient {
46
46
  }
47
47
 
48
48
  /**
49
- * Call a serverless function
50
- * POST /api/{functionName}/
49
+ * Execute raw SQL (RPC function call)
50
+ * @example
51
+ * const { data, error } = await client.rpc('my_function', { arg1: 'value' })
51
52
  */
52
53
  async rpc<T = unknown>(
53
54
  functionName: string,
54
55
  params?: Record<string, unknown>
55
56
  ): Promise<{ data: T | null; error: { message: string } | null }> {
56
57
  const token = this.accessToken || this.anonKey;
58
+
57
59
  try {
58
- const response = await fetch(`${this.url}/api/${functionName}/`, {
60
+ const response = await fetch(`${this.url}/rpc/v1/${functionName}`, {
59
61
  method: 'POST',
60
62
  headers: {
61
63
  'Content-Type': 'application/json',
@@ -65,24 +67,32 @@ export class AuraBaseClient {
65
67
  },
66
68
  body: JSON.stringify(params || {}),
67
69
  });
70
+
68
71
  const text = await response.text();
69
72
  let data: T | null = null;
70
73
  let error: { message: string } | null = null;
74
+
71
75
  if (text) {
72
76
  try {
73
77
  const parsed = JSON.parse(text);
74
78
  if (!response.ok) {
75
- error = { message: parsed.message || parsed.error || parsed.detail || `HTTP ${response.status}` };
79
+ error = { message: parsed.message || parsed.error || `HTTP ${response.status}` };
76
80
  } else {
77
81
  data = parsed;
78
82
  }
79
83
  } catch {
80
- if (!response.ok) error = { message: text || `HTTP ${response.status}` };
84
+ if (!response.ok) {
85
+ error = { message: text || `HTTP ${response.status}` };
86
+ }
81
87
  }
82
88
  }
89
+
83
90
  return { data, error };
84
91
  } catch (err) {
85
- return { data: null, error: { message: err instanceof Error ? err.message : 'Network error' } };
92
+ return {
93
+ data: null,
94
+ error: { message: err instanceof Error ? err.message : 'Network error' },
95
+ };
86
96
  }
87
97
  }
88
98