aurabase-js 0.1.0 → 0.2.1
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 +70 -2
- package/dist/cli.js +144 -0
- package/dist/index.js +116 -75
- package/dist/index.mjs +111 -81
- package/package.json +9 -5
- package/src/AuraBaseClient.ts +6 -16
- package/src/QueryBuilder.ts +122 -161
- package/src/cli.ts +149 -0
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
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;
|
|
5
10
|
this.url = url;
|
|
6
11
|
this.anonKey = anonKey;
|
|
7
12
|
this.accessToken = accessToken;
|
|
@@ -9,101 +14,120 @@ var QueryBuilder = class {
|
|
|
9
14
|
this.queryParams = new URLSearchParams();
|
|
10
15
|
this.headers = { ...headers };
|
|
11
16
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Select columns
|
|
14
|
-
* @example
|
|
15
|
-
* .select('id, name, email')
|
|
16
|
-
* .select('*')
|
|
17
|
-
*/
|
|
18
17
|
select(columns = "*") {
|
|
19
|
-
this.queryParams.set("select", columns);
|
|
18
|
+
if (columns !== "*") this.queryParams.set("select", columns.replace(/\s/g, ""));
|
|
20
19
|
return this;
|
|
21
20
|
}
|
|
22
|
-
/**
|
|
23
|
-
* Filter by column equality
|
|
24
|
-
* @example
|
|
25
|
-
* .eq('id', 1)
|
|
26
|
-
* .eq('status', 'active')
|
|
27
|
-
*/
|
|
28
21
|
eq(column, value) {
|
|
29
|
-
|
|
22
|
+
if (column === "id") this._idValue = value;
|
|
23
|
+
this.queryParams.append("eq", `${column}:${value}`);
|
|
30
24
|
return this;
|
|
31
25
|
}
|
|
32
26
|
/**
|
|
33
27
|
* Filter by column inequality
|
|
34
28
|
*/
|
|
35
29
|
neq(column, value) {
|
|
36
|
-
this.queryParams.append(
|
|
30
|
+
this.queryParams.append("neq", `${column}:${value}`);
|
|
37
31
|
return this;
|
|
38
32
|
}
|
|
39
33
|
/**
|
|
40
34
|
* Filter by greater than
|
|
41
35
|
*/
|
|
42
36
|
gt(column, value) {
|
|
43
|
-
this.queryParams.append(
|
|
37
|
+
this.queryParams.append("gt", `${column}:${value}`);
|
|
44
38
|
return this;
|
|
45
39
|
}
|
|
46
40
|
/**
|
|
47
41
|
* Filter by greater than or equal
|
|
48
42
|
*/
|
|
49
43
|
gte(column, value) {
|
|
50
|
-
this.queryParams.append(
|
|
44
|
+
this.queryParams.append("gte", `${column}:${value}`);
|
|
51
45
|
return this;
|
|
52
46
|
}
|
|
53
47
|
/**
|
|
54
48
|
* Filter by less than
|
|
55
49
|
*/
|
|
56
50
|
lt(column, value) {
|
|
57
|
-
this.queryParams.append(
|
|
51
|
+
this.queryParams.append("lt", `${column}:${value}`);
|
|
58
52
|
return this;
|
|
59
53
|
}
|
|
60
54
|
/**
|
|
61
55
|
* Filter by less than or equal
|
|
62
56
|
*/
|
|
63
57
|
lte(column, value) {
|
|
64
|
-
this.queryParams.append(
|
|
58
|
+
this.queryParams.append("lte", `${column}:${value}`);
|
|
65
59
|
return this;
|
|
66
60
|
}
|
|
67
61
|
/**
|
|
68
62
|
* Filter by like pattern
|
|
69
63
|
*/
|
|
70
64
|
like(column, pattern) {
|
|
71
|
-
this.queryParams.append(
|
|
65
|
+
this.queryParams.append("like", `${column}:${pattern}`);
|
|
72
66
|
return this;
|
|
73
67
|
}
|
|
74
68
|
/**
|
|
75
69
|
* Filter by case-insensitive like pattern
|
|
76
70
|
*/
|
|
77
71
|
ilike(column, pattern) {
|
|
78
|
-
this.queryParams.append(
|
|
72
|
+
this.queryParams.append("ilike", `${column}:${pattern}`);
|
|
79
73
|
return this;
|
|
80
74
|
}
|
|
81
75
|
/**
|
|
82
76
|
* Filter by array contains
|
|
83
77
|
*/
|
|
84
78
|
contains(column, value) {
|
|
85
|
-
this.queryParams.append(
|
|
79
|
+
this.queryParams.append("contains", `${column}:${JSON.stringify(value)}`);
|
|
86
80
|
return this;
|
|
87
81
|
}
|
|
88
82
|
/**
|
|
89
83
|
* Filter by value in array
|
|
90
84
|
*/
|
|
91
85
|
in(column, values) {
|
|
92
|
-
this.queryParams.append(
|
|
86
|
+
this.queryParams.append("in", `${column}:${values.join(",")}`);
|
|
93
87
|
return this;
|
|
94
88
|
}
|
|
95
89
|
/**
|
|
96
90
|
* Filter for null values
|
|
97
91
|
*/
|
|
98
92
|
isNull(column) {
|
|
99
|
-
this.queryParams.append(
|
|
93
|
+
this.queryParams.append("is_null", `${column}:true`);
|
|
100
94
|
return this;
|
|
101
95
|
}
|
|
102
96
|
/**
|
|
103
97
|
* Filter for non-null values
|
|
104
98
|
*/
|
|
105
99
|
isNotNull(column) {
|
|
106
|
-
this.queryParams.append(
|
|
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)}`);
|
|
107
131
|
return this;
|
|
108
132
|
}
|
|
109
133
|
/**
|
|
@@ -118,7 +142,8 @@ var QueryBuilder = class {
|
|
|
118
142
|
if (nullsFirst !== void 0) {
|
|
119
143
|
orderStr += nullsFirst ? ".nullsfirst" : ".nullslast";
|
|
120
144
|
}
|
|
121
|
-
this.queryParams.
|
|
145
|
+
const existing = this.queryParams.get("order");
|
|
146
|
+
this.queryParams.set("order", existing ? `${existing},${orderStr}` : orderStr);
|
|
122
147
|
return this;
|
|
123
148
|
}
|
|
124
149
|
/**
|
|
@@ -166,28 +191,36 @@ var QueryBuilder = class {
|
|
|
166
191
|
...this.headers
|
|
167
192
|
};
|
|
168
193
|
}
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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";
|
|
179
212
|
}
|
|
180
213
|
try {
|
|
181
214
|
const response = await fetch(fullUrl, options);
|
|
215
|
+
const text = await response.text();
|
|
182
216
|
let data = null;
|
|
183
217
|
let error = null;
|
|
184
|
-
const text = await response.text();
|
|
185
218
|
if (text) {
|
|
186
219
|
try {
|
|
187
220
|
const parsed = JSON.parse(text);
|
|
188
221
|
if (!response.ok) {
|
|
189
222
|
error = {
|
|
190
|
-
message: parsed.message || parsed.error || `HTTP ${response.status}`,
|
|
223
|
+
message: parsed.message || parsed.error || parsed.detail || `HTTP ${response.status}`,
|
|
191
224
|
code: parsed.code,
|
|
192
225
|
details: parsed.details
|
|
193
226
|
};
|
|
@@ -195,69 +228,49 @@ var QueryBuilder = class {
|
|
|
195
228
|
data = this.isSingle && Array.isArray(parsed) ? parsed[0] ?? null : parsed;
|
|
196
229
|
}
|
|
197
230
|
} catch {
|
|
198
|
-
if (!response.ok) {
|
|
199
|
-
error = {
|
|
200
|
-
message: text || `HTTP ${response.status}`
|
|
201
|
-
};
|
|
202
|
-
}
|
|
231
|
+
if (!response.ok) error = { message: text || `HTTP ${response.status}` };
|
|
203
232
|
}
|
|
204
233
|
}
|
|
205
|
-
return {
|
|
206
|
-
data,
|
|
207
|
-
error,
|
|
208
|
-
status: response.status,
|
|
209
|
-
statusText: response.statusText
|
|
210
|
-
};
|
|
234
|
+
return { data, error, status: response.status, statusText: response.statusText };
|
|
211
235
|
} catch (err) {
|
|
212
236
|
return {
|
|
213
237
|
data: null,
|
|
214
|
-
error: {
|
|
215
|
-
message: err instanceof Error ? err.message : "Network error"
|
|
216
|
-
},
|
|
238
|
+
error: { message: err instanceof Error ? err.message : "Network error" },
|
|
217
239
|
status: 0,
|
|
218
240
|
statusText: "Network Error"
|
|
219
241
|
};
|
|
220
242
|
}
|
|
221
243
|
}
|
|
222
|
-
/**
|
|
223
|
-
* Execute SELECT query
|
|
224
|
-
*/
|
|
225
244
|
async then(resolve, reject) {
|
|
226
245
|
try {
|
|
227
|
-
const result = await this.
|
|
246
|
+
const result = await this.execute();
|
|
228
247
|
await resolve(result);
|
|
229
248
|
} catch (err) {
|
|
230
|
-
if (reject)
|
|
231
|
-
await reject(err);
|
|
232
|
-
}
|
|
249
|
+
if (reject) await reject(err);
|
|
233
250
|
}
|
|
234
251
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
*/
|
|
238
|
-
async insert(row) {
|
|
252
|
+
insert(row) {
|
|
253
|
+
this._method = "POST";
|
|
239
254
|
const rows = Array.isArray(row) ? row : [row];
|
|
240
|
-
|
|
255
|
+
this._body = rows.length === 1 ? rows[0] : rows;
|
|
256
|
+
return this;
|
|
241
257
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return this.request("PATCH", data);
|
|
258
|
+
update(data) {
|
|
259
|
+
this._method = "PATCH";
|
|
260
|
+
this._body = data;
|
|
261
|
+
return this;
|
|
247
262
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
263
|
+
upsert(row, options = {}) {
|
|
264
|
+
this._method = "POST";
|
|
265
|
+
this._isUpsert = true;
|
|
266
|
+
this._onConflict = options.onConflict;
|
|
252
267
|
const rows = Array.isArray(row) ? row : [row];
|
|
253
|
-
this.
|
|
254
|
-
return this
|
|
268
|
+
this._body = rows.length === 1 ? rows[0] : rows;
|
|
269
|
+
return this;
|
|
255
270
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
async delete() {
|
|
260
|
-
return this.request("DELETE");
|
|
271
|
+
delete() {
|
|
272
|
+
this._method = "DELETE";
|
|
273
|
+
return this;
|
|
261
274
|
}
|
|
262
275
|
};
|
|
263
276
|
|
|
@@ -557,7 +570,7 @@ var AuraBaseClient = class {
|
|
|
557
570
|
async rpc(functionName, params) {
|
|
558
571
|
const token = this.accessToken || this.anonKey;
|
|
559
572
|
try {
|
|
560
|
-
const response = await fetch(`${this.url}/
|
|
573
|
+
const response = await fetch(`${this.url}/api/${functionName}/`, {
|
|
561
574
|
method: "POST",
|
|
562
575
|
headers: {
|
|
563
576
|
"Content-Type": "application/json",
|
|
@@ -731,6 +744,23 @@ var StorageBucket = class {
|
|
|
731
744
|
|
|
732
745
|
// src/index.ts
|
|
733
746
|
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
|
+
}
|
|
734
764
|
return new AuraBaseClient(options);
|
|
735
765
|
}
|
|
736
766
|
var index_default = createClient;
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aurabase-js",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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
|
+
"bin": {
|
|
9
|
+
"aurabase-js": "./dist/cli.js"
|
|
10
|
+
},
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"types": "./dist/index.d.ts",
|
|
@@ -13,16 +16,17 @@
|
|
|
13
16
|
}
|
|
14
17
|
},
|
|
15
18
|
"scripts": {
|
|
16
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
17
|
-
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
18
|
-
"prepublishOnly": "
|
|
19
|
+
"build": "tsup src/index.ts --format cjs,esm --dts && tsup src/cli.ts --format cjs --no-dts",
|
|
20
|
+
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
21
|
+
"prepublishOnly": "echo 'skipping build - dist already compiled'"
|
|
19
22
|
},
|
|
20
23
|
"keywords": [
|
|
21
24
|
"aurabase",
|
|
22
25
|
"database",
|
|
23
26
|
"rest",
|
|
24
27
|
"client",
|
|
25
|
-
"supabase-like"
|
|
28
|
+
"supabase-like",
|
|
29
|
+
"cli"
|
|
26
30
|
],
|
|
27
31
|
"author": "",
|
|
28
32
|
"license": "MIT",
|
package/src/AuraBaseClient.ts
CHANGED
|
@@ -46,18 +46,16 @@ export class AuraBaseClient {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* const { data, error } = await client.rpc('my_function', { arg1: 'value' })
|
|
49
|
+
* Call a serverless function
|
|
50
|
+
* POST /api/{functionName}/
|
|
52
51
|
*/
|
|
53
52
|
async rpc<T = unknown>(
|
|
54
53
|
functionName: string,
|
|
55
54
|
params?: Record<string, unknown>
|
|
56
55
|
): Promise<{ data: T | null; error: { message: string } | null }> {
|
|
57
56
|
const token = this.accessToken || this.anonKey;
|
|
58
|
-
|
|
59
57
|
try {
|
|
60
|
-
const response = await fetch(`${this.url}/
|
|
58
|
+
const response = await fetch(`${this.url}/api/${functionName}/`, {
|
|
61
59
|
method: 'POST',
|
|
62
60
|
headers: {
|
|
63
61
|
'Content-Type': 'application/json',
|
|
@@ -67,32 +65,24 @@ export class AuraBaseClient {
|
|
|
67
65
|
},
|
|
68
66
|
body: JSON.stringify(params || {}),
|
|
69
67
|
});
|
|
70
|
-
|
|
71
68
|
const text = await response.text();
|
|
72
69
|
let data: T | null = null;
|
|
73
70
|
let error: { message: string } | null = null;
|
|
74
|
-
|
|
75
71
|
if (text) {
|
|
76
72
|
try {
|
|
77
73
|
const parsed = JSON.parse(text);
|
|
78
74
|
if (!response.ok) {
|
|
79
|
-
error = { message: parsed.message || parsed.error || `HTTP ${response.status}` };
|
|
75
|
+
error = { message: parsed.message || parsed.error || parsed.detail || `HTTP ${response.status}` };
|
|
80
76
|
} else {
|
|
81
77
|
data = parsed;
|
|
82
78
|
}
|
|
83
79
|
} catch {
|
|
84
|
-
if (!response.ok) {
|
|
85
|
-
error = { message: text || `HTTP ${response.status}` };
|
|
86
|
-
}
|
|
80
|
+
if (!response.ok) error = { message: text || `HTTP ${response.status}` };
|
|
87
81
|
}
|
|
88
82
|
}
|
|
89
|
-
|
|
90
83
|
return { data, error };
|
|
91
84
|
} catch (err) {
|
|
92
|
-
return {
|
|
93
|
-
data: null,
|
|
94
|
-
error: { message: err instanceof Error ? err.message : 'Network error' },
|
|
95
|
-
};
|
|
85
|
+
return { data: null, error: { message: err instanceof Error ? err.message : 'Network error' } };
|
|
96
86
|
}
|
|
97
87
|
}
|
|
98
88
|
|