aurabase-js 0.2.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/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
- this.queryParams.append(column, `eq.${value}`);
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(column, `neq.${value}`);
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(column, `gt.${value}`);
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(column, `gte.${value}`);
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(column, `lt.${value}`);
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(column, `lte.${value}`);
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(column, `like.${pattern}`);
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(column, `ilike.${pattern}`);
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(column, `cs.{${value.join(",")}}`);
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(column, `in.(${values.join(",")})`);
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(column, "is.null");
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(column, "is.not.null");
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.append("order", orderStr);
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
- 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";
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.request("GET");
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
- * Insert row(s)
265
- */
266
- async insert(row) {
286
+ // CUD — 모두 this 반환 → Supabase 스타일 체이닝 지원
287
+ // .insert({ title: '할일' })
288
+ insert(row) {
289
+ this._method = "POST";
267
290
  const rows = Array.isArray(row) ? row : [row];
268
- return this.request("POST", rows.length === 1 ? rows[0] : rows);
291
+ this._body = rows.length === 1 ? rows[0] : rows;
292
+ return this;
269
293
  }
270
- /**
271
- * Update row(s)
272
- */
273
- async update(data) {
274
- return this.request("PATCH", data);
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
- * Upsert row(s)
278
- */
279
- async upsert(row) {
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.headers["Prefer"] = "resolution=merge-duplicates,return=representation";
282
- return this.request("POST", rows.length === 1 ? rows[0] : rows);
306
+ this._body = rows.length === 1 ? rows[0] : rows;
307
+ return this;
283
308
  }
284
- /**
285
- * Delete row(s)
286
- */
287
- async delete() {
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}/rpc/v1/${functionName}`, {
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;
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
- this.queryParams.append(column, `eq.${value}`);
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(column, `neq.${value}`);
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(column, `gt.${value}`);
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(column, `gte.${value}`);
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(column, `lt.${value}`);
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(column, `lte.${value}`);
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(column, `like.${pattern}`);
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(column, `ilike.${pattern}`);
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(column, `cs.{${value.join(",")}}`);
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(column, `in.(${values.join(",")})`);
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(column, "is.null");
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(column, "is.not.null");
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.append("order", orderStr);
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
- 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";
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.request("GET");
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
- * Insert row(s)
237
- */
238
- async insert(row) {
252
+ insert(row) {
253
+ this._method = "POST";
239
254
  const rows = Array.isArray(row) ? row : [row];
240
- return this.request("POST", rows.length === 1 ? rows[0] : rows);
255
+ this._body = rows.length === 1 ? rows[0] : rows;
256
+ return this;
241
257
  }
242
- /**
243
- * Update row(s)
244
- */
245
- async update(data) {
246
- return this.request("PATCH", data);
258
+ update(data) {
259
+ this._method = "PATCH";
260
+ this._body = data;
261
+ return this;
247
262
  }
248
- /**
249
- * Upsert row(s)
250
- */
251
- async upsert(row) {
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.headers["Prefer"] = "resolution=merge-duplicates,return=representation";
254
- return this.request("POST", rows.length === 1 ? rows[0] : rows);
268
+ this._body = rows.length === 1 ? rows[0] : rows;
269
+ return this;
255
270
  }
256
- /**
257
- * Delete row(s)
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}/rpc/v1/${functionName}`, {
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;