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/README.md
CHANGED
|
@@ -12,6 +12,74 @@ yarn add aurabase-js
|
|
|
12
12
|
pnpm add aurabase-js
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
설치 후 아래 명령어 한 번으로 `lib/` 폴더와 환경변수 파일을 자동 생성합니다:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx aurabase-js init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
aurabase-js init
|
|
23
|
+
──────────────────────────────────
|
|
24
|
+
✔ lib/client.ts 생성
|
|
25
|
+
✔ lib/server.ts 생성
|
|
26
|
+
✔ lib/admin.ts 생성
|
|
27
|
+
|
|
28
|
+
📋 환경변수 설정
|
|
29
|
+
──────────────────────────────────
|
|
30
|
+
✔ .env.local 생성 — 아래 값을 채워주세요
|
|
31
|
+
|
|
32
|
+
NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net
|
|
33
|
+
NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key
|
|
34
|
+
NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key
|
|
35
|
+
|
|
36
|
+
→ AuraBase 대시보드 API Keys 메뉴에서 확인하세요.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## ⚙️ 환경변수 설정 (Next.js)
|
|
42
|
+
|
|
43
|
+
설치 후 프로젝트 루트에 `.env.local` 파일을 생성하고 아래 값을 입력하세요.
|
|
44
|
+
|
|
45
|
+
```env
|
|
46
|
+
# AuraBase 프로젝트 URL
|
|
47
|
+
NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net
|
|
48
|
+
|
|
49
|
+
# 일반 사용자용 키 (클라이언트 컴포넌트, RLS 적용)
|
|
50
|
+
NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key
|
|
51
|
+
|
|
52
|
+
# 관리자용 키 (서버 컴포넌트 / API Route 전용, RLS 우회)
|
|
53
|
+
NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> 위 값은 AuraBase 대시보드 → **API Keys** 메뉴에서 확인할 수 있습니다.
|
|
57
|
+
|
|
58
|
+
### `lib/client.ts` — 클라이언트 컴포넌트용
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { createClient } from 'aurabase-js'
|
|
62
|
+
|
|
63
|
+
export const client = createClient({
|
|
64
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL!,
|
|
65
|
+
anonKey: process.env.NEXT_PUBLIC_AURABASE_ANON_KEY!,
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `lib/admin.ts` — 서버 전용 (API Route, Server Component)
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { createClient } from 'aurabase-js'
|
|
73
|
+
|
|
74
|
+
// ⚠️ 절대 클라이언트 컴포넌트에서 사용 금지 — RLS를 우회합니다
|
|
75
|
+
export const admin = createClient({
|
|
76
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL!,
|
|
77
|
+
anonKey: process.env.NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY!,
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
15
83
|
## 사용법
|
|
16
84
|
|
|
17
85
|
### 클라이언트 생성
|
|
@@ -20,8 +88,8 @@ pnpm add aurabase-js
|
|
|
20
88
|
import { createClient } from 'aurabase-js'
|
|
21
89
|
|
|
22
90
|
const aurabase = createClient({
|
|
23
|
-
url:
|
|
24
|
-
anonKey:
|
|
91
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL!,
|
|
92
|
+
anonKey: process.env.NEXT_PUBLIC_AURABASE_ANON_KEY!,
|
|
25
93
|
})
|
|
26
94
|
```
|
|
27
95
|
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const command = args[0];
|
|
9
|
+
|
|
10
|
+
const BOLD = '\x1b[1m';
|
|
11
|
+
const GREEN = '\x1b[32m';
|
|
12
|
+
const YELLOW = '\x1b[33m';
|
|
13
|
+
const CYAN = '\x1b[36m';
|
|
14
|
+
const RESET = '\x1b[0m';
|
|
15
|
+
|
|
16
|
+
function success(msg) { console.log(`${GREEN}✔${RESET} ${msg}`); }
|
|
17
|
+
function warn(msg) { console.log(`${YELLOW}⚠${RESET} ${msg}`); }
|
|
18
|
+
function info(msg) { console.log(`${CYAN}ℹ${RESET} ${msg}`); }
|
|
19
|
+
|
|
20
|
+
// ─── 생성할 파일 내용 ──────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
const CLIENT_TS = `import { createClient } from 'aurabase-js';
|
|
23
|
+
|
|
24
|
+
export const client = createClient({
|
|
25
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL || '',
|
|
26
|
+
anonKey: process.env.NEXT_PUBLIC_AURABASE_ANON_KEY || '',
|
|
27
|
+
});
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const SERVER_TS = `import { createClient } from 'aurabase-js';
|
|
31
|
+
import { cookies } from 'next/headers';
|
|
32
|
+
|
|
33
|
+
export async function server() {
|
|
34
|
+
const cookieStore = await cookies();
|
|
35
|
+
const accessToken = cookieStore.get('access_token')?.value;
|
|
36
|
+
|
|
37
|
+
const client = createClient({
|
|
38
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL || '',
|
|
39
|
+
anonKey: process.env.NEXT_PUBLIC_AURABASE_ANON_KEY || '',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (accessToken) {
|
|
43
|
+
client.setAccessToken(accessToken);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return client;
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const ADMIN_TS = `import { createClient } from 'aurabase-js';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Admin client with service_role key
|
|
54
|
+
* ⚠️ ONLY use on server-side (API routes, server components)
|
|
55
|
+
* ⚠️ Bypasses all RLS policies - use with caution!
|
|
56
|
+
*/
|
|
57
|
+
export const admin = createClient({
|
|
58
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL || '',
|
|
59
|
+
anonKey: process.env.NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY || '',
|
|
60
|
+
});
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const ENV_EXAMPLE = `# AuraBase
|
|
64
|
+
NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net
|
|
65
|
+
NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key
|
|
66
|
+
NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
// ─── init ─────────────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
function init() {
|
|
72
|
+
const cwd = process.cwd();
|
|
73
|
+
const libDir = path.join(cwd, 'lib');
|
|
74
|
+
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log(`${BOLD}aurabase-js init${RESET}`);
|
|
77
|
+
console.log('──────────────────────────────────');
|
|
78
|
+
|
|
79
|
+
if (!fs.existsSync(libDir)) {
|
|
80
|
+
fs.mkdirSync(libDir, { recursive: true });
|
|
81
|
+
success('lib/ 폴더 생성');
|
|
82
|
+
} else {
|
|
83
|
+
info('lib/ 폴더가 이미 존재합니다');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const files = [
|
|
87
|
+
['lib/client.ts', CLIENT_TS],
|
|
88
|
+
['lib/server.ts', SERVER_TS],
|
|
89
|
+
['lib/admin.ts', ADMIN_TS],
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
for (const [relPath, content] of files) {
|
|
93
|
+
const fullPath = path.join(cwd, relPath);
|
|
94
|
+
if (fs.existsSync(fullPath)) {
|
|
95
|
+
warn(`${relPath} 이미 존재 — 건너뜀`);
|
|
96
|
+
} else {
|
|
97
|
+
fs.writeFileSync(fullPath, content, 'utf8');
|
|
98
|
+
success(`${relPath} 생성`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const envPath = path.join(cwd, '.env.local');
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log(`${BOLD}📋 환경변수 설정${RESET}`);
|
|
105
|
+
console.log('──────────────────────────────────');
|
|
106
|
+
|
|
107
|
+
if (!fs.existsSync(envPath)) {
|
|
108
|
+
fs.writeFileSync(envPath, ENV_EXAMPLE, 'utf8');
|
|
109
|
+
success('.env.local 생성 — 아래 값을 채워주세요');
|
|
110
|
+
} else {
|
|
111
|
+
info('.env.local 이미 존재 — 아래 항목이 있는지 확인하세요');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(` ${CYAN}NEXT_PUBLIC_AURABASE_URL${RESET}=https://your-project.cloudfront.net`);
|
|
116
|
+
console.log(` ${CYAN}NEXT_PUBLIC_AURABASE_ANON_KEY${RESET}=your-anon-key`);
|
|
117
|
+
console.log(` ${CYAN}NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY${RESET}=your-service-role-key`);
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log(` → AuraBase 대시보드 ${BOLD}API Keys${RESET} 메뉴에서 확인하세요.`);
|
|
120
|
+
console.log('');
|
|
121
|
+
console.log(`${GREEN}✔ 완료!${RESET} 이제 아래처럼 사용할 수 있습니다:`);
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(` ${CYAN}// 클라이언트 컴포넌트${RESET}`);
|
|
124
|
+
console.log(` import { client } from '@/lib/client'`);
|
|
125
|
+
console.log(` const { data } = await client.from('todos').select('*')`);
|
|
126
|
+
console.log('');
|
|
127
|
+
console.log(` ${CYAN}// 서버 전용 (API Route, Server Component)${RESET}`);
|
|
128
|
+
console.log(` import { admin } from '@/lib/admin'`);
|
|
129
|
+
console.log(` const { data } = await admin.from('todos').select('*')`);
|
|
130
|
+
console.log('');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── 진입점 ────────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
if (command === 'init') {
|
|
136
|
+
init();
|
|
137
|
+
} else {
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(`${BOLD}aurabase-js CLI${RESET}`);
|
|
140
|
+
console.log('');
|
|
141
|
+
console.log('사용법:');
|
|
142
|
+
console.log(` ${CYAN}npx aurabase-js init${RESET} lib/ 폴더 및 환경변수 파일 자동 생성`);
|
|
143
|
+
console.log('');
|
|
144
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,11 @@ module.exports = __toCommonJS(index_exports);
|
|
|
30
30
|
var QueryBuilder = class {
|
|
31
31
|
constructor(url, anonKey, accessToken, tableName, headers = {}) {
|
|
32
32
|
this.isSingle = false;
|
|
33
|
+
this._method = "GET";
|
|
34
|
+
this._body = void 0;
|
|
35
|
+
this._isUpsert = false;
|
|
36
|
+
this._onConflict = void 0;
|
|
37
|
+
this._idValue = void 0;
|
|
33
38
|
this.url = url;
|
|
34
39
|
this.anonKey = anonKey;
|
|
35
40
|
this.accessToken = accessToken;
|
|
@@ -44,94 +49,119 @@ var QueryBuilder = class {
|
|
|
44
49
|
* .select('*')
|
|
45
50
|
*/
|
|
46
51
|
select(columns = "*") {
|
|
47
|
-
this.queryParams.set("select", columns);
|
|
52
|
+
if (columns !== "*") this.queryParams.set("select", columns.replace(/\s/g, ""));
|
|
48
53
|
return this;
|
|
49
54
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Filter by column equality
|
|
52
|
-
* @example
|
|
53
|
-
* .eq('id', 1)
|
|
54
|
-
* .eq('status', 'active')
|
|
55
|
-
*/
|
|
56
55
|
eq(column, value) {
|
|
57
|
-
|
|
56
|
+
if (column === "id") this._idValue = value;
|
|
57
|
+
this.queryParams.append("eq", `${column}:${value}`);
|
|
58
58
|
return this;
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
61
|
* Filter by column inequality
|
|
62
62
|
*/
|
|
63
63
|
neq(column, value) {
|
|
64
|
-
this.queryParams.append(
|
|
64
|
+
this.queryParams.append("neq", `${column}:${value}`);
|
|
65
65
|
return this;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
68
|
* Filter by greater than
|
|
69
69
|
*/
|
|
70
70
|
gt(column, value) {
|
|
71
|
-
this.queryParams.append(
|
|
71
|
+
this.queryParams.append("gt", `${column}:${value}`);
|
|
72
72
|
return this;
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Filter by greater than or equal
|
|
76
76
|
*/
|
|
77
77
|
gte(column, value) {
|
|
78
|
-
this.queryParams.append(
|
|
78
|
+
this.queryParams.append("gte", `${column}:${value}`);
|
|
79
79
|
return this;
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
82
|
* Filter by less than
|
|
83
83
|
*/
|
|
84
84
|
lt(column, value) {
|
|
85
|
-
this.queryParams.append(
|
|
85
|
+
this.queryParams.append("lt", `${column}:${value}`);
|
|
86
86
|
return this;
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
89
|
* Filter by less than or equal
|
|
90
90
|
*/
|
|
91
91
|
lte(column, value) {
|
|
92
|
-
this.queryParams.append(
|
|
92
|
+
this.queryParams.append("lte", `${column}:${value}`);
|
|
93
93
|
return this;
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* Filter by like pattern
|
|
97
97
|
*/
|
|
98
98
|
like(column, pattern) {
|
|
99
|
-
this.queryParams.append(
|
|
99
|
+
this.queryParams.append("like", `${column}:${pattern}`);
|
|
100
100
|
return this;
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* Filter by case-insensitive like pattern
|
|
104
104
|
*/
|
|
105
105
|
ilike(column, pattern) {
|
|
106
|
-
this.queryParams.append(
|
|
106
|
+
this.queryParams.append("ilike", `${column}:${pattern}`);
|
|
107
107
|
return this;
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
110
110
|
* Filter by array contains
|
|
111
111
|
*/
|
|
112
112
|
contains(column, value) {
|
|
113
|
-
this.queryParams.append(
|
|
113
|
+
this.queryParams.append("contains", `${column}:${JSON.stringify(value)}`);
|
|
114
114
|
return this;
|
|
115
115
|
}
|
|
116
116
|
/**
|
|
117
117
|
* Filter by value in array
|
|
118
118
|
*/
|
|
119
119
|
in(column, values) {
|
|
120
|
-
this.queryParams.append(
|
|
120
|
+
this.queryParams.append("in", `${column}:${values.join(",")}`);
|
|
121
121
|
return this;
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
124
124
|
* Filter for null values
|
|
125
125
|
*/
|
|
126
126
|
isNull(column) {
|
|
127
|
-
this.queryParams.append(
|
|
127
|
+
this.queryParams.append("is_null", `${column}:true`);
|
|
128
128
|
return this;
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
131
|
* Filter for non-null values
|
|
132
132
|
*/
|
|
133
133
|
isNotNull(column) {
|
|
134
|
-
this.queryParams.append(
|
|
134
|
+
this.queryParams.append("is_null", `${column}:false`);
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Full-text search across all columns
|
|
139
|
+
*/
|
|
140
|
+
search(query) {
|
|
141
|
+
this.queryParams.set("search", query);
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Negate a filter
|
|
146
|
+
* @example .not('eq', 'category', 'Electronics')
|
|
147
|
+
*/
|
|
148
|
+
not(operator, column, value) {
|
|
149
|
+
this.queryParams.append("not", `${operator}:${column}:${value}`);
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* OR conditions
|
|
154
|
+
* @example .or('category.eq.Electronics,price.lt.100000')
|
|
155
|
+
*/
|
|
156
|
+
or(conditions) {
|
|
157
|
+
this.queryParams.set("or", conditions);
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Filter by array contained by
|
|
162
|
+
*/
|
|
163
|
+
containedBy(column, value) {
|
|
164
|
+
this.queryParams.append("contained_by", `${column}:${JSON.stringify(value)}`);
|
|
135
165
|
return this;
|
|
136
166
|
}
|
|
137
167
|
/**
|
|
@@ -146,7 +176,8 @@ var QueryBuilder = class {
|
|
|
146
176
|
if (nullsFirst !== void 0) {
|
|
147
177
|
orderStr += nullsFirst ? ".nullsfirst" : ".nullslast";
|
|
148
178
|
}
|
|
149
|
-
this.queryParams.
|
|
179
|
+
const existing = this.queryParams.get("order");
|
|
180
|
+
this.queryParams.set("order", existing ? `${existing},${orderStr}` : orderStr);
|
|
150
181
|
return this;
|
|
151
182
|
}
|
|
152
183
|
/**
|
|
@@ -194,28 +225,36 @@ var QueryBuilder = class {
|
|
|
194
225
|
...this.headers
|
|
195
226
|
};
|
|
196
227
|
}
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
228
|
+
buildUrl() {
|
|
229
|
+
const qs = this.queryParams.toString();
|
|
230
|
+
if (this._isUpsert) {
|
|
231
|
+
const conflict = this._onConflict ? `?on_conflict=${this._onConflict}` : "";
|
|
232
|
+
return `${this.url}/api/${this.tableName}/upsert${conflict}`;
|
|
233
|
+
}
|
|
234
|
+
if ((this._method === "PATCH" || this._method === "DELETE") && this._idValue !== void 0) {
|
|
235
|
+
return `${this.url}/api/${this.tableName}/${this._idValue}/`;
|
|
236
|
+
}
|
|
237
|
+
return `${this.url}/api/${this.tableName}/${qs ? `?${qs}` : ""}`;
|
|
238
|
+
}
|
|
239
|
+
async execute() {
|
|
240
|
+
const fullUrl = this.buildUrl();
|
|
241
|
+
const reqHeaders = this.getHeaders();
|
|
242
|
+
const options = { method: this._method, headers: reqHeaders };
|
|
243
|
+
if (this._body !== void 0 && this._method !== "GET") {
|
|
244
|
+
options.body = JSON.stringify(this._body);
|
|
245
|
+
reqHeaders["Prefer"] = "return=representation";
|
|
207
246
|
}
|
|
208
247
|
try {
|
|
209
248
|
const response = await fetch(fullUrl, options);
|
|
249
|
+
const text = await response.text();
|
|
210
250
|
let data = null;
|
|
211
251
|
let error = null;
|
|
212
|
-
const text = await response.text();
|
|
213
252
|
if (text) {
|
|
214
253
|
try {
|
|
215
254
|
const parsed = JSON.parse(text);
|
|
216
255
|
if (!response.ok) {
|
|
217
256
|
error = {
|
|
218
|
-
message: parsed.message || parsed.error || `HTTP ${response.status}`,
|
|
257
|
+
message: parsed.message || parsed.error || parsed.detail || `HTTP ${response.status}`,
|
|
219
258
|
code: parsed.code,
|
|
220
259
|
details: parsed.details
|
|
221
260
|
};
|
|
@@ -223,69 +262,54 @@ var QueryBuilder = class {
|
|
|
223
262
|
data = this.isSingle && Array.isArray(parsed) ? parsed[0] ?? null : parsed;
|
|
224
263
|
}
|
|
225
264
|
} catch {
|
|
226
|
-
if (!response.ok) {
|
|
227
|
-
error = {
|
|
228
|
-
message: text || `HTTP ${response.status}`
|
|
229
|
-
};
|
|
230
|
-
}
|
|
265
|
+
if (!response.ok) error = { message: text || `HTTP ${response.status}` };
|
|
231
266
|
}
|
|
232
267
|
}
|
|
233
|
-
return {
|
|
234
|
-
data,
|
|
235
|
-
error,
|
|
236
|
-
status: response.status,
|
|
237
|
-
statusText: response.statusText
|
|
238
|
-
};
|
|
268
|
+
return { data, error, status: response.status, statusText: response.statusText };
|
|
239
269
|
} catch (err) {
|
|
240
270
|
return {
|
|
241
271
|
data: null,
|
|
242
|
-
error: {
|
|
243
|
-
message: err instanceof Error ? err.message : "Network error"
|
|
244
|
-
},
|
|
272
|
+
error: { message: err instanceof Error ? err.message : "Network error" },
|
|
245
273
|
status: 0,
|
|
246
274
|
statusText: "Network Error"
|
|
247
275
|
};
|
|
248
276
|
}
|
|
249
277
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Execute SELECT query
|
|
252
|
-
*/
|
|
253
278
|
async then(resolve, reject) {
|
|
254
279
|
try {
|
|
255
|
-
const result = await this.
|
|
280
|
+
const result = await this.execute();
|
|
256
281
|
await resolve(result);
|
|
257
282
|
} catch (err) {
|
|
258
|
-
if (reject)
|
|
259
|
-
await reject(err);
|
|
260
|
-
}
|
|
283
|
+
if (reject) await reject(err);
|
|
261
284
|
}
|
|
262
285
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
286
|
+
// CUD — 모두 this 반환 → Supabase 스타일 체이닝 지원
|
|
287
|
+
// .insert({ title: '할일' })
|
|
288
|
+
insert(row) {
|
|
289
|
+
this._method = "POST";
|
|
267
290
|
const rows = Array.isArray(row) ? row : [row];
|
|
268
|
-
|
|
291
|
+
this._body = rows.length === 1 ? rows[0] : rows;
|
|
292
|
+
return this;
|
|
269
293
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return this
|
|
294
|
+
// .update({ completed: true }).eq('id', 1)
|
|
295
|
+
update(data) {
|
|
296
|
+
this._method = "PATCH";
|
|
297
|
+
this._body = data;
|
|
298
|
+
return this;
|
|
275
299
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
300
|
+
// .upsert({ id: 1, title: '수정됨' }, { onConflict: 'id' })
|
|
301
|
+
upsert(row, options = {}) {
|
|
302
|
+
this._method = "POST";
|
|
303
|
+
this._isUpsert = true;
|
|
304
|
+
this._onConflict = options.onConflict;
|
|
280
305
|
const rows = Array.isArray(row) ? row : [row];
|
|
281
|
-
this.
|
|
282
|
-
return this
|
|
306
|
+
this._body = rows.length === 1 ? rows[0] : rows;
|
|
307
|
+
return this;
|
|
283
308
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return this.request("DELETE");
|
|
309
|
+
// .delete().eq('id', 1)
|
|
310
|
+
delete() {
|
|
311
|
+
this._method = "DELETE";
|
|
312
|
+
return this;
|
|
289
313
|
}
|
|
290
314
|
};
|
|
291
315
|
|
|
@@ -585,7 +609,7 @@ var AuraBaseClient = class {
|
|
|
585
609
|
async rpc(functionName, params) {
|
|
586
610
|
const token = this.accessToken || this.anonKey;
|
|
587
611
|
try {
|
|
588
|
-
const response = await fetch(`${this.url}/
|
|
612
|
+
const response = await fetch(`${this.url}/api/${functionName}/`, {
|
|
589
613
|
method: "POST",
|
|
590
614
|
headers: {
|
|
591
615
|
"Content-Type": "application/json",
|
|
@@ -759,6 +783,23 @@ var StorageBucket = class {
|
|
|
759
783
|
|
|
760
784
|
// src/index.ts
|
|
761
785
|
function createClient(options) {
|
|
786
|
+
if (!options.url) {
|
|
787
|
+
console.warn(
|
|
788
|
+
"[aurabase-js] NEXT_PUBLIC_AURABASE_URL이 설정되지 않았습니다.\n" +
|
|
789
|
+
".env.local 파일에 다음 항목을 추가하세요:\n\n" +
|
|
790
|
+
" NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net\n" +
|
|
791
|
+
" NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key\n" +
|
|
792
|
+
" NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key\n"
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
if (!options.anonKey) {
|
|
796
|
+
console.warn(
|
|
797
|
+
"[aurabase-js] anonKey가 설정되지 않았습니다.\n" +
|
|
798
|
+
".env.local 파일에 다음 항목을 추가하세요:\n\n" +
|
|
799
|
+
" NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key (클라이언트용)\n" +
|
|
800
|
+
" NEXT_PUBLIC_AURABASE_SERVICE_ROLE_KEY=your-service-role-key (서버/admin용)\n"
|
|
801
|
+
);
|
|
802
|
+
}
|
|
762
803
|
return new AuraBaseClient(options);
|
|
763
804
|
}
|
|
764
805
|
var index_default = createClient;
|