@freehour/supabase-core 1.0.2 → 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/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 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: 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 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: 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 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 V(r) {
76
- return r instanceof _ || $.safeParse(r).success;
93
+ function G(s) {
94
+ return s instanceof $ || j.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 p.string().transform((a, n) => {
81
99
  try {
82
- return A(n, a, e);
100
+ return A(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 N(s) {
115
+ return s.startsWith("not.") ? s.slice(4) : `not.${s}`;
98
116
  }
99
- function N(r) {
117
+ function L(s) {
100
118
  return {
101
- ...r,
102
- op: P(r.op)
119
+ ...s,
120
+ op: N(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 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(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 M(s, t = (r) => r, e = O) {
131
+ return s.map((r) => S(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 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: a(r.slice(4, -1)).map((l) => g(l, t, e))
146
+ args: r(s.slice(4, -1)).map((u) => b(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) => b(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) => b(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) => b(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);
150
- if (!c)
151
- throw new q(`Invalid filter expression '${r}'`, {
152
- expression: r,
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: I
174
+ operators: v
157
175
  }
158
176
  });
159
- const [, u, m, w] = c;
177
+ const [, c, h, g] = o;
160
178
  return {
161
179
  type: "condition",
162
- key: e(u),
163
- op: m,
164
- value: o.defined(w)
180
+ key: e(c),
181
+ op: h,
182
+ value: l.defined(g)
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 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(r, t = "/") {
171
- const e = r.lastIndexOf(t);
172
- return e === -1 ? ["", r] : [r.substring(0, e), r.substring(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 O(r) {
175
- return Array.isArray(r) ? r : [r];
192
+ function _(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;
204
+ }
205
+ function W(s) {
206
+ return Object.entries(s);
185
207
  }
186
- const p = {
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: (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) => 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") => p.filter.enable(
221
- r.select("*", { count: t, head: !0 })
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: () => p.filter.enable(
230
- r.delete()
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: (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) => m.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 = 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: 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(L)
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) => m.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, ...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: 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 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 p.query.enable(t);
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: 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.
@@ -444,13 +466,13 @@ class F {
444
466
  */
445
467
  async upsert(t, {
446
468
  onConflict: e,
447
- ...a
469
+ ...r
448
470
  } = {}) {
449
- const { data: n } = await this.query.upsert(t, {
471
+ const { data: a } = await this.query.upsert(t, {
450
472
  onConflict: e?.join(","),
451
- ...a
473
+ ...r
452
474
  }).select().single().throwOnError();
453
- return n;
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: a } = await this.query.update(e).eq("id", t).select().single().throwOnError();
465
- return a;
486
+ const { data: r } = await this.query.update(e).eq("id", t).select().single().throwOnError();
487
+ return r;
466
488
  }
467
489
  }
468
- class M extends F {
490
+ class C extends F {
469
491
  constructor({
470
492
  database: t,
471
493
  schema: e,
472
- table: a
494
+ table: r
473
495
  }) {
474
496
  super({
475
497
  database: t,
476
498
  schema: e,
477
- relation: a
499
+ relation: r
478
500
  });
479
501
  }
480
502
  }
481
- class R extends F {
503
+ class U extends F {
482
504
  constructor({
483
505
  database: t,
484
506
  schema: e,
485
- view: a
507
+ view: r
486
508
  }) {
487
509
  super({
488
510
  database: t,
489
511
  schema: e,
490
- relation: a
512
+ relation: r
491
513
  });
492
514
  }
493
515
  }
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;
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 Q {
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 M({
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 R({
550
+ return new U({
529
551
  database: this,
530
552
  schema: t,
531
553
  view: e
532
554
  });
533
555
  }
534
556
  }
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()
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
- class X {
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: a,
569
- overwriteExisting: n = !1
682
+ file: r,
683
+ overwriteExisting: a = !1
570
684
  }) {
571
- const { data: s, error: i } = await this.client.from(t).upload(
572
- `${e}/${a.name}`,
573
- a,
685
+ const { data: n, error: i } = await this.client.from(t).upload(
686
+ `${e}/${r.name}`,
687
+ r,
574
688
  {
575
- upsert: n
689
+ upsert: a
576
690
  }
577
691
  );
578
692
  if (i)
579
693
  throw i;
580
694
  return {
581
- id: s.id,
695
+ fileId: n.id,
582
696
  bucket: t,
583
- path: s.path
697
+ path: n.path
584
698
  };
585
699
  }
586
700
  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;
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 new File([s], c, n);
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: 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 }) => {
605
- if (u)
606
- 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])
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: 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;
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: 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 });
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: 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
- });
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 { 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;
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
- ...a
787
+ ...r
656
788
  }) {
657
- const { bucket: n, path: s } = "fileId" in a ? await this.getFileStorageInfo(a.fileId) : a, { data: { publicUrl: i } } = this.client.from(n).getPublicUrl(s, {
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
- Q as DatabaseService,
798
+ Y as DatabaseService,
799
+ K as EmbeddingService,
667
800
  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,
674
- $ as PostgrestErrorInterface,
675
- S as RecordNotFoundError,
676
- X as StorageService,
677
- M as TableDataService,
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
- R as ViewDataService,
680
- J as assertCounted,
681
- O as coerceArray,
682
- j as encodeFilter,
683
- x as encodeFilterNode,
684
- T as entries,
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
- V as isDatabaseApiError,
687
- N as negateFilterNode,
688
- P as negateOp,
689
- g as parseFilterExpression,
820
+ G as isDatabaseApiError,
821
+ L as negateFilterNode,
822
+ N as negateOp,
823
+ b as parseFilterExpression,
690
824
  A as parseFilterExpressionChain,
691
- p as postgrestExtensions,
692
- D as splitPath,
693
- B as toStorageInfo,
694
- W as toStorageLocation
825
+ m as postgrestExtensions,
826
+ tt as preprocessingSteps,
827
+ T as removeElement,
828
+ D as splitPath
695
829
  };