@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/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- import { assert as o } from "@freehour/assert";
2
- import d from "zod";
3
- import { PostgrestError as _ } from "@supabase/supabase-js";
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: a,
25
- path: n
25
+ bucket: r,
26
+ path: a
26
27
  } = {}) {
27
- super(t), this.fileId = e, this.bucket = a, this.path = n;
28
+ super(t), this.fileId = e, this.bucket = r, this.path = a;
28
29
  }
29
30
  }
30
- class q extends k {
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 = "Expression could not be parsed", {
40
+ constructor(t, {
40
41
  expression: e,
41
- format: a,
42
- ...n
42
+ format: r,
43
+ ...a
43
44
  } = {}) {
44
- super(t, n), this.expression = e, this.format = a;
45
+ super(t, a), this.expression = e, this.format = r;
45
46
  }
46
47
  }
47
- class S extends k {
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: a,
63
- id: n
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.schema = e, this.relation = a, this.id = n;
83
+ super(t, a), this.value = e, this.supported = r;
66
84
  }
67
85
  }
68
- const $ = d.object({
69
- code: d.string(),
70
- details: d.string().nullable(),
71
- hint: d.string().nullable(),
72
- name: d.string().optional(),
73
- message: d.string().optional()
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 V(r) {
76
- return r instanceof _ || $.safeParse(r).success;
93
+ function G(s) {
94
+ return s instanceof P || $.safeParse(s).success;
77
95
  }
78
- const I = ["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"], Z = ["and", "or"], G = ",", v = "~", H = (r) => (t = {}) => {
79
- const e = (n) => t[n] ?? n, a = Object.keys(r.shape);
80
- return d.string().transform((n, s) => {
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 A(n, a, e);
100
+ return M(a, r, e);
83
101
  } catch (i) {
84
- return s.addIssue({
102
+ return n.addIssue({
85
103
  code: "custom",
86
- input: n,
104
+ input: a,
87
105
  message: i instanceof Error ? i.message : void 0,
88
- params: i instanceof q ? {
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 P(r) {
97
- return r.startsWith("not.") ? r.slice(4) : `not.${r}`;
114
+ function j(s) {
115
+ return s.startsWith("not.") ? s.slice(4) : `not.${s}`;
98
116
  }
99
- function N(r) {
117
+ function N(s) {
100
118
  return {
101
- ...r,
102
- op: P(r.op)
119
+ ...s,
120
+ op: j(s.op)
103
121
  };
104
122
  }
105
- function x(r, t = (e) => e) {
106
- if (r.type === "logical") {
107
- const e = r.args.map((a) => x(a, t));
108
- return `${r.op}(${e})`;
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(r.key)}.${r.op}.${r.value}`;
128
+ return `${t(s.key)}.${s.op}.${s.value}`;
111
129
  }
112
- function j(r, t = (a) => a, e = v) {
113
- return r.map((a) => x(a, t)).join(e);
130
+ function L(s, t = (r) => r, e = O) {
131
+ return s.map((r) => q(r, t)).join(e);
114
132
  }
115
- function g(r, t = [], e = (a) => a) {
116
- function a(l) {
117
- const b = [];
118
- let y = 0, h = "";
119
- for (const f of l)
120
- f === "(" ? (y++, h += f) : f === ")" ? (y--, h += f) : f === "," && y === 0 ? (b.push(h.trim()), h = "") : h += f;
121
- return h && b.push(h.trim()), b;
122
- }
123
- if (r.endsWith(")")) {
124
- if (r.startsWith("and("))
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: a(r.slice(4, -1)).map((l) => g(l, t, e))
146
+ args: r(s.slice(4, -1)).map((u) => y(u, t, e))
129
147
  };
130
- if (r.startsWith("or("))
148
+ if (s.startsWith("or("))
131
149
  return {
132
150
  type: "logical",
133
151
  op: "or",
134
- args: a(r.slice(3, -1)).map((l) => g(l, t, e))
152
+ args: r(s.slice(3, -1)).map((u) => y(u, t, e))
135
153
  };
136
- if (r.startsWith("not.and("))
154
+ if (s.startsWith("not.and("))
137
155
  return {
138
156
  type: "logical",
139
157
  op: "not.and",
140
- args: a(r.slice(8, -1)).map((l) => g(l, t, e))
158
+ args: r(s.slice(8, -1)).map((u) => y(u, t, e))
141
159
  };
142
- if (r.startsWith("not.or("))
160
+ if (s.startsWith("not.or("))
143
161
  return {
144
162
  type: "logical",
145
163
  op: "not.or",
146
- args: a(r.slice(7, -1)).map((l) => g(l, t, e))
164
+ args: r(s.slice(7, -1)).map((u) => y(u, t, e))
147
165
  };
148
166
  }
149
- const s = `^(${t.length === 0 ? "[a-zA-Z_][a-zA-Z0-9_]*" : t.join("|")})\\.((?:not\\.)?(?:${I.join("|")}))\\.(.+)$`, c = new RegExp(s).exec(r);
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 q(`Invalid filter expression '${r}'`, {
152
- expression: r,
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: I
174
+ operators: v
157
175
  }
158
176
  });
159
- const [, u, m, w] = c;
177
+ const [, o, h, d] = c;
160
178
  return {
161
179
  type: "condition",
162
- key: e(u),
163
- op: m,
164
- value: o.defined(w)
180
+ key: e(o),
181
+ op: h,
182
+ value: l.defined(d)
165
183
  };
166
184
  }
167
- function A(r, t = [], e = (n) => n, a = v) {
168
- return r.length === 0 ? [] : r.split(a).map((n) => g(n, t, e));
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 D(r, t = "/") {
171
- const e = r.lastIndexOf(t);
172
- return e === -1 ? ["", r] : [r.substring(0, e), r.substring(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 O(r) {
175
- return Array.isArray(r) ? r : [r];
192
+ function D(s) {
193
+ return Array.isArray(s) ? s : [s];
176
194
  }
177
- function z(r, t) {
178
- return r.reduce((e, a) => {
179
- const n = t(a);
180
- return (e[n] ??= []).push(a), 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(r) {
184
- return Object.entries(r);
201
+ function T(s, t) {
202
+ const e = s.findIndex(t);
203
+ return e !== -1 && s.splice(e, 1), s;
185
204
  }
186
- const p = {
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: (r) => Object.assign(r, {
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) => p.filter.enable(
208
- r.select(
209
- O(t).join(","),
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") => p.filter.enable(
221
- r.select("*", { count: t, head: !0 })
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: () => p.filter.enable(
230
- r.delete()
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: (r, t = {}) => Object.assign(r, {
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) => p.filter.enable(
275
+ apply: (e) => w.filter.enable(
254
276
  (() => {
255
- function a(n, s) {
256
- if (s.type === "logical") {
257
- const i = j(s.args, (c) => c, ",");
258
- return s.op === "or" ? n.or(i) : s.op === "not.or" ? n.or(i, { referencedTable: "not" }) : a(n, {
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: s.op === "and" ? "not.or" : "or",
261
- args: s.args.map(N)
282
+ op: n.op === "and" ? "not.or" : "or",
283
+ args: n.args.map(N)
262
284
  });
263
285
  }
264
- return n.filter(s.key, s.op, s.value);
286
+ return a.filter(n.key, n.op, n.value);
265
287
  }
266
- return e.reduce(a, r);
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, a, n) => p.filter.enable(
299
+ paginate: (e, r, a) => w.filter.enable(
278
300
  (() => {
279
- o(e >= 0, "Page index must be ≥ 0"), o(a >= 0, "Page limit must be ≥ 0");
280
- const s = e * a, i = s + a - 1;
281
- if (n !== void 0) {
282
- if (s >= n)
283
- return r.limit(0);
284
- if (i >= n)
285
- return r.range(s, n - 1);
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 r.range(s, i);
309
+ return s.range(n, i);
288
310
  })(),
289
311
  {
290
312
  ...t,
291
313
  pagination: {
292
314
  page: e,
293
- limit: a,
294
- count: n
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: () => r.throwOnError().then((e) => {
304
- const { data: a, count: n } = e, { page: s, limit: i, ...c } = o.defined(t.pagination, "Pagination context is required for collect(). Make sure to call paginate() before collect()"), u = n ?? c.count;
305
- return o(i > 0, "Page limit must be > 0"), o(Array.isArray(a), "Data must be an array for pagination, make sure to select multiple rows in query"), o(u !== void 0, "Row count is required for pagination, make sure to count in query or pass `count` in paginate()"), {
306
- items: a,
307
- totalItems: u,
308
- page: s,
309
- totalPages: Math.ceil(u / i),
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: a
351
+ relation: r
330
352
  }) {
331
- this.database = t, this.schema = e, this.relation = a;
353
+ this.database = t, this.schema = e, this.relation = r;
332
354
  }
333
355
  recordNotFoundError(t) {
334
- return new S(`Record with id ${t} not found in ${this.schema}.${this.relation}`, {
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 p.query.enable(t);
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: a = 0,
359
- limit: n = 64
380
+ minSimilarity: r = 0,
381
+ limit: a = 64
360
382
  }) {
361
- const { data: s } = await this.database.schema("supabase_core").rpc("fuzzy_search", {
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: a,
367
- limit_results: n
388
+ min_similarity: r,
389
+ limit_results: a
368
390
  }).throwOnError();
369
- return s;
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: a } = await this.query.select(e).eq("id", t).throwOnError();
389
- return a[0];
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 a = await this.get(t, e);
401
- if (a === void 0)
422
+ const r = await this.get(t, e);
423
+ if (r === void 0)
402
424
  throw this.recordNotFoundError(t);
403
- return a;
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
- ...a
468
+ ...r
448
469
  } = {}) {
449
- const { data: n } = await this.query.upsert(t, {
470
+ const { data: a } = await this.query.upsert(t, {
450
471
  onConflict: e?.join(","),
451
- ...a
472
+ ...r
452
473
  }).select().single().throwOnError();
453
- return n;
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: a } = await this.query.update(e).eq("id", t).select().single().throwOnError();
465
- return a;
485
+ const { data: r } = await this.query.update(e).eq("id", t).select().single().throwOnError();
486
+ return r;
466
487
  }
467
488
  }
468
- class M extends F {
489
+ class C extends F {
469
490
  constructor({
470
491
  database: t,
471
492
  schema: e,
472
- table: a
493
+ table: r
473
494
  }) {
474
495
  super({
475
496
  database: t,
476
497
  schema: e,
477
- relation: a
498
+ relation: r
478
499
  });
479
500
  }
480
501
  }
481
- class R extends F {
502
+ class U extends F {
482
503
  constructor({
483
504
  database: t,
484
505
  schema: e,
485
- view: a
506
+ view: r
486
507
  }) {
487
508
  super({
488
509
  database: t,
489
510
  schema: e,
490
- relation: a
511
+ relation: r
491
512
  });
492
513
  }
493
514
  }
494
- function J(r) {
495
- if (r.error)
496
- throw r.error;
497
- return o(r.count !== null, "Response does not contain a count. Make sure to set the `count` option in the request."), r;
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 Q {
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 M({
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 R({
549
+ return new U({
529
550
  database: this,
530
551
  schema: t,
531
552
  view: e
532
553
  });
533
554
  }
534
555
  }
535
- function W(r) {
536
- return {
537
- id: r.id,
538
- bucket: o.notNull(r.bucket_id, "bucket_id must not be null"),
539
- path: o.defined(r.path_tokens?.join("/"), "path_tokens must not be null")
540
- };
541
- }
542
- function B(r) {
543
- const t = o.notNull(r.metadata, "metadata must not be null");
544
- return {
545
- ...W(r),
546
- metadata: t,
547
- properties: {
548
- type: t.mimetype,
549
- lastModified: new Date(t.lastModified).getTime()
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
- class X {
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 uploadFile({
566
- bucket: t,
567
- path: e,
568
- file: a,
569
- overwriteExisting: n = !1
570
- }) {
571
- const { data: s, error: i } = await this.client.from(t).upload(
572
- `${e}/${a.name}`,
573
- a,
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: n
730
+ upsert: a
576
731
  }
577
732
  );
578
733
  if (i)
579
734
  throw i;
580
735
  return {
581
- id: s.id,
582
- bucket: t,
583
- path: s.path
736
+ fileId: n.id,
737
+ bucket: e,
738
+ path: n.path
584
739
  };
585
740
  }
586
741
  async downloadFile(t) {
587
- const { bucket: e, path: a, properties: n } = "fileId" in t ? await this.getFileStorageInfo(t.fileId) : t, { data: s, error: i } = await this.client.from(e).download(a);
588
- if (i)
589
- throw i;
590
- const [, c] = D(a);
591
- return new File([s], c, n);
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 = "fileIds" in t ? (await this.files.query.select(["bucket_id", "path_tokens"]).containedBy("id", t.fileIds).throwOnError()).data.map(({ bucket_id: s, path_tokens: i }) => ({
595
- bucket: o.notNull(s, "bucket_id must not be null"),
596
- paths: o.notNull(i, "path_tokens must not be null").join("/")
597
- })) : O(t), a = T(
598
- z(e, (s) => s.bucket)
599
- ).map(([s, i]) => ({
600
- bucket: s,
601
- paths: i.flatMap((c) => c.paths)
602
- })).filter(({ paths: s }) => s.length > 0);
603
- return (await Promise.all(a.map(
604
- async ({ bucket: s, paths: i }) => this.client.from(s).remove(i).then(({ data: c, error: u }) => {
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 c.map((m, w) => ({
608
- id: o.notNull(m.id, "file id must not be null"),
609
- bucket: s,
610
- path: o.defined(i[w])
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
- Q as DatabaseService,
778
+ Y as DatabaseService,
779
+ K as EmbeddingService,
667
780
  E as FileNotFoundError,
668
- H as Filter,
669
- v as FilterChainSeparator,
670
- I as FilterOp,
671
- Z as LogicalOp,
672
- G as LogicalOpSeparator,
673
- q as ParseError,
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
- S as RecordNotFoundError,
676
- X as StorageService,
677
- M as TableDataService,
788
+ _ as RecordNotFoundError,
789
+ et as StorageService,
790
+ C as TableDataService,
678
791
  k as TracedError,
679
- R as ViewDataService,
680
- J as assertCounted,
681
- O as coerceArray,
682
- j as encodeFilter,
683
- x as encodeFilterNode,
684
- T as entries,
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
- V as isDatabaseApiError,
800
+ G as isDatabaseApiError,
687
801
  N as negateFilterNode,
688
- P as negateOp,
689
- g as parseFilterExpression,
690
- A as parseFilterExpressionChain,
691
- p as postgrestExtensions,
692
- D as splitPath,
693
- B as toStorageInfo,
694
- W as toStorageLocation
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
  };