aurabase-js 0.6.0 → 0.7.2
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/cli.js +21 -1
- package/dist/cli.mjs +21 -1
- package/dist/index.d.mts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +91 -10
- package/dist/index.mjs +91 -10
- package/package.json +5 -1
- package/src/AuraBaseClient.ts +23 -1
- package/src/QueryBuilder.ts +79 -8
- package/src/cli.ts +21 -1
- package/src/types.ts +1 -0
- package/.omc/state/hud-state.json +0 -6
- package/.omc/state/hud-stdin-cache.json +0 -1
- package/lib/aurabase.ts +0 -9
- package/tsconfig.json +0 -20
package/dist/cli.js
CHANGED
|
@@ -52,12 +52,30 @@ export async function server() {
|
|
|
52
52
|
|
|
53
53
|
return client;
|
|
54
54
|
}
|
|
55
|
+
`,
|
|
56
|
+
"lib/admin.ts": `import { createClient } from 'aurabase-js';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Admin client with service_role key
|
|
60
|
+
* \u26A0\uFE0F ONLY use on server-side (API routes, server components)
|
|
61
|
+
* \u26A0\uFE0F Bypasses all RLS policies - use with caution!
|
|
62
|
+
*/
|
|
63
|
+
export const admin = createClient({
|
|
64
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL || '',
|
|
65
|
+
anonKey: process.env.AURABASE_SERVICE_ROLE_KEY || '',
|
|
66
|
+
});
|
|
55
67
|
`
|
|
56
68
|
};
|
|
57
69
|
var ENV_TEMPLATE = `
|
|
58
70
|
# AuraBase Configuration (.env.local)
|
|
71
|
+
|
|
72
|
+
# Public keys (client + server)
|
|
59
73
|
NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net
|
|
60
74
|
NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key-here
|
|
75
|
+
|
|
76
|
+
# Service role key (server only - bypasses RLS!)
|
|
77
|
+
# \u26A0\uFE0F NEVER expose this to the client!
|
|
78
|
+
AURABASE_SERVICE_ROLE_KEY=your-service-role-key-here
|
|
61
79
|
`;
|
|
62
80
|
function findProjectRoot() {
|
|
63
81
|
let dir = process.cwd();
|
|
@@ -93,6 +111,7 @@ function init() {
|
|
|
93
111
|
console.log("\x1B[1m\n\u{1F680} Initializing AuraBase...\x1B[0m\n");
|
|
94
112
|
createFile(projectRoot, "lib/client.ts");
|
|
95
113
|
createFile(projectRoot, "lib/server.ts");
|
|
114
|
+
createFile(projectRoot, "lib/admin.ts");
|
|
96
115
|
console.log("\x1B[36m%s\x1B[0m", ENV_TEMPLATE);
|
|
97
116
|
}
|
|
98
117
|
function showHelp() {
|
|
@@ -107,8 +126,9 @@ function showHelp() {
|
|
|
107
126
|
-v, --version Show version
|
|
108
127
|
|
|
109
128
|
\x1B[1mGenerated files:\x1B[0m
|
|
110
|
-
lib/client.ts Browser client
|
|
129
|
+
lib/client.ts Browser client (anon key)
|
|
111
130
|
lib/server.ts Server client (with cookie auth)
|
|
131
|
+
lib/admin.ts Admin client (service role, bypasses RLS)
|
|
112
132
|
`);
|
|
113
133
|
}
|
|
114
134
|
function showVersion() {
|
package/dist/cli.mjs
CHANGED
|
@@ -29,12 +29,30 @@ export async function server() {
|
|
|
29
29
|
|
|
30
30
|
return client;
|
|
31
31
|
}
|
|
32
|
+
`,
|
|
33
|
+
"lib/admin.ts": `import { createClient } from 'aurabase-js';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Admin client with service_role key
|
|
37
|
+
* \u26A0\uFE0F ONLY use on server-side (API routes, server components)
|
|
38
|
+
* \u26A0\uFE0F Bypasses all RLS policies - use with caution!
|
|
39
|
+
*/
|
|
40
|
+
export const admin = createClient({
|
|
41
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL || '',
|
|
42
|
+
anonKey: process.env.AURABASE_SERVICE_ROLE_KEY || '',
|
|
43
|
+
});
|
|
32
44
|
`
|
|
33
45
|
};
|
|
34
46
|
var ENV_TEMPLATE = `
|
|
35
47
|
# AuraBase Configuration (.env.local)
|
|
48
|
+
|
|
49
|
+
# Public keys (client + server)
|
|
36
50
|
NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net
|
|
37
51
|
NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key-here
|
|
52
|
+
|
|
53
|
+
# Service role key (server only - bypasses RLS!)
|
|
54
|
+
# \u26A0\uFE0F NEVER expose this to the client!
|
|
55
|
+
AURABASE_SERVICE_ROLE_KEY=your-service-role-key-here
|
|
38
56
|
`;
|
|
39
57
|
function findProjectRoot() {
|
|
40
58
|
let dir = process.cwd();
|
|
@@ -70,6 +88,7 @@ function init() {
|
|
|
70
88
|
console.log("\x1B[1m\n\u{1F680} Initializing AuraBase...\x1B[0m\n");
|
|
71
89
|
createFile(projectRoot, "lib/client.ts");
|
|
72
90
|
createFile(projectRoot, "lib/server.ts");
|
|
91
|
+
createFile(projectRoot, "lib/admin.ts");
|
|
73
92
|
console.log("\x1B[36m%s\x1B[0m", ENV_TEMPLATE);
|
|
74
93
|
}
|
|
75
94
|
function showHelp() {
|
|
@@ -84,8 +103,9 @@ function showHelp() {
|
|
|
84
103
|
-v, --version Show version
|
|
85
104
|
|
|
86
105
|
\x1B[1mGenerated files:\x1B[0m
|
|
87
|
-
lib/client.ts Browser client
|
|
106
|
+
lib/client.ts Browser client (anon key)
|
|
88
107
|
lib/server.ts Server client (with cookie auth)
|
|
108
|
+
lib/admin.ts Admin client (service role, bypasses RLS)
|
|
89
109
|
`);
|
|
90
110
|
}
|
|
91
111
|
function showVersion() {
|
package/dist/index.d.mts
CHANGED
|
@@ -26,6 +26,7 @@ interface PostgrestResponse<T> {
|
|
|
26
26
|
error: AuraBaseError | null;
|
|
27
27
|
status: number;
|
|
28
28
|
statusText: string;
|
|
29
|
+
count?: number | null;
|
|
29
30
|
}
|
|
30
31
|
interface AuraBaseError {
|
|
31
32
|
message: string;
|
|
@@ -65,6 +66,9 @@ declare class QueryBuilder<T> {
|
|
|
65
66
|
private queryParams;
|
|
66
67
|
private headers;
|
|
67
68
|
private isSingle;
|
|
69
|
+
private _countOption;
|
|
70
|
+
private _head;
|
|
71
|
+
private _idValue;
|
|
68
72
|
constructor(url: string, anonKey: string, accessToken: string | null, tableName: string, headers?: Record<string, string>);
|
|
69
73
|
/**
|
|
70
74
|
* Select columns
|
|
@@ -72,7 +76,10 @@ declare class QueryBuilder<T> {
|
|
|
72
76
|
* .select('id, name, email')
|
|
73
77
|
* .select('*')
|
|
74
78
|
*/
|
|
75
|
-
select(columns?: string
|
|
79
|
+
select(columns?: string, options?: {
|
|
80
|
+
count?: 'exact' | 'planned' | 'estimated';
|
|
81
|
+
head?: boolean;
|
|
82
|
+
}): this;
|
|
76
83
|
/**
|
|
77
84
|
* Filter by column equality
|
|
78
85
|
* @example
|
|
@@ -124,6 +131,21 @@ declare class QueryBuilder<T> {
|
|
|
124
131
|
* Filter for non-null values
|
|
125
132
|
*/
|
|
126
133
|
isNotNull(column: string): this;
|
|
134
|
+
/**
|
|
135
|
+
* Negate a filter
|
|
136
|
+
*/
|
|
137
|
+
not(column: string, operator: string, value?: unknown): this;
|
|
138
|
+
/**
|
|
139
|
+
* Filter by null or not null
|
|
140
|
+
*/
|
|
141
|
+
is(column: string, value: null | 'not.null'): this;
|
|
142
|
+
/**
|
|
143
|
+
* Full-text search
|
|
144
|
+
*/
|
|
145
|
+
textSearch(column: string, query: string, options?: {
|
|
146
|
+
config?: string;
|
|
147
|
+
type?: 'plain' | 'phrase' | 'websearch';
|
|
148
|
+
}): this;
|
|
127
149
|
/**
|
|
128
150
|
* Order results
|
|
129
151
|
* @example
|
|
@@ -266,6 +288,10 @@ declare class AuraBaseClient {
|
|
|
266
288
|
* Set access token for authenticated requests
|
|
267
289
|
*/
|
|
268
290
|
setAccessToken(token: string | null): void;
|
|
291
|
+
/**
|
|
292
|
+
* Manually set session (Supabase-compatible alias)
|
|
293
|
+
*/
|
|
294
|
+
setSession(token: string | null): void;
|
|
269
295
|
/**
|
|
270
296
|
* Get the current access token
|
|
271
297
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ interface PostgrestResponse<T> {
|
|
|
26
26
|
error: AuraBaseError | null;
|
|
27
27
|
status: number;
|
|
28
28
|
statusText: string;
|
|
29
|
+
count?: number | null;
|
|
29
30
|
}
|
|
30
31
|
interface AuraBaseError {
|
|
31
32
|
message: string;
|
|
@@ -65,6 +66,9 @@ declare class QueryBuilder<T> {
|
|
|
65
66
|
private queryParams;
|
|
66
67
|
private headers;
|
|
67
68
|
private isSingle;
|
|
69
|
+
private _countOption;
|
|
70
|
+
private _head;
|
|
71
|
+
private _idValue;
|
|
68
72
|
constructor(url: string, anonKey: string, accessToken: string | null, tableName: string, headers?: Record<string, string>);
|
|
69
73
|
/**
|
|
70
74
|
* Select columns
|
|
@@ -72,7 +76,10 @@ declare class QueryBuilder<T> {
|
|
|
72
76
|
* .select('id, name, email')
|
|
73
77
|
* .select('*')
|
|
74
78
|
*/
|
|
75
|
-
select(columns?: string
|
|
79
|
+
select(columns?: string, options?: {
|
|
80
|
+
count?: 'exact' | 'planned' | 'estimated';
|
|
81
|
+
head?: boolean;
|
|
82
|
+
}): this;
|
|
76
83
|
/**
|
|
77
84
|
* Filter by column equality
|
|
78
85
|
* @example
|
|
@@ -124,6 +131,21 @@ declare class QueryBuilder<T> {
|
|
|
124
131
|
* Filter for non-null values
|
|
125
132
|
*/
|
|
126
133
|
isNotNull(column: string): this;
|
|
134
|
+
/**
|
|
135
|
+
* Negate a filter
|
|
136
|
+
*/
|
|
137
|
+
not(column: string, operator: string, value?: unknown): this;
|
|
138
|
+
/**
|
|
139
|
+
* Filter by null or not null
|
|
140
|
+
*/
|
|
141
|
+
is(column: string, value: null | 'not.null'): this;
|
|
142
|
+
/**
|
|
143
|
+
* Full-text search
|
|
144
|
+
*/
|
|
145
|
+
textSearch(column: string, query: string, options?: {
|
|
146
|
+
config?: string;
|
|
147
|
+
type?: 'plain' | 'phrase' | 'websearch';
|
|
148
|
+
}): this;
|
|
127
149
|
/**
|
|
128
150
|
* Order results
|
|
129
151
|
* @example
|
|
@@ -266,6 +288,10 @@ declare class AuraBaseClient {
|
|
|
266
288
|
* Set access token for authenticated requests
|
|
267
289
|
*/
|
|
268
290
|
setAccessToken(token: string | null): void;
|
|
291
|
+
/**
|
|
292
|
+
* Manually set session (Supabase-compatible alias)
|
|
293
|
+
*/
|
|
294
|
+
setSession(token: string | null): void;
|
|
269
295
|
/**
|
|
270
296
|
* Get the current access token
|
|
271
297
|
*/
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,9 @@ 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._countOption = null;
|
|
34
|
+
this._head = false;
|
|
35
|
+
this._idValue = void 0;
|
|
33
36
|
this.url = url;
|
|
34
37
|
this.anonKey = anonKey;
|
|
35
38
|
this.accessToken = accessToken;
|
|
@@ -43,8 +46,10 @@ var QueryBuilder = class {
|
|
|
43
46
|
* .select('id, name, email')
|
|
44
47
|
* .select('*')
|
|
45
48
|
*/
|
|
46
|
-
select(columns = "*") {
|
|
49
|
+
select(columns = "*", options) {
|
|
47
50
|
this.queryParams.set("select", columns);
|
|
51
|
+
if (options?.count) this._countOption = options.count;
|
|
52
|
+
if (options?.head) this._head = true;
|
|
48
53
|
return this;
|
|
49
54
|
}
|
|
50
55
|
/**
|
|
@@ -55,6 +60,7 @@ var QueryBuilder = class {
|
|
|
55
60
|
*/
|
|
56
61
|
eq(column, value) {
|
|
57
62
|
this.queryParams.append(column, `eq.${value}`);
|
|
63
|
+
if (column === "id") this._idValue = value;
|
|
58
64
|
return this;
|
|
59
65
|
}
|
|
60
66
|
/**
|
|
@@ -134,6 +140,29 @@ var QueryBuilder = class {
|
|
|
134
140
|
this.queryParams.append(column, "is.not.null");
|
|
135
141
|
return this;
|
|
136
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Negate a filter
|
|
145
|
+
*/
|
|
146
|
+
not(column, operator, value) {
|
|
147
|
+
this.queryParams.append(column, `not.${operator}.${value ?? ""}`);
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Filter by null or not null
|
|
152
|
+
*/
|
|
153
|
+
is(column, value) {
|
|
154
|
+
if (value === null) return this.isNull(column);
|
|
155
|
+
return this.isNotNull(column);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Full-text search
|
|
159
|
+
*/
|
|
160
|
+
textSearch(column, query, options) {
|
|
161
|
+
const prefix = options?.type === "plain" ? "plfts" : options?.type === "phrase" ? "phfts" : "fts";
|
|
162
|
+
const configStr = options?.config ? `(${options.config})` : "";
|
|
163
|
+
this.queryParams.append(column, `${prefix}${configStr}.${query}`);
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
137
166
|
/**
|
|
138
167
|
* Order results
|
|
139
168
|
* @example
|
|
@@ -187,28 +216,61 @@ var QueryBuilder = class {
|
|
|
187
216
|
}
|
|
188
217
|
getHeaders() {
|
|
189
218
|
const token = this.accessToken || this.anonKey;
|
|
190
|
-
|
|
219
|
+
const headers = {
|
|
191
220
|
"Content-Type": "application/json",
|
|
192
221
|
"apikey": this.anonKey,
|
|
193
222
|
"Authorization": `Bearer ${token}`,
|
|
194
223
|
...this.headers
|
|
195
224
|
};
|
|
225
|
+
if (this._countOption) {
|
|
226
|
+
headers["Prefer"] = `count=${this._countOption}`;
|
|
227
|
+
}
|
|
228
|
+
return headers;
|
|
196
229
|
}
|
|
197
230
|
async request(method, body) {
|
|
198
|
-
const
|
|
199
|
-
|
|
231
|
+
const effectiveMethod = this._head ? "HEAD" : method;
|
|
232
|
+
let fullUrl;
|
|
233
|
+
if ((method === "PATCH" || method === "DELETE") && this._idValue !== void 0) {
|
|
234
|
+
const params = new URLSearchParams(this.queryParams);
|
|
235
|
+
params.delete("id");
|
|
236
|
+
const qs = params.toString();
|
|
237
|
+
fullUrl = `${this.url}/api/${this.tableName}/${this._idValue}/${qs ? `?${qs}` : ""}`;
|
|
238
|
+
} else {
|
|
239
|
+
const queryString = this.queryParams.toString();
|
|
240
|
+
fullUrl = `${this.url}/api/${this.tableName}/${queryString ? `?${queryString}` : ""}`;
|
|
241
|
+
}
|
|
200
242
|
const options = {
|
|
201
|
-
method,
|
|
243
|
+
method: effectiveMethod,
|
|
202
244
|
headers: this.getHeaders()
|
|
203
245
|
};
|
|
204
|
-
if (body && method !== "GET") {
|
|
246
|
+
if (body && method !== "GET" && method !== "HEAD") {
|
|
205
247
|
options.body = JSON.stringify(body);
|
|
206
|
-
options.headers
|
|
248
|
+
const hdrs = options.headers;
|
|
249
|
+
if (hdrs["Prefer"]) {
|
|
250
|
+
hdrs["Prefer"] = hdrs["Prefer"] + ",return=representation";
|
|
251
|
+
} else {
|
|
252
|
+
hdrs["Prefer"] = "return=representation";
|
|
253
|
+
}
|
|
207
254
|
}
|
|
208
255
|
try {
|
|
209
256
|
const response = await fetch(fullUrl, options);
|
|
210
257
|
let data = null;
|
|
211
258
|
let error = null;
|
|
259
|
+
const contentRange = response.headers.get("content-range");
|
|
260
|
+
let count = null;
|
|
261
|
+
if (contentRange) {
|
|
262
|
+
const match = contentRange.match(/\/(\d+)$/);
|
|
263
|
+
if (match) count = parseInt(match[1], 10);
|
|
264
|
+
}
|
|
265
|
+
if (effectiveMethod === "HEAD") {
|
|
266
|
+
return {
|
|
267
|
+
data: null,
|
|
268
|
+
error: null,
|
|
269
|
+
status: response.status,
|
|
270
|
+
statusText: response.statusText,
|
|
271
|
+
count
|
|
272
|
+
};
|
|
273
|
+
}
|
|
212
274
|
const text = await response.text();
|
|
213
275
|
if (text) {
|
|
214
276
|
try {
|
|
@@ -234,7 +296,8 @@ var QueryBuilder = class {
|
|
|
234
296
|
data,
|
|
235
297
|
error,
|
|
236
298
|
status: response.status,
|
|
237
|
-
statusText: response.statusText
|
|
299
|
+
statusText: response.statusText,
|
|
300
|
+
count
|
|
238
301
|
};
|
|
239
302
|
} catch (err) {
|
|
240
303
|
return {
|
|
@@ -243,7 +306,8 @@ var QueryBuilder = class {
|
|
|
243
306
|
message: err instanceof Error ? err.message : "Network error"
|
|
244
307
|
},
|
|
245
308
|
status: 0,
|
|
246
|
-
statusText: "Network Error"
|
|
309
|
+
statusText: "Network Error",
|
|
310
|
+
count: null
|
|
247
311
|
};
|
|
248
312
|
}
|
|
249
313
|
}
|
|
@@ -550,6 +614,17 @@ var AuraBaseClient = class {
|
|
|
550
614
|
this.anonKey = options.anonKey;
|
|
551
615
|
this.customHeaders = options.headers || {};
|
|
552
616
|
this.auth = new AuthClient(this.url, this.anonKey);
|
|
617
|
+
const { data: { session } } = this.auth.getSession();
|
|
618
|
+
if (session?.access_token) {
|
|
619
|
+
this.accessToken = session.access_token;
|
|
620
|
+
}
|
|
621
|
+
this.auth.onAuthStateChange((event, session2) => {
|
|
622
|
+
if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
|
|
623
|
+
this.accessToken = session2?.access_token ?? null;
|
|
624
|
+
} else if (event === "SIGNED_OUT") {
|
|
625
|
+
this.accessToken = null;
|
|
626
|
+
}
|
|
627
|
+
});
|
|
553
628
|
}
|
|
554
629
|
/**
|
|
555
630
|
* Set access token for authenticated requests
|
|
@@ -557,6 +632,12 @@ var AuraBaseClient = class {
|
|
|
557
632
|
setAccessToken(token) {
|
|
558
633
|
this.accessToken = token;
|
|
559
634
|
}
|
|
635
|
+
/**
|
|
636
|
+
* Manually set session (Supabase-compatible alias)
|
|
637
|
+
*/
|
|
638
|
+
setSession(token) {
|
|
639
|
+
this.accessToken = token;
|
|
640
|
+
}
|
|
560
641
|
/**
|
|
561
642
|
* Get the current access token
|
|
562
643
|
*/
|
|
@@ -585,7 +666,7 @@ var AuraBaseClient = class {
|
|
|
585
666
|
async rpc(functionName, params) {
|
|
586
667
|
const token = this.accessToken || this.anonKey;
|
|
587
668
|
try {
|
|
588
|
-
const response = await fetch(`${this.url}/
|
|
669
|
+
const response = await fetch(`${this.url}/rest/v1/rpc/${functionName}`, {
|
|
589
670
|
method: "POST",
|
|
590
671
|
headers: {
|
|
591
672
|
"Content-Type": "application/json",
|
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
var QueryBuilder = class {
|
|
3
3
|
constructor(url, anonKey, accessToken, tableName, headers = {}) {
|
|
4
4
|
this.isSingle = false;
|
|
5
|
+
this._countOption = null;
|
|
6
|
+
this._head = false;
|
|
7
|
+
this._idValue = void 0;
|
|
5
8
|
this.url = url;
|
|
6
9
|
this.anonKey = anonKey;
|
|
7
10
|
this.accessToken = accessToken;
|
|
@@ -15,8 +18,10 @@ var QueryBuilder = class {
|
|
|
15
18
|
* .select('id, name, email')
|
|
16
19
|
* .select('*')
|
|
17
20
|
*/
|
|
18
|
-
select(columns = "*") {
|
|
21
|
+
select(columns = "*", options) {
|
|
19
22
|
this.queryParams.set("select", columns);
|
|
23
|
+
if (options?.count) this._countOption = options.count;
|
|
24
|
+
if (options?.head) this._head = true;
|
|
20
25
|
return this;
|
|
21
26
|
}
|
|
22
27
|
/**
|
|
@@ -27,6 +32,7 @@ var QueryBuilder = class {
|
|
|
27
32
|
*/
|
|
28
33
|
eq(column, value) {
|
|
29
34
|
this.queryParams.append(column, `eq.${value}`);
|
|
35
|
+
if (column === "id") this._idValue = value;
|
|
30
36
|
return this;
|
|
31
37
|
}
|
|
32
38
|
/**
|
|
@@ -106,6 +112,29 @@ var QueryBuilder = class {
|
|
|
106
112
|
this.queryParams.append(column, "is.not.null");
|
|
107
113
|
return this;
|
|
108
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Negate a filter
|
|
117
|
+
*/
|
|
118
|
+
not(column, operator, value) {
|
|
119
|
+
this.queryParams.append(column, `not.${operator}.${value ?? ""}`);
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Filter by null or not null
|
|
124
|
+
*/
|
|
125
|
+
is(column, value) {
|
|
126
|
+
if (value === null) return this.isNull(column);
|
|
127
|
+
return this.isNotNull(column);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Full-text search
|
|
131
|
+
*/
|
|
132
|
+
textSearch(column, query, options) {
|
|
133
|
+
const prefix = options?.type === "plain" ? "plfts" : options?.type === "phrase" ? "phfts" : "fts";
|
|
134
|
+
const configStr = options?.config ? `(${options.config})` : "";
|
|
135
|
+
this.queryParams.append(column, `${prefix}${configStr}.${query}`);
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
109
138
|
/**
|
|
110
139
|
* Order results
|
|
111
140
|
* @example
|
|
@@ -159,28 +188,61 @@ var QueryBuilder = class {
|
|
|
159
188
|
}
|
|
160
189
|
getHeaders() {
|
|
161
190
|
const token = this.accessToken || this.anonKey;
|
|
162
|
-
|
|
191
|
+
const headers = {
|
|
163
192
|
"Content-Type": "application/json",
|
|
164
193
|
"apikey": this.anonKey,
|
|
165
194
|
"Authorization": `Bearer ${token}`,
|
|
166
195
|
...this.headers
|
|
167
196
|
};
|
|
197
|
+
if (this._countOption) {
|
|
198
|
+
headers["Prefer"] = `count=${this._countOption}`;
|
|
199
|
+
}
|
|
200
|
+
return headers;
|
|
168
201
|
}
|
|
169
202
|
async request(method, body) {
|
|
170
|
-
const
|
|
171
|
-
|
|
203
|
+
const effectiveMethod = this._head ? "HEAD" : method;
|
|
204
|
+
let fullUrl;
|
|
205
|
+
if ((method === "PATCH" || method === "DELETE") && this._idValue !== void 0) {
|
|
206
|
+
const params = new URLSearchParams(this.queryParams);
|
|
207
|
+
params.delete("id");
|
|
208
|
+
const qs = params.toString();
|
|
209
|
+
fullUrl = `${this.url}/api/${this.tableName}/${this._idValue}/${qs ? `?${qs}` : ""}`;
|
|
210
|
+
} else {
|
|
211
|
+
const queryString = this.queryParams.toString();
|
|
212
|
+
fullUrl = `${this.url}/api/${this.tableName}/${queryString ? `?${queryString}` : ""}`;
|
|
213
|
+
}
|
|
172
214
|
const options = {
|
|
173
|
-
method,
|
|
215
|
+
method: effectiveMethod,
|
|
174
216
|
headers: this.getHeaders()
|
|
175
217
|
};
|
|
176
|
-
if (body && method !== "GET") {
|
|
218
|
+
if (body && method !== "GET" && method !== "HEAD") {
|
|
177
219
|
options.body = JSON.stringify(body);
|
|
178
|
-
options.headers
|
|
220
|
+
const hdrs = options.headers;
|
|
221
|
+
if (hdrs["Prefer"]) {
|
|
222
|
+
hdrs["Prefer"] = hdrs["Prefer"] + ",return=representation";
|
|
223
|
+
} else {
|
|
224
|
+
hdrs["Prefer"] = "return=representation";
|
|
225
|
+
}
|
|
179
226
|
}
|
|
180
227
|
try {
|
|
181
228
|
const response = await fetch(fullUrl, options);
|
|
182
229
|
let data = null;
|
|
183
230
|
let error = null;
|
|
231
|
+
const contentRange = response.headers.get("content-range");
|
|
232
|
+
let count = null;
|
|
233
|
+
if (contentRange) {
|
|
234
|
+
const match = contentRange.match(/\/(\d+)$/);
|
|
235
|
+
if (match) count = parseInt(match[1], 10);
|
|
236
|
+
}
|
|
237
|
+
if (effectiveMethod === "HEAD") {
|
|
238
|
+
return {
|
|
239
|
+
data: null,
|
|
240
|
+
error: null,
|
|
241
|
+
status: response.status,
|
|
242
|
+
statusText: response.statusText,
|
|
243
|
+
count
|
|
244
|
+
};
|
|
245
|
+
}
|
|
184
246
|
const text = await response.text();
|
|
185
247
|
if (text) {
|
|
186
248
|
try {
|
|
@@ -206,7 +268,8 @@ var QueryBuilder = class {
|
|
|
206
268
|
data,
|
|
207
269
|
error,
|
|
208
270
|
status: response.status,
|
|
209
|
-
statusText: response.statusText
|
|
271
|
+
statusText: response.statusText,
|
|
272
|
+
count
|
|
210
273
|
};
|
|
211
274
|
} catch (err) {
|
|
212
275
|
return {
|
|
@@ -215,7 +278,8 @@ var QueryBuilder = class {
|
|
|
215
278
|
message: err instanceof Error ? err.message : "Network error"
|
|
216
279
|
},
|
|
217
280
|
status: 0,
|
|
218
|
-
statusText: "Network Error"
|
|
281
|
+
statusText: "Network Error",
|
|
282
|
+
count: null
|
|
219
283
|
};
|
|
220
284
|
}
|
|
221
285
|
}
|
|
@@ -522,6 +586,17 @@ var AuraBaseClient = class {
|
|
|
522
586
|
this.anonKey = options.anonKey;
|
|
523
587
|
this.customHeaders = options.headers || {};
|
|
524
588
|
this.auth = new AuthClient(this.url, this.anonKey);
|
|
589
|
+
const { data: { session } } = this.auth.getSession();
|
|
590
|
+
if (session?.access_token) {
|
|
591
|
+
this.accessToken = session.access_token;
|
|
592
|
+
}
|
|
593
|
+
this.auth.onAuthStateChange((event, session2) => {
|
|
594
|
+
if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
|
|
595
|
+
this.accessToken = session2?.access_token ?? null;
|
|
596
|
+
} else if (event === "SIGNED_OUT") {
|
|
597
|
+
this.accessToken = null;
|
|
598
|
+
}
|
|
599
|
+
});
|
|
525
600
|
}
|
|
526
601
|
/**
|
|
527
602
|
* Set access token for authenticated requests
|
|
@@ -529,6 +604,12 @@ var AuraBaseClient = class {
|
|
|
529
604
|
setAccessToken(token) {
|
|
530
605
|
this.accessToken = token;
|
|
531
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Manually set session (Supabase-compatible alias)
|
|
609
|
+
*/
|
|
610
|
+
setSession(token) {
|
|
611
|
+
this.accessToken = token;
|
|
612
|
+
}
|
|
532
613
|
/**
|
|
533
614
|
* Get the current access token
|
|
534
615
|
*/
|
|
@@ -557,7 +638,7 @@ var AuraBaseClient = class {
|
|
|
557
638
|
async rpc(functionName, params) {
|
|
558
639
|
const token = this.accessToken || this.anonKey;
|
|
559
640
|
try {
|
|
560
|
-
const response = await fetch(`${this.url}/
|
|
641
|
+
const response = await fetch(`${this.url}/rest/v1/rpc/${functionName}`, {
|
|
561
642
|
method: "POST",
|
|
562
643
|
headers: {
|
|
563
644
|
"Content-Type": "application/json",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aurabase-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "AuraBase client library - Supabase-style SDK for AuraBase",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"require": "./dist/index.js"
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src"
|
|
21
|
+
],
|
|
18
22
|
"scripts": {
|
|
19
23
|
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
|
|
20
24
|
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
package/src/AuraBaseClient.ts
CHANGED
|
@@ -14,6 +14,21 @@ export class AuraBaseClient {
|
|
|
14
14
|
this.anonKey = options.anonKey;
|
|
15
15
|
this.customHeaders = options.headers || {};
|
|
16
16
|
this.auth = new AuthClient(this.url, this.anonKey);
|
|
17
|
+
|
|
18
|
+
// 저장된 세션 복원 (페이지 새로고침 후에도 로그인 상태 유지)
|
|
19
|
+
const { data: { session } } = this.auth.getSession();
|
|
20
|
+
if (session?.access_token) {
|
|
21
|
+
this.accessToken = session.access_token;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 로그인/로그아웃 시 accessToken 자동 동기화
|
|
25
|
+
this.auth.onAuthStateChange((event, session) => {
|
|
26
|
+
if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
|
|
27
|
+
this.accessToken = session?.access_token ?? null;
|
|
28
|
+
} else if (event === 'SIGNED_OUT') {
|
|
29
|
+
this.accessToken = null;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
/**
|
|
@@ -23,6 +38,13 @@ export class AuraBaseClient {
|
|
|
23
38
|
this.accessToken = token;
|
|
24
39
|
}
|
|
25
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Manually set session (Supabase-compatible alias)
|
|
43
|
+
*/
|
|
44
|
+
setSession(token: string | null): void {
|
|
45
|
+
this.accessToken = token;
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
/**
|
|
27
49
|
* Get the current access token
|
|
28
50
|
*/
|
|
@@ -57,7 +79,7 @@ export class AuraBaseClient {
|
|
|
57
79
|
const token = this.accessToken || this.anonKey;
|
|
58
80
|
|
|
59
81
|
try {
|
|
60
|
-
const response = await fetch(`${this.url}/
|
|
82
|
+
const response = await fetch(`${this.url}/rest/v1/rpc/${functionName}`, {
|
|
61
83
|
method: 'POST',
|
|
62
84
|
headers: {
|
|
63
85
|
'Content-Type': 'application/json',
|
package/src/QueryBuilder.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AuraBaseApiError } from './errors';
|
|
2
2
|
import { PostgrestResponse, AuraBaseError } from './types';
|
|
3
3
|
|
|
4
|
-
type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
4
|
+
type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' | 'HEAD';
|
|
5
5
|
|
|
6
6
|
export class QueryBuilder<T> {
|
|
7
7
|
private url: string;
|
|
@@ -11,6 +11,9 @@ export class QueryBuilder<T> {
|
|
|
11
11
|
private queryParams: URLSearchParams;
|
|
12
12
|
private headers: Record<string, string>;
|
|
13
13
|
private isSingle: boolean = false;
|
|
14
|
+
private _countOption: 'exact' | 'planned' | 'estimated' | null = null;
|
|
15
|
+
private _head: boolean = false;
|
|
16
|
+
private _idValue: unknown = undefined;
|
|
14
17
|
|
|
15
18
|
constructor(
|
|
16
19
|
url: string,
|
|
@@ -33,8 +36,10 @@ export class QueryBuilder<T> {
|
|
|
33
36
|
* .select('id, name, email')
|
|
34
37
|
* .select('*')
|
|
35
38
|
*/
|
|
36
|
-
select(columns: string = '*'): this {
|
|
39
|
+
select(columns: string = '*', options?: { count?: 'exact' | 'planned' | 'estimated'; head?: boolean }): this {
|
|
37
40
|
this.queryParams.set('select', columns);
|
|
41
|
+
if (options?.count) this._countOption = options.count;
|
|
42
|
+
if (options?.head) this._head = true;
|
|
38
43
|
return this;
|
|
39
44
|
}
|
|
40
45
|
|
|
@@ -46,6 +51,7 @@ export class QueryBuilder<T> {
|
|
|
46
51
|
*/
|
|
47
52
|
eq(column: string, value: unknown): this {
|
|
48
53
|
this.queryParams.append(column, `eq.${value}`);
|
|
54
|
+
if (column === 'id') this._idValue = value;
|
|
49
55
|
return this;
|
|
50
56
|
}
|
|
51
57
|
|
|
@@ -137,6 +143,32 @@ export class QueryBuilder<T> {
|
|
|
137
143
|
return this;
|
|
138
144
|
}
|
|
139
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Negate a filter
|
|
148
|
+
*/
|
|
149
|
+
not(column: string, operator: string, value?: unknown): this {
|
|
150
|
+
this.queryParams.append(column, `not.${operator}.${value ?? ''}`);
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Filter by null or not null
|
|
156
|
+
*/
|
|
157
|
+
is(column: string, value: null | 'not.null'): this {
|
|
158
|
+
if (value === null) return this.isNull(column);
|
|
159
|
+
return this.isNotNull(column);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Full-text search
|
|
164
|
+
*/
|
|
165
|
+
textSearch(column: string, query: string, options?: { config?: string; type?: 'plain' | 'phrase' | 'websearch' }): this {
|
|
166
|
+
const prefix = options?.type === 'plain' ? 'plfts' : options?.type === 'phrase' ? 'phfts' : 'fts';
|
|
167
|
+
const configStr = options?.config ? `(${options.config})` : '';
|
|
168
|
+
this.queryParams.append(column, `${prefix}${configStr}.${query}`);
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
|
|
140
172
|
/**
|
|
141
173
|
* Order results
|
|
142
174
|
* @example
|
|
@@ -196,29 +228,48 @@ export class QueryBuilder<T> {
|
|
|
196
228
|
|
|
197
229
|
private getHeaders(): Record<string, string> {
|
|
198
230
|
const token = this.accessToken || this.anonKey;
|
|
199
|
-
|
|
231
|
+
const headers: Record<string, string> = {
|
|
200
232
|
'Content-Type': 'application/json',
|
|
201
233
|
'apikey': this.anonKey,
|
|
202
234
|
'Authorization': `Bearer ${token}`,
|
|
203
235
|
...this.headers,
|
|
204
236
|
};
|
|
237
|
+
if (this._countOption) {
|
|
238
|
+
headers['Prefer'] = `count=${this._countOption}`;
|
|
239
|
+
}
|
|
240
|
+
return headers;
|
|
205
241
|
}
|
|
206
242
|
|
|
207
243
|
private async request<TResponse>(
|
|
208
244
|
method: HttpMethod,
|
|
209
245
|
body?: unknown
|
|
210
246
|
): Promise<PostgrestResponse<TResponse>> {
|
|
211
|
-
const
|
|
212
|
-
|
|
247
|
+
const effectiveMethod = this._head ? 'HEAD' : method;
|
|
248
|
+
|
|
249
|
+
let fullUrl: string;
|
|
250
|
+
if ((method === 'PATCH' || method === 'DELETE') && this._idValue !== undefined) {
|
|
251
|
+
const params = new URLSearchParams(this.queryParams);
|
|
252
|
+
params.delete('id');
|
|
253
|
+
const qs = params.toString();
|
|
254
|
+
fullUrl = `${this.url}/api/${this.tableName}/${this._idValue}/${qs ? `?${qs}` : ''}`;
|
|
255
|
+
} else {
|
|
256
|
+
const queryString = this.queryParams.toString();
|
|
257
|
+
fullUrl = `${this.url}/api/${this.tableName}/${queryString ? `?${queryString}` : ''}`;
|
|
258
|
+
}
|
|
213
259
|
|
|
214
260
|
const options: RequestInit = {
|
|
215
|
-
method,
|
|
261
|
+
method: effectiveMethod,
|
|
216
262
|
headers: this.getHeaders(),
|
|
217
263
|
};
|
|
218
264
|
|
|
219
|
-
if (body && method !== 'GET') {
|
|
265
|
+
if (body && method !== 'GET' && method !== 'HEAD') {
|
|
220
266
|
options.body = JSON.stringify(body);
|
|
221
|
-
|
|
267
|
+
const hdrs = options.headers as Record<string, string>;
|
|
268
|
+
if (hdrs['Prefer']) {
|
|
269
|
+
hdrs['Prefer'] = hdrs['Prefer'] + ',return=representation';
|
|
270
|
+
} else {
|
|
271
|
+
hdrs['Prefer'] = 'return=representation';
|
|
272
|
+
}
|
|
222
273
|
}
|
|
223
274
|
|
|
224
275
|
try {
|
|
@@ -227,6 +278,24 @@ export class QueryBuilder<T> {
|
|
|
227
278
|
let data: TResponse | null = null;
|
|
228
279
|
let error: AuraBaseError | null = null;
|
|
229
280
|
|
|
281
|
+
// Parse Content-Range header for count
|
|
282
|
+
const contentRange = response.headers.get('content-range');
|
|
283
|
+
let count: number | null = null;
|
|
284
|
+
if (contentRange) {
|
|
285
|
+
const match = contentRange.match(/\/(\d+)$/);
|
|
286
|
+
if (match) count = parseInt(match[1], 10);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (effectiveMethod === 'HEAD') {
|
|
290
|
+
return {
|
|
291
|
+
data: null,
|
|
292
|
+
error: null,
|
|
293
|
+
status: response.status,
|
|
294
|
+
statusText: response.statusText,
|
|
295
|
+
count,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
230
299
|
const text = await response.text();
|
|
231
300
|
|
|
232
301
|
if (text) {
|
|
@@ -256,6 +325,7 @@ export class QueryBuilder<T> {
|
|
|
256
325
|
error,
|
|
257
326
|
status: response.status,
|
|
258
327
|
statusText: response.statusText,
|
|
328
|
+
count,
|
|
259
329
|
};
|
|
260
330
|
} catch (err) {
|
|
261
331
|
return {
|
|
@@ -265,6 +335,7 @@ export class QueryBuilder<T> {
|
|
|
265
335
|
},
|
|
266
336
|
status: 0,
|
|
267
337
|
statusText: 'Network Error',
|
|
338
|
+
count: null,
|
|
268
339
|
};
|
|
269
340
|
}
|
|
270
341
|
}
|
package/src/cli.ts
CHANGED
|
@@ -29,13 +29,31 @@ export async function server() {
|
|
|
29
29
|
|
|
30
30
|
return client;
|
|
31
31
|
}
|
|
32
|
+
`,
|
|
33
|
+
'lib/admin.ts': `import { createClient } from 'aurabase-js';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Admin client with service_role key
|
|
37
|
+
* ⚠️ ONLY use on server-side (API routes, server components)
|
|
38
|
+
* ⚠️ Bypasses all RLS policies - use with caution!
|
|
39
|
+
*/
|
|
40
|
+
export const admin = createClient({
|
|
41
|
+
url: process.env.NEXT_PUBLIC_AURABASE_URL || '',
|
|
42
|
+
anonKey: process.env.AURABASE_SERVICE_ROLE_KEY || '',
|
|
43
|
+
});
|
|
32
44
|
`,
|
|
33
45
|
};
|
|
34
46
|
|
|
35
47
|
const ENV_TEMPLATE = `
|
|
36
48
|
# AuraBase Configuration (.env.local)
|
|
49
|
+
|
|
50
|
+
# Public keys (client + server)
|
|
37
51
|
NEXT_PUBLIC_AURABASE_URL=https://your-project.cloudfront.net
|
|
38
52
|
NEXT_PUBLIC_AURABASE_ANON_KEY=your-anon-key-here
|
|
53
|
+
|
|
54
|
+
# Service role key (server only - bypasses RLS!)
|
|
55
|
+
# ⚠️ NEVER expose this to the client!
|
|
56
|
+
AURABASE_SERVICE_ROLE_KEY=your-service-role-key-here
|
|
39
57
|
`;
|
|
40
58
|
|
|
41
59
|
function findProjectRoot(): string {
|
|
@@ -80,6 +98,7 @@ function init() {
|
|
|
80
98
|
|
|
81
99
|
createFile(projectRoot, 'lib/client.ts');
|
|
82
100
|
createFile(projectRoot, 'lib/server.ts');
|
|
101
|
+
createFile(projectRoot, 'lib/admin.ts');
|
|
83
102
|
|
|
84
103
|
console.log('\x1b[36m%s\x1b[0m', ENV_TEMPLATE);
|
|
85
104
|
}
|
|
@@ -96,8 +115,9 @@ function showHelp() {
|
|
|
96
115
|
-v, --version Show version
|
|
97
116
|
|
|
98
117
|
\x1b[1mGenerated files:\x1b[0m
|
|
99
|
-
lib/client.ts Browser client
|
|
118
|
+
lib/client.ts Browser client (anon key)
|
|
100
119
|
lib/server.ts Server client (with cookie auth)
|
|
120
|
+
lib/admin.ts Admin client (service role, bypasses RLS)
|
|
101
121
|
`);
|
|
102
122
|
}
|
|
103
123
|
|
package/src/types.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"session_id":"1c1e8df6-335a-4058-8bd4-4c0a67d996cd","transcript_path":"C:\\Users\\Jay\\.claude\\projects\\D--000-FrontEnd-242-dino-game\\1c1e8df6-335a-4058-8bd4-4c0a67d996cd.jsonl","cwd":"D:\\000.FrontEnd\\242.dino_game\\packages\\aurabase-js","model":{"id":"GLM-5","display_name":"GLM-5"},"workspace":{"current_dir":"D:\\000.FrontEnd\\242.dino_game\\packages\\aurabase-js","project_dir":"D:\\000.FrontEnd\\242.dino_game","added_dirs":[]},"version":"2.1.71","output_style":{"name":"default"},"cost":{"total_cost_usd":3.1387229999999997,"total_duration_ms":1800053,"total_api_duration_ms":890803,"total_lines_added":356,"total_lines_removed":168},"context_window":{"total_input_tokens":80855,"total_output_tokens":22864,"context_window_size":200000,"current_usage":{"input_tokens":137,"output_tokens":64,"cache_creation_input_tokens":0,"cache_read_input_tokens":86976},"used_percentage":44,"remaining_percentage":56},"exceeds_200k_tokens":false}
|
package/lib/aurabase.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
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/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ES2020", "DOM"],
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"declarationMap": true,
|
|
8
|
-
"sourceMap": true,
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"rootDir": "./src",
|
|
11
|
-
"strict": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"skipLibCheck": true,
|
|
14
|
-
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"moduleResolution": "node",
|
|
16
|
-
"resolveJsonModule": true
|
|
17
|
-
},
|
|
18
|
-
"include": ["src/**/*"],
|
|
19
|
-
"exclude": ["node_modules", "dist"]
|
|
20
|
-
}
|