@freehour/supabase-core 1.0.3 → 1.1.0
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/database.d.ts +2 -10
- package/dist/database.d.ts.map +1 -1
- package/dist/embedding-service.d.ts +53 -0
- package/dist/embedding-service.d.ts.map +1 -0
- package/dist/embedding.d.ts +32 -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 +385 -251
- package/dist/storage-service.d.ts +10 -27
- package/dist/storage-service.d.ts.map +1 -1
- package/dist/storage.d.ts +10 -7
- 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 +2 -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 p from "zod";
|
|
3
|
+
import { PostgrestError as $ } from "@supabase/supabase-js";
|
|
4
|
+
import { Mime as q } 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 P 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 j = p.object({
|
|
87
|
+
code: p.string(),
|
|
88
|
+
details: p.string().nullable(),
|
|
89
|
+
hint: p.string().nullable(),
|
|
90
|
+
name: p.string().optional(),
|
|
91
|
+
message: p.string().optional()
|
|
74
92
|
});
|
|
75
|
-
function
|
|
76
|
-
return
|
|
93
|
+
function G(s) {
|
|
94
|
+
return s instanceof $ || j.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 p.string().transform((a, n) => {
|
|
81
99
|
try {
|
|
82
|
-
return A(
|
|
100
|
+
return A(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 N(s) {
|
|
115
|
+
return s.startsWith("not.") ? s.slice(4) : `not.${s}`;
|
|
98
116
|
}
|
|
99
|
-
function
|
|
117
|
+
function L(s) {
|
|
100
118
|
return {
|
|
101
|
-
...
|
|
102
|
-
op:
|
|
119
|
+
...s,
|
|
120
|
+
op: N(s.op)
|
|
103
121
|
};
|
|
104
122
|
}
|
|
105
|
-
function
|
|
106
|
-
if (
|
|
107
|
-
const e =
|
|
108
|
-
return `${
|
|
123
|
+
function S(s, t = (e) => e) {
|
|
124
|
+
if (s.type === "logical") {
|
|
125
|
+
const e = s.args.map((r) => S(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 M(s, t = (r) => r, e = O) {
|
|
131
|
+
return s.map((r) => S(r, t)).join(e);
|
|
114
132
|
}
|
|
115
|
-
function
|
|
116
|
-
function
|
|
117
|
-
const
|
|
118
|
-
let y = 0,
|
|
119
|
-
for (const f of
|
|
120
|
-
f === "(" ? (y++,
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
if (
|
|
124
|
-
if (
|
|
133
|
+
function b(s, t = [], e = (r) => r) {
|
|
134
|
+
function r(u) {
|
|
135
|
+
const w = [];
|
|
136
|
+
let y = 0, d = "";
|
|
137
|
+
for (const f of u)
|
|
138
|
+
f === "(" ? (y++, d += f) : f === ")" ? (y--, d += f) : f === "," && y === 0 ? (w.push(d.trim()), d = "") : d += f;
|
|
139
|
+
return d && w.push(d.trim()), w;
|
|
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) => b(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) => b(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) => b(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) => b(u, t, e))
|
|
147
165
|
};
|
|
148
166
|
}
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
151
|
-
throw new
|
|
152
|
-
expression:
|
|
167
|
+
const n = `^(${t.length === 0 ? "[a-zA-Z_][a-zA-Z0-9_]*" : t.join("|")})\\.((?:not\\.)?(?:${v.join("|")}))\\.(.+)$`, o = new RegExp(n).exec(s);
|
|
168
|
+
if (!o)
|
|
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 [, c, h, g] = o;
|
|
160
178
|
return {
|
|
161
179
|
type: "condition",
|
|
162
|
-
key: e(
|
|
163
|
-
op:
|
|
164
|
-
value:
|
|
180
|
+
key: e(c),
|
|
181
|
+
op: h,
|
|
182
|
+
value: l.defined(g)
|
|
165
183
|
};
|
|
166
184
|
}
|
|
167
|
-
function A(
|
|
168
|
-
return
|
|
185
|
+
function A(s, t = [], e = (a) => a, r = O) {
|
|
186
|
+
return s.length === 0 ? [] : s.split(r).map((a) => b(a, t, e));
|
|
169
187
|
}
|
|
170
|
-
function D(
|
|
171
|
-
const e =
|
|
172
|
-
return e === -1 ? ["",
|
|
188
|
+
function D(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 _(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;
|
|
204
|
+
}
|
|
205
|
+
function W(s) {
|
|
206
|
+
return Object.entries(s);
|
|
185
207
|
}
|
|
186
|
-
const
|
|
208
|
+
const m = {
|
|
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) => m.filter.enable(
|
|
230
|
+
s.select(
|
|
231
|
+
_(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") => m.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: () => m.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) => m.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 = M(n.args, (o) => o, ",");
|
|
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(L)
|
|
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) => m.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, ...o } = l.defined(t.pagination, "Pagination context is required for collect(). Make sure to call paginate() before collect()"), c = a ?? o.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(c !== void 0, "Row count is required for pagination, make sure to count in query or pass `count` in paginate()"), {
|
|
328
|
+
items: r,
|
|
329
|
+
totalItems: c,
|
|
330
|
+
page: n,
|
|
331
|
+
totalPages: Math.ceil(c / 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 P(`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 m.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.
|
|
@@ -444,13 +466,13 @@ class F {
|
|
|
444
466
|
*/
|
|
445
467
|
async upsert(t, {
|
|
446
468
|
onConflict: e,
|
|
447
|
-
...
|
|
469
|
+
...r
|
|
448
470
|
} = {}) {
|
|
449
|
-
const { data:
|
|
471
|
+
const { data: a } = await this.query.upsert(t, {
|
|
450
472
|
onConflict: e?.join(","),
|
|
451
|
-
...
|
|
473
|
+
...r
|
|
452
474
|
}).select().single().throwOnError();
|
|
453
|
-
return
|
|
475
|
+
return a;
|
|
454
476
|
}
|
|
455
477
|
/**
|
|
456
478
|
* Updates an existing row in the relation by its ID.
|
|
@@ -461,42 +483,42 @@ class F {
|
|
|
461
483
|
* @throws DatabaseApiError if the update fails.
|
|
462
484
|
*/
|
|
463
485
|
async update(t, e) {
|
|
464
|
-
const { data:
|
|
465
|
-
return
|
|
486
|
+
const { data: r } = await this.query.update(e).eq("id", t).select().single().throwOnError();
|
|
487
|
+
return r;
|
|
466
488
|
}
|
|
467
489
|
}
|
|
468
|
-
class
|
|
490
|
+
class C extends F {
|
|
469
491
|
constructor({
|
|
470
492
|
database: t,
|
|
471
493
|
schema: e,
|
|
472
|
-
table:
|
|
494
|
+
table: r
|
|
473
495
|
}) {
|
|
474
496
|
super({
|
|
475
497
|
database: t,
|
|
476
498
|
schema: e,
|
|
477
|
-
relation:
|
|
499
|
+
relation: r
|
|
478
500
|
});
|
|
479
501
|
}
|
|
480
502
|
}
|
|
481
|
-
class
|
|
503
|
+
class U extends F {
|
|
482
504
|
constructor({
|
|
483
505
|
database: t,
|
|
484
506
|
schema: e,
|
|
485
|
-
view:
|
|
507
|
+
view: r
|
|
486
508
|
}) {
|
|
487
509
|
super({
|
|
488
510
|
database: t,
|
|
489
511
|
schema: e,
|
|
490
|
-
relation:
|
|
512
|
+
relation: r
|
|
491
513
|
});
|
|
492
514
|
}
|
|
493
515
|
}
|
|
494
|
-
function
|
|
495
|
-
if (
|
|
496
|
-
throw
|
|
497
|
-
return
|
|
516
|
+
function X(s) {
|
|
517
|
+
if (s.error)
|
|
518
|
+
throw s.error;
|
|
519
|
+
return l(s.count !== null, "Response does not contain a count. Make sure to set the `count` option in the request."), s;
|
|
498
520
|
}
|
|
499
|
-
class
|
|
521
|
+
class Y {
|
|
500
522
|
supabase;
|
|
501
523
|
constructor({ supabase: t }) {
|
|
502
524
|
this.supabase = t;
|
|
@@ -518,39 +540,125 @@ class Q {
|
|
|
518
540
|
});
|
|
519
541
|
}
|
|
520
542
|
table(t, e) {
|
|
521
|
-
return new
|
|
543
|
+
return new C({
|
|
522
544
|
database: this,
|
|
523
545
|
schema: t,
|
|
524
546
|
table: e
|
|
525
547
|
});
|
|
526
548
|
}
|
|
527
549
|
view(t, e) {
|
|
528
|
-
return new
|
|
550
|
+
return new U({
|
|
529
551
|
database: this,
|
|
530
552
|
schema: t,
|
|
531
553
|
view: e
|
|
532
554
|
});
|
|
533
555
|
}
|
|
534
556
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
557
|
+
class K {
|
|
558
|
+
preprocesses = [];
|
|
559
|
+
storage;
|
|
560
|
+
constructor(t) {
|
|
561
|
+
this.storage = t;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Retrieves a list of files in the specified bucket that have either no embeddings or embeddings that are outdated.
|
|
565
|
+
* Note: The base implementation of this method is expensive to run.
|
|
566
|
+
* It is recommended to override it with a more efficient implementation (e.g. using pure SQL) if possible.
|
|
567
|
+
*
|
|
568
|
+
* @param bucket The name of the bucket to check for outdated embeddings.
|
|
569
|
+
* @returns A promise that resolves to an array of file references with outdated embeddings.
|
|
570
|
+
*/
|
|
571
|
+
async getOutdatedEmbeddings(t) {
|
|
572
|
+
const e = [];
|
|
573
|
+
let r = !0, a;
|
|
574
|
+
for (; r; ) {
|
|
575
|
+
const { objects: n, ...i } = await this.storage.getFiles({
|
|
576
|
+
bucket: t,
|
|
577
|
+
cursor: a
|
|
578
|
+
}), o = await Promise.all(
|
|
579
|
+
n.map(async (c) => {
|
|
580
|
+
const h = new Date(c.updated_at), g = await this.storage.getFileStorageLocation({ fileId: c.id }), u = await this.getEmbeddings(g);
|
|
581
|
+
return u.length === 0 || u.some((w) => w.createdAt < h);
|
|
582
|
+
})
|
|
583
|
+
);
|
|
584
|
+
e.push(
|
|
585
|
+
...n.filter((c, h) => o[h]).map(({ id: c }) => ({ fileId: c }))
|
|
586
|
+
), { hasNext: r, nextCursor: a } = i;
|
|
550
587
|
}
|
|
551
|
-
|
|
588
|
+
return e;
|
|
589
|
+
}
|
|
590
|
+
preprocess(t, e) {
|
|
591
|
+
return this.preprocesses.forEach((r) => {
|
|
592
|
+
t = r.run(t, e);
|
|
593
|
+
}), t;
|
|
594
|
+
}
|
|
595
|
+
addPreprocessingStep(t) {
|
|
596
|
+
return this.preprocesses.push(t), this;
|
|
597
|
+
}
|
|
598
|
+
removePreprocessingStep(t) {
|
|
599
|
+
return T(this.preprocesses, (e) => e.name === t), this;
|
|
600
|
+
}
|
|
601
|
+
async get(t) {
|
|
602
|
+
const e = await this.storage.getFileStorageLocation(t);
|
|
603
|
+
return this.getEmbeddings(e);
|
|
604
|
+
}
|
|
605
|
+
async ingest(t) {
|
|
606
|
+
const { file: e, ...r } = await this.storage.downloadFile(t), a = q.parse(e.type);
|
|
607
|
+
if (a.type !== "text")
|
|
608
|
+
throw new I(`Unsupported file type: ${a}. Only text files can be embedded.`);
|
|
609
|
+
await this.deleteEmbeddings(r);
|
|
610
|
+
const n = {
|
|
611
|
+
name: e.name,
|
|
612
|
+
type: e.type,
|
|
613
|
+
size: e.size,
|
|
614
|
+
...r,
|
|
615
|
+
...typeof t.metadata == "function" ? t.metadata(e, r) : t.metadata
|
|
616
|
+
}, i = this.preprocess(await e.text(), n);
|
|
617
|
+
return this.createEmbeddings(r, i, n);
|
|
618
|
+
}
|
|
619
|
+
async synchronize({
|
|
620
|
+
bucket: t,
|
|
621
|
+
metadata: e
|
|
622
|
+
}) {
|
|
623
|
+
const r = await this.getOutdatedEmbeddings(t);
|
|
624
|
+
return (await Promise.all(
|
|
625
|
+
r.map(
|
|
626
|
+
async (n) => this.ingest({ ...n, metadata: e }).then(() => ({
|
|
627
|
+
file: n,
|
|
628
|
+
success: !0,
|
|
629
|
+
error: null
|
|
630
|
+
})).catch((i) => i instanceof I ? null : {
|
|
631
|
+
file: n,
|
|
632
|
+
error: i,
|
|
633
|
+
success: !1
|
|
634
|
+
})
|
|
635
|
+
)
|
|
636
|
+
)).filter((n) => n !== null);
|
|
637
|
+
}
|
|
552
638
|
}
|
|
553
|
-
|
|
639
|
+
const tt = {
|
|
640
|
+
removeImagesFromMarkdown: {
|
|
641
|
+
name: "removeImagesFromMarkdown",
|
|
642
|
+
run(s, t) {
|
|
643
|
+
if (t.type === "text/markdown") {
|
|
644
|
+
const e = /!\[([^\]]*)\]\([^)]*\)/g;
|
|
645
|
+
return s.replace(e, (r, a) => `![${a}]()`);
|
|
646
|
+
}
|
|
647
|
+
return s;
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
removeLinksFromMarkdown: {
|
|
651
|
+
name: "removeLinksFromMarkdown",
|
|
652
|
+
run(s, t) {
|
|
653
|
+
if (t.type === "text/markdown") {
|
|
654
|
+
const e = /\[([^\]]*)\]\([^)]*\)/g;
|
|
655
|
+
return s.replace(e, (r, a) => `[${a}]()`);
|
|
656
|
+
}
|
|
657
|
+
return s;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
class et {
|
|
554
662
|
client;
|
|
555
663
|
database;
|
|
556
664
|
constructor({
|
|
@@ -562,99 +670,123 @@ class X {
|
|
|
562
670
|
get files() {
|
|
563
671
|
return this.database.table("storage", "objects");
|
|
564
672
|
}
|
|
673
|
+
async getFileObject(t, e) {
|
|
674
|
+
const { data: r, error: a } = await this.client.from(t).info(e);
|
|
675
|
+
if (a)
|
|
676
|
+
throw a;
|
|
677
|
+
return r;
|
|
678
|
+
}
|
|
565
679
|
async uploadFile({
|
|
566
680
|
bucket: t,
|
|
567
681
|
path: e,
|
|
568
|
-
file:
|
|
569
|
-
overwriteExisting:
|
|
682
|
+
file: r,
|
|
683
|
+
overwriteExisting: a = !1
|
|
570
684
|
}) {
|
|
571
|
-
const { data:
|
|
572
|
-
`${e}/${
|
|
573
|
-
|
|
685
|
+
const { data: n, error: i } = await this.client.from(t).upload(
|
|
686
|
+
`${e}/${r.name}`,
|
|
687
|
+
r,
|
|
574
688
|
{
|
|
575
|
-
upsert:
|
|
689
|
+
upsert: a
|
|
576
690
|
}
|
|
577
691
|
);
|
|
578
692
|
if (i)
|
|
579
693
|
throw i;
|
|
580
694
|
return {
|
|
581
|
-
|
|
695
|
+
fileId: n.id,
|
|
582
696
|
bucket: t,
|
|
583
|
-
path:
|
|
697
|
+
path: n.path
|
|
584
698
|
};
|
|
585
699
|
}
|
|
586
700
|
async downloadFile(t) {
|
|
587
|
-
const {
|
|
588
|
-
if (
|
|
589
|
-
throw
|
|
701
|
+
const { fileId: e, bucket: r, path: a, properties: n } = await this.getFileInfo(t), { data: i, error: o } = await this.client.from(r).download(a);
|
|
702
|
+
if (o)
|
|
703
|
+
throw o;
|
|
590
704
|
const [, c] = D(a);
|
|
591
|
-
return
|
|
705
|
+
return {
|
|
706
|
+
fileId: e,
|
|
707
|
+
bucket: r,
|
|
708
|
+
path: a,
|
|
709
|
+
file: new File([i], c, n)
|
|
710
|
+
};
|
|
592
711
|
}
|
|
593
712
|
async deleteFiles(t) {
|
|
594
|
-
const e = "fileIds" in t ? (await this.files.query.select(["bucket_id", "path_tokens"]).containedBy("id", t.fileIds).throwOnError()).data.map(({ bucket_id:
|
|
595
|
-
bucket:
|
|
596
|
-
paths:
|
|
597
|
-
})) :
|
|
598
|
-
z(e, (
|
|
599
|
-
).map(([
|
|
600
|
-
bucket:
|
|
601
|
-
paths: i.flatMap((
|
|
602
|
-
})).filter(({ paths:
|
|
603
|
-
return (await Promise.all(
|
|
604
|
-
async ({ bucket:
|
|
605
|
-
if (
|
|
606
|
-
throw
|
|
607
|
-
return
|
|
608
|
-
|
|
609
|
-
bucket:
|
|
610
|
-
path:
|
|
713
|
+
const e = "fileIds" in t ? (await this.files.query.select(["bucket_id", "path_tokens"]).containedBy("id", t.fileIds).throwOnError()).data.map(({ bucket_id: n, path_tokens: i }) => ({
|
|
714
|
+
bucket: l.notNull(n, "bucket_id must not be null"),
|
|
715
|
+
paths: l.notNull(i, "path_tokens must not be null").join("/")
|
|
716
|
+
})) : _(t), r = W(
|
|
717
|
+
z(e, (n) => n.bucket)
|
|
718
|
+
).map(([n, i]) => ({
|
|
719
|
+
bucket: n,
|
|
720
|
+
paths: i.flatMap((o) => o.paths)
|
|
721
|
+
})).filter(({ paths: n }) => n.length > 0);
|
|
722
|
+
return (await Promise.all(r.map(
|
|
723
|
+
async ({ bucket: n, paths: i }) => this.client.from(n).remove(i).then(({ data: o, error: c }) => {
|
|
724
|
+
if (c)
|
|
725
|
+
throw c;
|
|
726
|
+
return o.map((h, g) => ({
|
|
727
|
+
fileId: l.notNull(h.id, "file id must not be null"),
|
|
728
|
+
bucket: n,
|
|
729
|
+
path: l.defined(i[g])
|
|
611
730
|
}));
|
|
612
731
|
})
|
|
613
732
|
))).flat();
|
|
614
733
|
}
|
|
615
734
|
async existsFile(t) {
|
|
616
|
-
const { bucket: e, path:
|
|
617
|
-
if (
|
|
618
|
-
throw
|
|
619
|
-
return
|
|
735
|
+
const { bucket: e, path: r } = await this.getFileStorageLocation(t), { data: a, error: n } = await this.client.from(e).exists(r);
|
|
736
|
+
if (n)
|
|
737
|
+
throw n;
|
|
738
|
+
return a;
|
|
620
739
|
}
|
|
621
740
|
async assertExistsFile(t) {
|
|
622
|
-
const { bucket: e, path:
|
|
623
|
-
if (
|
|
624
|
-
throw
|
|
625
|
-
if (!
|
|
626
|
-
throw new E(`File not found in bucket '${e}' at path '${
|
|
741
|
+
const { bucket: e, path: r } = await this.getFileStorageLocation(t), { data: a, error: n } = await this.client.from(e).exists(r);
|
|
742
|
+
if (n)
|
|
743
|
+
throw n;
|
|
744
|
+
if (!a)
|
|
745
|
+
throw new E(`File not found in bucket '${e}' at path '${r}'`, { bucket: e, path: r });
|
|
627
746
|
}
|
|
628
747
|
async getFiles({
|
|
629
748
|
bucket: t,
|
|
630
749
|
...e
|
|
631
750
|
}) {
|
|
632
|
-
const { data:
|
|
633
|
-
if (
|
|
634
|
-
throw
|
|
635
|
-
return
|
|
636
|
-
}
|
|
637
|
-
async
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
751
|
+
const { data: r, error: a } = await this.client.from(t).listV2(e);
|
|
752
|
+
if (a)
|
|
753
|
+
throw a;
|
|
754
|
+
return r;
|
|
755
|
+
}
|
|
756
|
+
async getFileStorageLocation(t) {
|
|
757
|
+
if ("fileId" in t) {
|
|
758
|
+
const { fileId: n } = t, i = await this.files.get(n, ["bucket_id", "path_tokens"]);
|
|
759
|
+
if (!i)
|
|
760
|
+
throw new E(`File with ID ${n} not found`, { fileId: n });
|
|
761
|
+
return {
|
|
762
|
+
fileId: n,
|
|
763
|
+
bucket: l.notNull(i.bucket_id, "bucket_id must not be null"),
|
|
764
|
+
path: l.notNull(i.path_tokens, "path_tokens must not be null").join("/")
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
const { bucket: e, path: r } = t, { id: a } = await this.getFileObject(e, r);
|
|
768
|
+
return { fileId: a, bucket: e, path: r };
|
|
645
769
|
}
|
|
646
770
|
async getFileInfo(t) {
|
|
647
|
-
const {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
771
|
+
const { fileId: e, bucket: r, path: a } = await this.getFileStorageLocation(t), { id: n, bucketId: i, metadata: o, ...c } = await this.getFileObject(r, a);
|
|
772
|
+
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"), {
|
|
773
|
+
...c,
|
|
774
|
+
fileId: e,
|
|
775
|
+
bucket: r,
|
|
776
|
+
path: a,
|
|
777
|
+
metadata: o,
|
|
778
|
+
properties: o ? {
|
|
779
|
+
type: o.mimetype,
|
|
780
|
+
lastModified: new Date(o.lastModified).getTime()
|
|
781
|
+
} : {}
|
|
782
|
+
};
|
|
651
783
|
}
|
|
652
784
|
async getPublicURL({
|
|
653
785
|
transform: t,
|
|
654
786
|
download: e,
|
|
655
|
-
...
|
|
787
|
+
...r
|
|
656
788
|
}) {
|
|
657
|
-
const { bucket:
|
|
789
|
+
const { bucket: a, path: n } = await this.getFileStorageLocation(r), { data: { publicUrl: i } } = this.client.from(a).getPublicUrl(n, {
|
|
658
790
|
transform: t,
|
|
659
791
|
download: e
|
|
660
792
|
});
|
|
@@ -663,33 +795,35 @@ class X {
|
|
|
663
795
|
}
|
|
664
796
|
export {
|
|
665
797
|
F as DataService,
|
|
666
|
-
|
|
798
|
+
Y as DatabaseService,
|
|
799
|
+
K as EmbeddingService,
|
|
667
800
|
E as FileNotFoundError,
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
801
|
+
Q as Filter,
|
|
802
|
+
O as FilterChainSeparator,
|
|
803
|
+
v as FilterOp,
|
|
804
|
+
H as LogicalOp,
|
|
805
|
+
J as LogicalOpSeparator,
|
|
806
|
+
x as ParseError,
|
|
807
|
+
j as PostgrestErrorInterface,
|
|
808
|
+
P as RecordNotFoundError,
|
|
809
|
+
et as StorageService,
|
|
810
|
+
C as TableDataService,
|
|
678
811
|
k as TracedError,
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
812
|
+
I as UnsupportedMimeError,
|
|
813
|
+
U as ViewDataService,
|
|
814
|
+
X as assertCounted,
|
|
815
|
+
_ as coerceArray,
|
|
816
|
+
M as encodeFilter,
|
|
817
|
+
S as encodeFilterNode,
|
|
818
|
+
W as entries,
|
|
685
819
|
z as groupBy,
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
820
|
+
G as isDatabaseApiError,
|
|
821
|
+
L as negateFilterNode,
|
|
822
|
+
N as negateOp,
|
|
823
|
+
b as parseFilterExpression,
|
|
690
824
|
A as parseFilterExpressionChain,
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
825
|
+
m as postgrestExtensions,
|
|
826
|
+
tt as preprocessingSteps,
|
|
827
|
+
T as removeElement,
|
|
828
|
+
D as splitPath
|
|
695
829
|
};
|