@freehour/supabase-core 1.0.3 → 1.1.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 +1 -0
- package/dist/data-service.d.ts +4 -53
- package/dist/data-service.d.ts.map +1 -1
- package/dist/data.d.ts +53 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/database.d.ts +2 -10
- package/dist/database.d.ts.map +1 -1
- package/dist/embedding-service.d.ts +49 -0
- package/dist/embedding-service.d.ts.map +1 -0
- package/dist/embedding.d.ts +33 -0
- package/dist/embedding.d.ts.map +1 -0
- package/dist/errors.d.ts +26 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +388 -274
- package/dist/storage-service.d.ts +12 -56
- package/dist/storage-service.d.ts.map +1 -1
- package/dist/storage.d.ts +22 -12
- package/dist/storage.d.ts.map +1 -1
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -1
- package/package.json +2 -1
- package/supabase/schemas/supabase-core/2_extensions.sql +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { assert as
|
|
2
|
-
import
|
|
3
|
-
import { PostgrestError as
|
|
1
|
+
import { assert as l } from "@freehour/assert";
|
|
2
|
+
import m from "zod";
|
|
3
|
+
import { PostgrestError as P } from "@supabase/supabase-js";
|
|
4
|
+
import { Mime as S } from "@freehour/mime";
|
|
4
5
|
class k extends Error {
|
|
5
6
|
constructor(t, e = {}) {
|
|
6
7
|
super(t, e), this.name = this.constructor.name, Error.captureStackTrace(this, this.constructor);
|
|
@@ -21,13 +22,13 @@ class E extends k {
|
|
|
21
22
|
path;
|
|
22
23
|
constructor(t, {
|
|
23
24
|
fileId: e,
|
|
24
|
-
bucket:
|
|
25
|
-
path:
|
|
25
|
+
bucket: r,
|
|
26
|
+
path: a
|
|
26
27
|
} = {}) {
|
|
27
|
-
super(t), this.fileId = e, this.bucket =
|
|
28
|
+
super(t), this.fileId = e, this.bucket = r, this.path = a;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
class
|
|
31
|
+
class x extends k {
|
|
31
32
|
/**
|
|
32
33
|
* The encountered expression that could not be parsed.
|
|
33
34
|
*/
|
|
@@ -36,15 +37,15 @@ class q extends k {
|
|
|
36
37
|
* Additional context about the expected format or structure.
|
|
37
38
|
*/
|
|
38
39
|
format;
|
|
39
|
-
constructor(t
|
|
40
|
+
constructor(t, {
|
|
40
41
|
expression: e,
|
|
41
|
-
format:
|
|
42
|
-
...
|
|
42
|
+
format: r,
|
|
43
|
+
...a
|
|
43
44
|
} = {}) {
|
|
44
|
-
super(t,
|
|
45
|
+
super(t, a), this.expression = e, this.format = r;
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
|
-
class
|
|
48
|
+
class _ extends k {
|
|
48
49
|
/**
|
|
49
50
|
* The schema where the record was expected to be found.
|
|
50
51
|
*/
|
|
@@ -59,33 +60,50 @@ class S extends k {
|
|
|
59
60
|
id;
|
|
60
61
|
constructor(t, {
|
|
61
62
|
schema: e,
|
|
62
|
-
relation:
|
|
63
|
-
id:
|
|
63
|
+
relation: r,
|
|
64
|
+
id: a
|
|
65
|
+
} = {}) {
|
|
66
|
+
super(t), this.schema = e, this.relation = r, this.id = a;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
class I extends Error {
|
|
70
|
+
/**
|
|
71
|
+
* The MIME type that is unsupported.
|
|
72
|
+
*/
|
|
73
|
+
value;
|
|
74
|
+
/**
|
|
75
|
+
* The list of supported MIME types.
|
|
76
|
+
*/
|
|
77
|
+
supported;
|
|
78
|
+
constructor(t, {
|
|
79
|
+
value: e,
|
|
80
|
+
supported: r,
|
|
81
|
+
...a
|
|
64
82
|
} = {}) {
|
|
65
|
-
super(t), this.
|
|
83
|
+
super(t, a), this.value = e, this.supported = r;
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
|
-
const $ =
|
|
69
|
-
code:
|
|
70
|
-
details:
|
|
71
|
-
hint:
|
|
72
|
-
name:
|
|
73
|
-
message:
|
|
86
|
+
const $ = m.object({
|
|
87
|
+
code: m.string(),
|
|
88
|
+
details: m.string().nullable(),
|
|
89
|
+
hint: m.string().nullable(),
|
|
90
|
+
name: m.string().optional(),
|
|
91
|
+
message: m.string().optional()
|
|
74
92
|
});
|
|
75
|
-
function
|
|
76
|
-
return
|
|
93
|
+
function G(s) {
|
|
94
|
+
return s instanceof P || $.safeParse(s).success;
|
|
77
95
|
}
|
|
78
|
-
const
|
|
79
|
-
const e = (
|
|
80
|
-
return
|
|
96
|
+
const v = ["eq", "neq", "gt", "gte", "lt", "lte", "like", "ilike", "match", "imatch", "in", "is", "isdistinct", "fts", "plfts", "phfts", "wfts", "cs", "cd", "ov", "sl", "sr", "nxr", "nxl", "adj"], H = ["and", "or"], J = ",", O = "~", Q = (s) => (t = {}) => {
|
|
97
|
+
const e = (a) => t[a] ?? a, r = Object.keys(s.shape);
|
|
98
|
+
return m.string().transform((a, n) => {
|
|
81
99
|
try {
|
|
82
|
-
return
|
|
100
|
+
return M(a, r, e);
|
|
83
101
|
} catch (i) {
|
|
84
|
-
return
|
|
102
|
+
return n.addIssue({
|
|
85
103
|
code: "custom",
|
|
86
|
-
input:
|
|
104
|
+
input: a,
|
|
87
105
|
message: i instanceof Error ? i.message : void 0,
|
|
88
|
-
params: i instanceof
|
|
106
|
+
params: i instanceof x ? {
|
|
89
107
|
expression: i.expression,
|
|
90
108
|
format: i.format
|
|
91
109
|
} : void 0
|
|
@@ -93,97 +111,101 @@ const I = ["eq", "neq", "gt", "gte", "lt", "lte", "like", "ilike", "match", "ima
|
|
|
93
111
|
}
|
|
94
112
|
});
|
|
95
113
|
};
|
|
96
|
-
function
|
|
97
|
-
return
|
|
114
|
+
function j(s) {
|
|
115
|
+
return s.startsWith("not.") ? s.slice(4) : `not.${s}`;
|
|
98
116
|
}
|
|
99
|
-
function N(
|
|
117
|
+
function N(s) {
|
|
100
118
|
return {
|
|
101
|
-
...
|
|
102
|
-
op:
|
|
119
|
+
...s,
|
|
120
|
+
op: j(s.op)
|
|
103
121
|
};
|
|
104
122
|
}
|
|
105
|
-
function
|
|
106
|
-
if (
|
|
107
|
-
const e =
|
|
108
|
-
return `${
|
|
123
|
+
function q(s, t = (e) => e) {
|
|
124
|
+
if (s.type === "logical") {
|
|
125
|
+
const e = s.args.map((r) => q(r, t));
|
|
126
|
+
return `${s.op}(${e})`;
|
|
109
127
|
}
|
|
110
|
-
return `${t(
|
|
128
|
+
return `${t(s.key)}.${s.op}.${s.value}`;
|
|
111
129
|
}
|
|
112
|
-
function
|
|
113
|
-
return
|
|
130
|
+
function L(s, t = (r) => r, e = O) {
|
|
131
|
+
return s.map((r) => q(r, t)).join(e);
|
|
114
132
|
}
|
|
115
|
-
function
|
|
116
|
-
function
|
|
117
|
-
const
|
|
118
|
-
let
|
|
119
|
-
for (const
|
|
120
|
-
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
if (
|
|
124
|
-
if (
|
|
133
|
+
function y(s, t = [], e = (r) => r) {
|
|
134
|
+
function r(u) {
|
|
135
|
+
const p = [];
|
|
136
|
+
let b = 0, f = "";
|
|
137
|
+
for (const g of u)
|
|
138
|
+
g === "(" ? (b++, f += g) : g === ")" ? (b--, f += g) : g === "," && b === 0 ? (p.push(f.trim()), f = "") : f += g;
|
|
139
|
+
return f && p.push(f.trim()), p;
|
|
140
|
+
}
|
|
141
|
+
if (s.endsWith(")")) {
|
|
142
|
+
if (s.startsWith("and("))
|
|
125
143
|
return {
|
|
126
144
|
type: "logical",
|
|
127
145
|
op: "and",
|
|
128
|
-
args:
|
|
146
|
+
args: r(s.slice(4, -1)).map((u) => y(u, t, e))
|
|
129
147
|
};
|
|
130
|
-
if (
|
|
148
|
+
if (s.startsWith("or("))
|
|
131
149
|
return {
|
|
132
150
|
type: "logical",
|
|
133
151
|
op: "or",
|
|
134
|
-
args:
|
|
152
|
+
args: r(s.slice(3, -1)).map((u) => y(u, t, e))
|
|
135
153
|
};
|
|
136
|
-
if (
|
|
154
|
+
if (s.startsWith("not.and("))
|
|
137
155
|
return {
|
|
138
156
|
type: "logical",
|
|
139
157
|
op: "not.and",
|
|
140
|
-
args:
|
|
158
|
+
args: r(s.slice(8, -1)).map((u) => y(u, t, e))
|
|
141
159
|
};
|
|
142
|
-
if (
|
|
160
|
+
if (s.startsWith("not.or("))
|
|
143
161
|
return {
|
|
144
162
|
type: "logical",
|
|
145
163
|
op: "not.or",
|
|
146
|
-
args:
|
|
164
|
+
args: r(s.slice(7, -1)).map((u) => y(u, t, e))
|
|
147
165
|
};
|
|
148
166
|
}
|
|
149
|
-
const
|
|
167
|
+
const n = `^(${t.length === 0 ? "[a-zA-Z_][a-zA-Z0-9_]*" : t.join("|")})\\.((?:not\\.)?(?:${v.join("|")}))\\.(.+)$`, c = new RegExp(n).exec(s);
|
|
150
168
|
if (!c)
|
|
151
|
-
throw new
|
|
152
|
-
expression:
|
|
169
|
+
throw new x(`Invalid filter expression '${s}'`, {
|
|
170
|
+
expression: s,
|
|
153
171
|
format: {
|
|
154
172
|
syntax: "key.(not.)op.value",
|
|
155
173
|
keys: t.length === 0 ? "*" : t,
|
|
156
|
-
operators:
|
|
174
|
+
operators: v
|
|
157
175
|
}
|
|
158
176
|
});
|
|
159
|
-
const [,
|
|
177
|
+
const [, o, h, d] = c;
|
|
160
178
|
return {
|
|
161
179
|
type: "condition",
|
|
162
|
-
key: e(
|
|
163
|
-
op:
|
|
164
|
-
value:
|
|
180
|
+
key: e(o),
|
|
181
|
+
op: h,
|
|
182
|
+
value: l.defined(d)
|
|
165
183
|
};
|
|
166
184
|
}
|
|
167
|
-
function
|
|
168
|
-
return
|
|
185
|
+
function M(s, t = [], e = (a) => a, r = O) {
|
|
186
|
+
return s.length === 0 ? [] : s.split(r).map((a) => y(a, t, e));
|
|
169
187
|
}
|
|
170
|
-
function
|
|
171
|
-
const e =
|
|
172
|
-
return e === -1 ? ["",
|
|
188
|
+
function A(s, t = "/") {
|
|
189
|
+
const e = s.lastIndexOf(t);
|
|
190
|
+
return e === -1 ? ["", s] : [s.substring(0, e), s.substring(e + 1)];
|
|
173
191
|
}
|
|
174
|
-
function
|
|
175
|
-
return Array.isArray(
|
|
192
|
+
function D(s) {
|
|
193
|
+
return Array.isArray(s) ? s : [s];
|
|
176
194
|
}
|
|
177
|
-
function z(
|
|
178
|
-
return
|
|
179
|
-
const
|
|
180
|
-
return (e[
|
|
195
|
+
function z(s, t) {
|
|
196
|
+
return s.reduce((e, r) => {
|
|
197
|
+
const a = t(r);
|
|
198
|
+
return (e[a] ??= []).push(r), e;
|
|
181
199
|
}, {});
|
|
182
200
|
}
|
|
183
|
-
function T(
|
|
184
|
-
|
|
201
|
+
function T(s, t) {
|
|
202
|
+
const e = s.findIndex(t);
|
|
203
|
+
return e !== -1 && s.splice(e, 1), s;
|
|
185
204
|
}
|
|
186
|
-
|
|
205
|
+
function W(s) {
|
|
206
|
+
return Object.entries(s);
|
|
207
|
+
}
|
|
208
|
+
const w = {
|
|
187
209
|
/**
|
|
188
210
|
* Query extension for PostgREST queries.
|
|
189
211
|
* Supports typesafe column selection and counting.
|
|
@@ -196,7 +218,7 @@ const p = {
|
|
|
196
218
|
* .then(({data}) => console.log(data)); // [{ id: 1, name: 'John' }, ...]
|
|
197
219
|
*/
|
|
198
220
|
query: {
|
|
199
|
-
enable: (
|
|
221
|
+
enable: (s) => Object.assign(s, {
|
|
200
222
|
/**
|
|
201
223
|
* Selects columns from the relation.
|
|
202
224
|
*
|
|
@@ -204,9 +226,9 @@ const p = {
|
|
|
204
226
|
* @param options The options for the selection, such as count.
|
|
205
227
|
* @returns The PostgREST filter builder with selection applied and filter extension enabled.
|
|
206
228
|
*/
|
|
207
|
-
select: (t, e) =>
|
|
208
|
-
|
|
209
|
-
|
|
229
|
+
select: (t, e) => w.filter.enable(
|
|
230
|
+
s.select(
|
|
231
|
+
D(t).join(","),
|
|
210
232
|
e
|
|
211
233
|
)
|
|
212
234
|
),
|
|
@@ -217,8 +239,8 @@ const p = {
|
|
|
217
239
|
* @param method The counting method to use, defaults to 'exact'.
|
|
218
240
|
* @returns The PostgREST filter builder with counting applied and filter extension enabled.
|
|
219
241
|
*/
|
|
220
|
-
count: (t = "exact") =>
|
|
221
|
-
|
|
242
|
+
count: (t = "exact") => w.filter.enable(
|
|
243
|
+
s.select("*", { count: t, head: !0 })
|
|
222
244
|
),
|
|
223
245
|
/**
|
|
224
246
|
* Deletes rows from the relation.
|
|
@@ -226,8 +248,8 @@ const p = {
|
|
|
226
248
|
*
|
|
227
249
|
* @returns The PostgREST filter builder with delete applied and filter extension enabled.
|
|
228
250
|
*/
|
|
229
|
-
delete: () =>
|
|
230
|
-
|
|
251
|
+
delete: () => w.filter.enable(
|
|
252
|
+
s.delete()
|
|
231
253
|
)
|
|
232
254
|
})
|
|
233
255
|
},
|
|
@@ -244,26 +266,26 @@ const p = {
|
|
|
244
266
|
* .collect();
|
|
245
267
|
*/
|
|
246
268
|
filter: {
|
|
247
|
-
enable: (
|
|
269
|
+
enable: (s, t = {}) => Object.assign(s, {
|
|
248
270
|
/**
|
|
249
271
|
* Applies a filter to the query.
|
|
250
272
|
* A filter is defined as an array of AST filter nodes including conditions and logical operators.
|
|
251
273
|
* @param filter The filter to apply.
|
|
252
274
|
*/
|
|
253
|
-
apply: (e) =>
|
|
275
|
+
apply: (e) => w.filter.enable(
|
|
254
276
|
(() => {
|
|
255
|
-
function a
|
|
256
|
-
if (
|
|
257
|
-
const i =
|
|
258
|
-
return
|
|
277
|
+
function r(a, n) {
|
|
278
|
+
if (n.type === "logical") {
|
|
279
|
+
const i = L(n.args, (c) => c, ",");
|
|
280
|
+
return n.op === "or" ? a.or(i) : n.op === "not.or" ? a.or(i, { referencedTable: "not" }) : r(a, {
|
|
259
281
|
type: "logical",
|
|
260
|
-
op:
|
|
261
|
-
args:
|
|
282
|
+
op: n.op === "and" ? "not.or" : "or",
|
|
283
|
+
args: n.args.map(N)
|
|
262
284
|
});
|
|
263
285
|
}
|
|
264
|
-
return
|
|
286
|
+
return a.filter(n.key, n.op, n.value);
|
|
265
287
|
}
|
|
266
|
-
return e.reduce(
|
|
288
|
+
return e.reduce(r, s);
|
|
267
289
|
})(),
|
|
268
290
|
t
|
|
269
291
|
),
|
|
@@ -274,24 +296,24 @@ const p = {
|
|
|
274
296
|
* @param count Optional count of total items, if known.
|
|
275
297
|
* If provided, it will be used to check if the pagination range is valid and resolve to an empty range if not.
|
|
276
298
|
*/
|
|
277
|
-
paginate: (e,
|
|
299
|
+
paginate: (e, r, a) => w.filter.enable(
|
|
278
300
|
(() => {
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
if (
|
|
282
|
-
if (
|
|
283
|
-
return
|
|
284
|
-
if (i >=
|
|
285
|
-
return
|
|
301
|
+
l(e >= 0, "Page index must be ≥ 0"), l(r >= 0, "Page limit must be ≥ 0");
|
|
302
|
+
const n = e * r, i = n + r - 1;
|
|
303
|
+
if (a !== void 0) {
|
|
304
|
+
if (n >= a)
|
|
305
|
+
return s.limit(0);
|
|
306
|
+
if (i >= a)
|
|
307
|
+
return s.range(n, a - 1);
|
|
286
308
|
}
|
|
287
|
-
return
|
|
309
|
+
return s.range(n, i);
|
|
288
310
|
})(),
|
|
289
311
|
{
|
|
290
312
|
...t,
|
|
291
313
|
pagination: {
|
|
292
314
|
page: e,
|
|
293
|
-
limit:
|
|
294
|
-
count:
|
|
315
|
+
limit: r,
|
|
316
|
+
count: a
|
|
295
317
|
}
|
|
296
318
|
}
|
|
297
319
|
),
|
|
@@ -300,13 +322,13 @@ const p = {
|
|
|
300
322
|
* **Note:** For collect to work, paginate() must be called before collect() and the selection must include a `count`.
|
|
301
323
|
* @returns The paginated list of queried items.
|
|
302
324
|
*/
|
|
303
|
-
collect: () =>
|
|
304
|
-
const { data:
|
|
305
|
-
return
|
|
306
|
-
items:
|
|
307
|
-
totalItems:
|
|
308
|
-
page:
|
|
309
|
-
totalPages: Math.ceil(
|
|
325
|
+
collect: () => s.throwOnError().then((e) => {
|
|
326
|
+
const { data: r, count: a } = e, { page: n, limit: i, ...c } = l.defined(t.pagination, "Pagination context is required for collect(). Make sure to call paginate() before collect()"), o = a ?? c.count;
|
|
327
|
+
return l(i > 0, "Page limit must be > 0"), l(Array.isArray(r), "Data must be an array for pagination, make sure to select multiple rows in query"), l(o !== void 0, "Row count is required for pagination, make sure to count in query or pass `count` in paginate()"), {
|
|
328
|
+
items: r,
|
|
329
|
+
totalItems: o,
|
|
330
|
+
page: n,
|
|
331
|
+
totalPages: Math.ceil(o / i),
|
|
310
332
|
limit: i
|
|
311
333
|
};
|
|
312
334
|
})
|
|
@@ -326,12 +348,12 @@ class F {
|
|
|
326
348
|
constructor({
|
|
327
349
|
database: t,
|
|
328
350
|
schema: e,
|
|
329
|
-
relation:
|
|
351
|
+
relation: r
|
|
330
352
|
}) {
|
|
331
|
-
this.database = t, this.schema = e, this.relation =
|
|
353
|
+
this.database = t, this.schema = e, this.relation = r;
|
|
332
354
|
}
|
|
333
355
|
recordNotFoundError(t) {
|
|
334
|
-
return new
|
|
356
|
+
return new _(`Record with id ${t} not found in ${this.schema}.${this.relation}`, {
|
|
335
357
|
schema: this.schema,
|
|
336
358
|
relation: this.relation,
|
|
337
359
|
id: t
|
|
@@ -345,7 +367,7 @@ class F {
|
|
|
345
367
|
*/
|
|
346
368
|
get query() {
|
|
347
369
|
const t = this.database.schema(this.schema).from(this.relation);
|
|
348
|
-
return
|
|
370
|
+
return w.query.enable(t);
|
|
349
371
|
}
|
|
350
372
|
/**
|
|
351
373
|
* Performs a fuzzy search on the specified column of the relation.
|
|
@@ -355,18 +377,18 @@ class F {
|
|
|
355
377
|
async fuzzySearch({
|
|
356
378
|
column: t,
|
|
357
379
|
searchTerm: e = "",
|
|
358
|
-
minSimilarity:
|
|
359
|
-
limit:
|
|
380
|
+
minSimilarity: r = 0,
|
|
381
|
+
limit: a = 64
|
|
360
382
|
}) {
|
|
361
|
-
const { data:
|
|
383
|
+
const { data: n } = await this.database.schema("supabase_core").rpc("fuzzy_search", {
|
|
362
384
|
relation: this.relation,
|
|
363
385
|
schema_name: this.schema,
|
|
364
386
|
column_name: t,
|
|
365
387
|
search_term: e,
|
|
366
|
-
min_similarity:
|
|
367
|
-
limit_results:
|
|
388
|
+
min_similarity: r,
|
|
389
|
+
limit_results: a
|
|
368
390
|
}).throwOnError();
|
|
369
|
-
return
|
|
391
|
+
return n;
|
|
370
392
|
}
|
|
371
393
|
/**
|
|
372
394
|
* List all rows in the relation.
|
|
@@ -385,8 +407,8 @@ class F {
|
|
|
385
407
|
* @throws DatabaseApiError if the query fails.
|
|
386
408
|
*/
|
|
387
409
|
async get(t, e = "*") {
|
|
388
|
-
const { data:
|
|
389
|
-
return
|
|
410
|
+
const { data: r } = await this.query.select(e).eq("id", t).throwOnError();
|
|
411
|
+
return r[0];
|
|
390
412
|
}
|
|
391
413
|
/**
|
|
392
414
|
* Gets a single row by its ID, throwing an error if no such row exists.
|
|
@@ -397,10 +419,10 @@ class F {
|
|
|
397
419
|
* @throws DatabaseApiError if the query fails for any other reason.
|
|
398
420
|
*/
|
|
399
421
|
async getOrThrow(t, e = "*") {
|
|
400
|
-
const
|
|
401
|
-
if (
|
|
422
|
+
const r = await this.get(t, e);
|
|
423
|
+
if (r === void 0)
|
|
402
424
|
throw this.recordNotFoundError(t);
|
|
403
|
-
return
|
|
425
|
+
return r;
|
|
404
426
|
}
|
|
405
427
|
/**
|
|
406
428
|
* Deletes a row from the relation by its ID, i.e. by the `id` column.
|
|
@@ -438,19 +460,18 @@ class F {
|
|
|
438
460
|
/**
|
|
439
461
|
* Inserts or updates a row in the relation.
|
|
440
462
|
* @param insert The data to insert or update in the relation.
|
|
441
|
-
* @param options Options for the upsert operation, such as conflict resolution.
|
|
442
463
|
* @returns The inserted or updated row.
|
|
443
464
|
* @throws DatabaseApiError if the upsert operation fails.
|
|
444
465
|
*/
|
|
445
466
|
async upsert(t, {
|
|
446
467
|
onConflict: e,
|
|
447
|
-
...
|
|
468
|
+
...r
|
|
448
469
|
} = {}) {
|
|
449
|
-
const { data:
|
|
470
|
+
const { data: a } = await this.query.upsert(t, {
|
|
450
471
|
onConflict: e?.join(","),
|
|
451
|
-
...
|
|
472
|
+
...r
|
|
452
473
|
}).select().single().throwOnError();
|
|
453
|
-
return
|
|
474
|
+
return a;
|
|
454
475
|
}
|
|
455
476
|
/**
|
|
456
477
|
* Updates an existing row in the relation by its ID.
|
|
@@ -461,42 +482,42 @@ class F {
|
|
|
461
482
|
* @throws DatabaseApiError if the update fails.
|
|
462
483
|
*/
|
|
463
484
|
async update(t, e) {
|
|
464
|
-
const { data:
|
|
465
|
-
return
|
|
485
|
+
const { data: r } = await this.query.update(e).eq("id", t).select().single().throwOnError();
|
|
486
|
+
return r;
|
|
466
487
|
}
|
|
467
488
|
}
|
|
468
|
-
class
|
|
489
|
+
class C extends F {
|
|
469
490
|
constructor({
|
|
470
491
|
database: t,
|
|
471
492
|
schema: e,
|
|
472
|
-
table:
|
|
493
|
+
table: r
|
|
473
494
|
}) {
|
|
474
495
|
super({
|
|
475
496
|
database: t,
|
|
476
497
|
schema: e,
|
|
477
|
-
relation:
|
|
498
|
+
relation: r
|
|
478
499
|
});
|
|
479
500
|
}
|
|
480
501
|
}
|
|
481
|
-
class
|
|
502
|
+
class U extends F {
|
|
482
503
|
constructor({
|
|
483
504
|
database: t,
|
|
484
505
|
schema: e,
|
|
485
|
-
view:
|
|
506
|
+
view: r
|
|
486
507
|
}) {
|
|
487
508
|
super({
|
|
488
509
|
database: t,
|
|
489
510
|
schema: e,
|
|
490
|
-
relation:
|
|
511
|
+
relation: r
|
|
491
512
|
});
|
|
492
513
|
}
|
|
493
514
|
}
|
|
494
|
-
function
|
|
495
|
-
if (
|
|
496
|
-
throw
|
|
497
|
-
return
|
|
515
|
+
function X(s) {
|
|
516
|
+
if (s.error)
|
|
517
|
+
throw s.error;
|
|
518
|
+
return l(s.count !== null, "Response does not contain a count. Make sure to set the `count` option in the request."), s;
|
|
498
519
|
}
|
|
499
|
-
class
|
|
520
|
+
class Y {
|
|
500
521
|
supabase;
|
|
501
522
|
constructor({ supabase: t }) {
|
|
502
523
|
this.supabase = t;
|
|
@@ -518,39 +539,121 @@ class Q {
|
|
|
518
539
|
});
|
|
519
540
|
}
|
|
520
541
|
table(t, e) {
|
|
521
|
-
return new
|
|
542
|
+
return new C({
|
|
522
543
|
database: this,
|
|
523
544
|
schema: t,
|
|
524
545
|
table: e
|
|
525
546
|
});
|
|
526
547
|
}
|
|
527
548
|
view(t, e) {
|
|
528
|
-
return new
|
|
549
|
+
return new U({
|
|
529
550
|
database: this,
|
|
530
551
|
schema: t,
|
|
531
552
|
view: e
|
|
532
553
|
});
|
|
533
554
|
}
|
|
534
555
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
556
|
+
class K {
|
|
557
|
+
preprocesses = [];
|
|
558
|
+
storage;
|
|
559
|
+
constructor({
|
|
560
|
+
storage: t
|
|
561
|
+
}) {
|
|
562
|
+
this.storage = t;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Retrieves a list of files in the specified bucket that have either no embeddings or embeddings that are outdated.
|
|
566
|
+
* Note: The base implementation of this method is expensive to run.
|
|
567
|
+
* It is recommended to override it with a more efficient implementation (e.g. using pure SQL) if possible.
|
|
568
|
+
*
|
|
569
|
+
* @param bucket The name of the bucket to check for outdated embeddings.
|
|
570
|
+
* @returns A promise that resolves to an array of file references with outdated embeddings.
|
|
571
|
+
*/
|
|
572
|
+
async getOutdatedEmbeddings(t) {
|
|
573
|
+
const e = [];
|
|
574
|
+
let r = !0, a;
|
|
575
|
+
for (; r; ) {
|
|
576
|
+
const { objects: n, ...i } = await this.storage.getFiles(t, { cursor: a }), c = await Promise.all(
|
|
577
|
+
n.map(async (o) => {
|
|
578
|
+
const h = new Date(o.updated_at), d = await this.storage.getFileStorageLocation({ fileId: o.id }), u = await this.getEmbeddings(d);
|
|
579
|
+
return u.length === 0 || u.some((p) => p.createdAt < h);
|
|
580
|
+
})
|
|
581
|
+
);
|
|
582
|
+
e.push(
|
|
583
|
+
...n.filter((o, h) => c[h]).map(({ id: o }) => ({ fileId: o }))
|
|
584
|
+
), { hasNext: r, nextCursor: a } = i;
|
|
550
585
|
}
|
|
551
|
-
|
|
586
|
+
return e;
|
|
587
|
+
}
|
|
588
|
+
preprocess(t, e) {
|
|
589
|
+
return this.preprocesses.forEach((r) => {
|
|
590
|
+
t = r.run(t, e);
|
|
591
|
+
}), t;
|
|
592
|
+
}
|
|
593
|
+
addPreprocessingStep(t) {
|
|
594
|
+
return this.preprocesses.push(t), this;
|
|
595
|
+
}
|
|
596
|
+
removePreprocessingStep(t) {
|
|
597
|
+
return T(this.preprocesses, (e) => e.name === t), this;
|
|
598
|
+
}
|
|
599
|
+
async get(t) {
|
|
600
|
+
const e = await this.storage.getFileStorageLocation(t);
|
|
601
|
+
return this.getEmbeddings(e);
|
|
602
|
+
}
|
|
603
|
+
async ingest(t, e) {
|
|
604
|
+
const { file: r, ...a } = await this.storage.downloadFile(t), n = S.parse(r.type);
|
|
605
|
+
if (n.type !== "text")
|
|
606
|
+
throw new I(`Unsupported file type: ${n}. Only text files can be embedded.`);
|
|
607
|
+
await this.deleteEmbeddings(a);
|
|
608
|
+
const i = {
|
|
609
|
+
name: r.name,
|
|
610
|
+
type: r.type,
|
|
611
|
+
size: r.size,
|
|
612
|
+
...a,
|
|
613
|
+
...typeof e == "function" ? e(r, a) : e
|
|
614
|
+
}, c = this.preprocess(await r.text(), i);
|
|
615
|
+
return this.createEmbeddings(a, c, i);
|
|
616
|
+
}
|
|
617
|
+
async synchronize(t, e) {
|
|
618
|
+
const r = await this.getOutdatedEmbeddings(t);
|
|
619
|
+
return (await Promise.all(
|
|
620
|
+
r.map(
|
|
621
|
+
async (n) => this.ingest(n, e).then(() => ({
|
|
622
|
+
file: n,
|
|
623
|
+
success: !0,
|
|
624
|
+
error: null
|
|
625
|
+
})).catch((i) => i instanceof I ? null : {
|
|
626
|
+
file: n,
|
|
627
|
+
error: i,
|
|
628
|
+
success: !1
|
|
629
|
+
})
|
|
630
|
+
)
|
|
631
|
+
)).filter((n) => n !== null);
|
|
632
|
+
}
|
|
552
633
|
}
|
|
553
|
-
|
|
634
|
+
const tt = {
|
|
635
|
+
removeImagesFromMarkdown: {
|
|
636
|
+
name: "removeImagesFromMarkdown",
|
|
637
|
+
run(s, t) {
|
|
638
|
+
if (t.type === "text/markdown") {
|
|
639
|
+
const e = /!\[([^\]]*)\]\([^)]*\)/g;
|
|
640
|
+
return s.replace(e, (r, a) => `![${a}]()`);
|
|
641
|
+
}
|
|
642
|
+
return s;
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
removeLinksFromMarkdown: {
|
|
646
|
+
name: "removeLinksFromMarkdown",
|
|
647
|
+
run(s, t) {
|
|
648
|
+
if (t.type === "text/markdown") {
|
|
649
|
+
const e = /\[([^\]]*)\]\([^)]*\)/g;
|
|
650
|
+
return s.replace(e, (r, a) => `[${a}]()`);
|
|
651
|
+
}
|
|
652
|
+
return s;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
class et {
|
|
554
657
|
client;
|
|
555
658
|
database;
|
|
556
659
|
constructor({
|
|
@@ -562,134 +665,145 @@ class X {
|
|
|
562
665
|
get files() {
|
|
563
666
|
return this.database.table("storage", "objects");
|
|
564
667
|
}
|
|
565
|
-
async
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
668
|
+
async getFileObject(t, e) {
|
|
669
|
+
const { data: r, error: a } = await this.client.from(t).info(e);
|
|
670
|
+
if (a)
|
|
671
|
+
throw a;
|
|
672
|
+
return r;
|
|
673
|
+
}
|
|
674
|
+
async getFiles(t, e) {
|
|
675
|
+
const { data: r, error: a } = await this.client.from(t).listV2(e);
|
|
676
|
+
if (a)
|
|
677
|
+
throw a;
|
|
678
|
+
return r;
|
|
679
|
+
}
|
|
680
|
+
async getFileStorageLocation(t) {
|
|
681
|
+
if ("fileId" in t) {
|
|
682
|
+
const { fileId: n } = t, i = await this.files.get(n, ["bucket_id", "path_tokens"]);
|
|
683
|
+
if (!i)
|
|
684
|
+
throw new E(`File with ID ${n} not found`, { fileId: n });
|
|
685
|
+
return {
|
|
686
|
+
fileId: n,
|
|
687
|
+
bucket: l.notNull(i.bucket_id, "bucket_id must not be null"),
|
|
688
|
+
path: l.notNull(i.path_tokens, "path_tokens must not be null").join("/")
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
const { bucket: e, path: r } = t, { id: a } = await this.getFileObject(e, r);
|
|
692
|
+
return { fileId: a, bucket: e, path: r };
|
|
693
|
+
}
|
|
694
|
+
async getFileInfo(t) {
|
|
695
|
+
const { fileId: e, bucket: r, path: a } = await this.getFileStorageLocation(t), { id: n, bucketId: i, metadata: c, ...o } = await this.getFileObject(r, a);
|
|
696
|
+
return l(n === e, "file ID from storage client must match file ID from database"), l(i === r, "bucketId from storage client must match bucket from database"), {
|
|
697
|
+
...o,
|
|
698
|
+
fileId: e,
|
|
699
|
+
bucket: r,
|
|
700
|
+
path: a,
|
|
701
|
+
metadata: c,
|
|
702
|
+
properties: c ? {
|
|
703
|
+
type: c.mimetype,
|
|
704
|
+
lastModified: new Date(c.lastModified).getTime()
|
|
705
|
+
} : {}
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
async getPublicURL(t, e) {
|
|
709
|
+
const { bucket: r, path: a } = await this.getFileStorageLocation(t), { data: { publicUrl: n } } = this.client.from(r).getPublicUrl(a, e);
|
|
710
|
+
return n;
|
|
711
|
+
}
|
|
712
|
+
async existsFile(t) {
|
|
713
|
+
const { bucket: e, path: r } = await this.getFileStorageLocation(t), { data: a, error: n } = await this.client.from(e).exists(r);
|
|
714
|
+
if (n)
|
|
715
|
+
throw n;
|
|
716
|
+
return a;
|
|
717
|
+
}
|
|
718
|
+
async assertExistsFile(t) {
|
|
719
|
+
const { bucket: e, path: r } = await this.getFileStorageLocation(t), { data: a, error: n } = await this.client.from(e).exists(r);
|
|
720
|
+
if (n)
|
|
721
|
+
throw n;
|
|
722
|
+
if (!a)
|
|
723
|
+
throw new E(`File not found in bucket '${e}' at path '${r}'`, { bucket: e, path: r });
|
|
724
|
+
}
|
|
725
|
+
async uploadFile(t, { bucket: e, path: r }, { overwriteExisting: a = !1 } = {}) {
|
|
726
|
+
const { data: n, error: i } = await this.client.from(e).upload(
|
|
727
|
+
`${r}/${t.name}`,
|
|
728
|
+
t,
|
|
574
729
|
{
|
|
575
|
-
upsert:
|
|
730
|
+
upsert: a
|
|
576
731
|
}
|
|
577
732
|
);
|
|
578
733
|
if (i)
|
|
579
734
|
throw i;
|
|
580
735
|
return {
|
|
581
|
-
|
|
582
|
-
bucket:
|
|
583
|
-
path:
|
|
736
|
+
fileId: n.id,
|
|
737
|
+
bucket: e,
|
|
738
|
+
path: n.path
|
|
584
739
|
};
|
|
585
740
|
}
|
|
586
741
|
async downloadFile(t) {
|
|
587
|
-
const {
|
|
588
|
-
if (
|
|
589
|
-
throw
|
|
590
|
-
const [,
|
|
591
|
-
return
|
|
742
|
+
const { fileId: e, bucket: r, path: a, properties: n } = await this.getFileInfo(t), { data: i, error: c } = await this.client.from(r).download(a);
|
|
743
|
+
if (c)
|
|
744
|
+
throw c;
|
|
745
|
+
const [, o] = A(a);
|
|
746
|
+
return {
|
|
747
|
+
fileId: e,
|
|
748
|
+
bucket: r,
|
|
749
|
+
path: a,
|
|
750
|
+
file: new File([i], o, n)
|
|
751
|
+
};
|
|
592
752
|
}
|
|
593
753
|
async deleteFiles(t) {
|
|
594
|
-
const e = "
|
|
595
|
-
bucket:
|
|
596
|
-
|
|
597
|
-
}))
|
|
598
|
-
z(
|
|
599
|
-
).map(([
|
|
600
|
-
bucket:
|
|
601
|
-
paths:
|
|
602
|
-
}))
|
|
603
|
-
return (await Promise.all(
|
|
604
|
-
async ({ bucket:
|
|
754
|
+
const e = t.filter((o) => "fileId" in o).map((o) => o.fileId), a = (await this.files.query.select(["bucket_id", "path_tokens"]).containedBy("id", e).throwOnError()).data.map(({ bucket_id: o, path_tokens: h }) => ({
|
|
755
|
+
bucket: l.notNull(o, "bucket_id must not be null"),
|
|
756
|
+
path: l.notNull(h, "path_tokens must not be null").join("/")
|
|
757
|
+
})), n = t.filter((o) => "path" in o).concat(a), i = W(
|
|
758
|
+
z(n, (o) => o.bucket)
|
|
759
|
+
).map(([o, h]) => ({
|
|
760
|
+
bucket: o,
|
|
761
|
+
paths: h.map((d) => d.path)
|
|
762
|
+
}));
|
|
763
|
+
return (await Promise.all(i.map(
|
|
764
|
+
async ({ bucket: o, paths: h }) => this.client.from(o).remove(h).then(({ data: d, error: u }) => {
|
|
605
765
|
if (u)
|
|
606
766
|
throw u;
|
|
607
|
-
return
|
|
608
|
-
|
|
609
|
-
bucket:
|
|
610
|
-
path:
|
|
767
|
+
return d.map((p, b) => ({
|
|
768
|
+
fileId: l.notNull(p.id, "file id must not be null"),
|
|
769
|
+
bucket: o,
|
|
770
|
+
path: l.defined(h[b], "path must not be null")
|
|
611
771
|
}));
|
|
612
772
|
})
|
|
613
773
|
))).flat();
|
|
614
774
|
}
|
|
615
|
-
async existsFile(t) {
|
|
616
|
-
const { bucket: e, path: a } = "fileId" in t ? await this.getFileStorageInfo(t.fileId) : t, { data: n, error: s } = await this.client.from(e).exists(a);
|
|
617
|
-
if (s)
|
|
618
|
-
throw s;
|
|
619
|
-
return n;
|
|
620
|
-
}
|
|
621
|
-
async assertExistsFile(t) {
|
|
622
|
-
const { bucket: e, path: a } = "fileId" in t ? await this.getFileStorageInfo(t.fileId) : t, { data: n, error: s } = await this.client.from(e).exists(a);
|
|
623
|
-
if (s)
|
|
624
|
-
throw s;
|
|
625
|
-
if (!n)
|
|
626
|
-
throw new E(`File not found in bucket '${e}' at path '${a}'`, { bucket: e, path: a });
|
|
627
|
-
}
|
|
628
|
-
async getFiles({
|
|
629
|
-
bucket: t,
|
|
630
|
-
...e
|
|
631
|
-
}) {
|
|
632
|
-
const { data: a, error: n } = await this.client.from(t).listV2(e);
|
|
633
|
-
if (n)
|
|
634
|
-
throw n;
|
|
635
|
-
return a;
|
|
636
|
-
}
|
|
637
|
-
async getFileStorageInfo(t) {
|
|
638
|
-
const e = await this.files.get(t, ["bucket_id", "path_tokens", "metadata"]);
|
|
639
|
-
if (!e)
|
|
640
|
-
throw new E(`File with ID ${t} not found`, { fileId: t });
|
|
641
|
-
return B({
|
|
642
|
-
id: t,
|
|
643
|
-
...e
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
async getFileInfo(t) {
|
|
647
|
-
const { bucket: e, path: a } = "fileId" in t ? await this.getFileStorageInfo(t.fileId) : t, { data: n, error: s } = await this.client.from(e).info(a);
|
|
648
|
-
if (s)
|
|
649
|
-
throw s;
|
|
650
|
-
return n;
|
|
651
|
-
}
|
|
652
|
-
async getPublicURL({
|
|
653
|
-
transform: t,
|
|
654
|
-
download: e,
|
|
655
|
-
...a
|
|
656
|
-
}) {
|
|
657
|
-
const { bucket: n, path: s } = "fileId" in a ? await this.getFileStorageInfo(a.fileId) : a, { data: { publicUrl: i } } = this.client.from(n).getPublicUrl(s, {
|
|
658
|
-
transform: t,
|
|
659
|
-
download: e
|
|
660
|
-
});
|
|
661
|
-
return i;
|
|
662
|
-
}
|
|
663
775
|
}
|
|
664
776
|
export {
|
|
665
777
|
F as DataService,
|
|
666
|
-
|
|
778
|
+
Y as DatabaseService,
|
|
779
|
+
K as EmbeddingService,
|
|
667
780
|
E as FileNotFoundError,
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
781
|
+
Q as Filter,
|
|
782
|
+
O as FilterChainSeparator,
|
|
783
|
+
v as FilterOp,
|
|
784
|
+
H as LogicalOp,
|
|
785
|
+
J as LogicalOpSeparator,
|
|
786
|
+
x as ParseError,
|
|
674
787
|
$ as PostgrestErrorInterface,
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
788
|
+
_ as RecordNotFoundError,
|
|
789
|
+
et as StorageService,
|
|
790
|
+
C as TableDataService,
|
|
678
791
|
k as TracedError,
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
792
|
+
I as UnsupportedMimeError,
|
|
793
|
+
U as ViewDataService,
|
|
794
|
+
X as assertCounted,
|
|
795
|
+
D as coerceArray,
|
|
796
|
+
L as encodeFilter,
|
|
797
|
+
q as encodeFilterNode,
|
|
798
|
+
W as entries,
|
|
685
799
|
z as groupBy,
|
|
686
|
-
|
|
800
|
+
G as isDatabaseApiError,
|
|
687
801
|
N as negateFilterNode,
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
802
|
+
j as negateOp,
|
|
803
|
+
y as parseFilterExpression,
|
|
804
|
+
M as parseFilterExpressionChain,
|
|
805
|
+
w as postgrestExtensions,
|
|
806
|
+
tt as preprocessingSteps,
|
|
807
|
+
T as removeElement,
|
|
808
|
+
A as splitPath
|
|
695
809
|
};
|