@voltro/plugin-search 0.34.0 → 0.35.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,12 +1,12 @@
1
- import { a as e, i as t, n, r } from "./rpc-BQBNr0OU.js";
2
- import { Data as i, Duration as a, Effect as o, Schedule as s } from "effect";
3
- import { definePlugin as c, pluginInstanceName as l } from "@voltro/protocol";
4
- import { and as u, count as d, eq as f, id as p, integer as m, table as h, text as g, timestamp as _ } from "@voltro/database";
1
+ import { a as e, i as t, n, r } from "./rpc-DaYt-dP6.js";
2
+ import { Cause as i, Chunk as a, Data as o, Duration as s, Effect as c, Exit as l, Option as u, Schedule as d, Stream as f } from "effect";
3
+ import { and as p, count as m, eq as h, id as g, integer as _, streamTable as ee, table as v, text as y, timestamp as b } from "@voltro/database";
4
+ import { definePlugin as te, pluginInstanceName as ne } from "@voltro/protocol";
5
5
  //#region src/sanitize.ts
6
- var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
6
+ var x = /^[A-Za-z_][A-Za-z0-9_.]*$/, S = (e) => x.test(e), re = (e, t) => {
7
7
  let n = t ? new Set(t) : void 0;
8
8
  for (let [t, r] of e) {
9
- if (!y(r)) return {
9
+ if (!S(r)) return {
10
10
  field: r,
11
11
  where: t,
12
12
  reason: "not-an-identifier"
@@ -17,7 +17,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
17
17
  reason: "not-queryable"
18
18
  };
19
19
  }
20
- }, b = {
20
+ }, C = {
21
21
  typesense: [
22
22
  "per_page",
23
23
  "page",
@@ -71,7 +71,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
71
71
  "highlightPreTag",
72
72
  "highlightPostTag"
73
73
  ]
74
- }, x = {
74
+ }, ie = {
75
75
  typesense: [
76
76
  "filter_by",
77
77
  "q",
@@ -108,20 +108,20 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
108
108
  "aroundLatLng",
109
109
  "insideBoundingBox"
110
110
  ]
111
- }, S = (e, t, n) => {
111
+ }, w = (e, t, n) => {
112
112
  if (!t) return {
113
113
  params: {},
114
114
  appAllowed: {},
115
115
  dropped: []
116
116
  };
117
- let r = new Set(x[e]), i = new Set(b[e]), a = new Set(n ?? []), o = {}, s = {}, c = [];
117
+ let r = new Set(ie[e]), i = new Set(C[e]), a = new Set(n ?? []), o = {}, s = {}, c = [];
118
118
  for (let [e, n] of Object.entries(t)) r.has(e) ? c.push(e) : i.has(e) ? o[e] = n : a.has(e) ? s[e] = n : c.push(e);
119
119
  return {
120
120
  params: o,
121
121
  appAllowed: s,
122
122
  dropped: c
123
123
  };
124
- }, C = (e) => b[e], w = class extends i.TaggedError("SearchBackendError") {}, T = (e) => Array.isArray(e) ? e : [e], E = (e, t, n) => {
124
+ }, T = (e) => C[e], E = class extends o.TaggedError("SearchBackendError") {}, D = (e) => Array.isArray(e) ? e : [e], O = (e, t, n) => {
125
125
  if (Math.abs(e.length - t.length) > n) return !1;
126
126
  if (e === t) return !0;
127
127
  let r = t.length, i = Array.from({ length: r + 1 }, (e, t) => t);
@@ -137,7 +137,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
137
137
  i = o;
138
138
  }
139
139
  return (i[r] ?? Infinity) <= n;
140
- }, D = (e) => e.length <= 4 ? 1 : 2, O = () => {
140
+ }, k = (e) => e.length <= 4 ? 1 : 2, A = () => {
141
141
  let e = /* @__PURE__ */ new Map(), t = (t) => {
142
142
  let n = e.get(t);
143
143
  return n || (n = /* @__PURE__ */ new Map(), e.set(t, n)), n;
@@ -146,13 +146,13 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
146
146
  switch (t.op) {
147
147
  case "eq": return String(n) === String(t.value);
148
148
  case "neq": return String(n) !== String(t.value);
149
- case "in": return T(t.value).some((e) => String(n) === String(e));
150
- case "nin": return T(t.value).every((e) => String(n) !== String(e));
149
+ case "in": return D(t.value).some((e) => String(n) === String(e));
150
+ case "nin": return D(t.value).every((e) => String(n) !== String(e));
151
151
  case "gt":
152
152
  case "gte":
153
153
  case "lt":
154
154
  case "lte": {
155
- let [e, r] = [k(n), k(t.value)];
155
+ let [e, r] = [j(n), j(t.value)];
156
156
  return e === void 0 || r === void 0 ? !1 : t.op === "gt" ? e > r : t.op === "gte" ? e >= r : t.op === "lt" ? e < r : e <= r;
157
157
  }
158
158
  }
@@ -162,8 +162,8 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
162
162
  let e = r.toLowerCase();
163
163
  if (e.includes(t)) return !0;
164
164
  if (n !== void 0 && n !== 0) {
165
- let r = n === "auto" ? D(t) : n;
166
- for (let n of e.split(/\s+/)) if (E(n, t, r)) return !0;
165
+ let r = n === "auto" ? k(t) : n;
166
+ for (let n of e.split(/\s+/)) if (O(n, t, r)) return !0;
167
167
  }
168
168
  }
169
169
  return !1;
@@ -207,7 +207,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
207
207
  };
208
208
  }
209
209
  };
210
- }, k = (e) => {
210
+ }, j = (e) => {
211
211
  if (typeof e == "number") return e;
212
212
  if (typeof e == "boolean") return +!!e;
213
213
  if (typeof e == "string") {
@@ -216,19 +216,19 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
216
216
  let n = Date.parse(e);
217
217
  return Number.isNaN(n) ? void 0 : n;
218
218
  }
219
- }, A = async (e, t, n) => {
219
+ }, M = async (e, t, n) => {
220
220
  try {
221
221
  return await n();
222
222
  } catch {
223
- throw new w({
223
+ throw new E({
224
224
  engine: t,
225
225
  op: "query",
226
226
  message: `the '${t}' search backend requires the '${e}' optional dependency. Install it to enable it (e.g. \`npm i ${e}\`).`,
227
227
  transient: !1
228
228
  });
229
229
  }
230
- }, j = (e, t) => (n) => {
231
- let { params: r, appAllowed: i, dropped: a } = S(e, n, t.allowEngineParams);
230
+ }, N = (e, t) => (n) => {
231
+ let { params: r, appAllowed: i, dropped: a } = w(e, n, t.allowEngineParams);
232
232
  return a.length > 0 && t.onWarn?.("search dropped disallowed engineParams", {
233
233
  engine: e,
234
234
  keys: a
@@ -236,16 +236,16 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
236
236
  before: r,
237
237
  after: i
238
238
  };
239
- }, M = (e, t) => {
240
- if (!y(t)) throw new w({
239
+ }, P = (e, t) => {
240
+ if (!S(t)) throw new E({
241
241
  engine: e,
242
242
  op: "query",
243
243
  message: `filter field "${t}" is not a plain field path (^[A-Za-z_][A-Za-z0-9_.]*$)`,
244
244
  transient: !1
245
245
  });
246
246
  return t;
247
- }, te = (e) => {
248
- let t = (e) => JSON.stringify(e), n = M("typesense", e.field);
247
+ }, ae = (e) => {
248
+ let t = (e) => JSON.stringify(e), n = P("typesense", e.field);
249
249
  switch (e.op) {
250
250
  case "eq": return `${n}:=${t(e.value)}`;
251
251
  case "neq": return `${n}:!=${t(e.value)}`;
@@ -253,21 +253,21 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
253
253
  case "gte": return `${n}:>=${t(e.value)}`;
254
254
  case "lt": return `${n}:<${t(e.value)}`;
255
255
  case "lte": return `${n}:<=${t(e.value)}`;
256
- case "in": return `${n}:[${T(e.value).map(t).join(",")}]`;
257
- case "nin": return `${n}:!=[${T(e.value).map(t).join(",")}]`;
256
+ case "in": return `${n}:[${D(e.value).map(t).join(",")}]`;
257
+ case "nin": return `${n}:!=[${D(e.value).map(t).join(",")}]`;
258
258
  }
259
- }, ne = (e, t = {}) => {
260
- let n = j("typesense", t), r, i = async () => (r ||= A("typesense", "typesense", () => import("typesense")).then((t) => {
259
+ }, oe = (e, t = {}) => {
260
+ let n = N("typesense", t), r, i = async () => (r ||= M("typesense", "typesense", () => import("typesense")).then((t) => {
261
261
  let n = t.Client;
262
262
  return new n({
263
263
  nodes: [{ url: e.url ?? e.host ?? "http://localhost:8108" }],
264
264
  apiKey: e.apiKey
265
265
  });
266
- }), r), a = (e) => e && e.length > 0 ? e.map(te).join(" && ") : void 0, o = async (e, t) => {
266
+ }), r), a = (e) => e && e.length > 0 ? e.map(ae).join(" && ") : void 0, o = async (e, t) => {
267
267
  try {
268
268
  return await t();
269
269
  } catch (t) {
270
- throw t instanceof w ? t : new w({
270
+ throw t instanceof E ? t : new E({
271
271
  engine: "typesense",
272
272
  op: e,
273
273
  message: String(t?.message ?? t),
@@ -299,10 +299,10 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
299
299
  ...d !== void 0 && d !== "auto" ? { num_typos: Math.min(2, Math.max(0, d)) } : {},
300
300
  ...p.after
301
301
  };
302
- return re(await o.collections(e).documents().search(m));
302
+ return se(await o.collections(e).documents().search(m));
303
303
  })
304
304
  };
305
- }, re = (e) => {
305
+ }, se = (e) => {
306
306
  let t = (e.hits ?? []).map((e) => {
307
307
  let t = {};
308
308
  for (let n of e.highlights ?? []) {
@@ -319,8 +319,8 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
319
319
  hits: t,
320
320
  facets: n
321
321
  };
322
- }, ie = (e) => {
323
- let t = (e) => JSON.stringify(e), n = M("meilisearch", e.field);
322
+ }, ce = (e) => {
323
+ let t = (e) => JSON.stringify(e), n = P("meilisearch", e.field);
324
324
  switch (e.op) {
325
325
  case "eq": return `${n} = ${t(e.value)}`;
326
326
  case "neq": return `${n} != ${t(e.value)}`;
@@ -328,18 +328,18 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
328
328
  case "gte": return `${n} >= ${t(e.value)}`;
329
329
  case "lt": return `${n} < ${t(e.value)}`;
330
330
  case "lte": return `${n} <= ${t(e.value)}`;
331
- case "in": return `${n} IN [${T(e.value).map(t).join(", ")}]`;
332
- case "nin": return `${n} NOT IN [${T(e.value).map(t).join(", ")}]`;
331
+ case "in": return `${n} IN [${D(e.value).map(t).join(", ")}]`;
332
+ case "nin": return `${n} NOT IN [${D(e.value).map(t).join(", ")}]`;
333
333
  }
334
- }, ae = (e, t = {}) => {
335
- let n = j("meilisearch", t), r, i = async () => (r ||= A("meilisearch", "meilisearch", () => import("meilisearch")).then((t) => new t.MeiliSearch({
334
+ }, F = (e, t = {}) => {
335
+ let n = N("meilisearch", t), r, i = async () => (r ||= M("meilisearch", "meilisearch", () => import("meilisearch")).then((t) => new t.MeiliSearch({
336
336
  host: e.host ?? e.url ?? "http://localhost:7700",
337
337
  apiKey: e.apiKey
338
- })), r), a = (e) => e && e.length > 0 ? e.map(ie) : void 0, o = async (e, t) => {
338
+ })), r), a = (e) => e && e.length > 0 ? e.map(ce) : void 0, o = async (e, t) => {
339
339
  try {
340
340
  return await t();
341
341
  } catch (t) {
342
- throw t instanceof w ? t : new w({
342
+ throw t instanceof E ? t : new E({
343
343
  engine: "meilisearch",
344
344
  op: e,
345
345
  message: String(t?.message ?? t),
@@ -372,10 +372,10 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
372
372
  } : {},
373
373
  ...o.after
374
374
  };
375
- return oe(await (await i()).index(e).search(t, p), u);
375
+ return le(await (await i()).index(e).search(t, p), u);
376
376
  })
377
377
  };
378
- }, oe = (e, t) => ({
378
+ }, le = (e, t) => ({
379
379
  hits: e.hits.map((e) => {
380
380
  let { _formatted: n, ...r } = e;
381
381
  if (t && n) {
@@ -389,19 +389,19 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
389
389
  return { doc: r };
390
390
  }),
391
391
  facets: e.facetDistribution ?? {}
392
- }), se = (e) => String(e).replace(/^-/, "\\-"), ce = (e, t) => {
392
+ }), ue = (e) => String(e).replace(/^-/, "\\-"), de = (e, t) => {
393
393
  let n = typeof t == "boolean" ? +!!t : Number(t);
394
- if (!Number.isFinite(n)) throw new w({
394
+ if (!Number.isFinite(n)) throw new E({
395
395
  engine: "algolia",
396
396
  op: "query",
397
397
  message: `range filter on "${e}" needs a numeric value (got ${JSON.stringify(t)})`,
398
398
  transient: !1
399
399
  });
400
400
  return n;
401
- }, le = (e) => {
401
+ }, fe = (e) => {
402
402
  let t = [], n = [];
403
403
  for (let r of e ?? []) {
404
- let e = M("algolia", r.field), i = (e) => se(e), a = (t) => ce(e, t);
404
+ let e = P("algolia", r.field), i = (e) => ue(e), a = (t) => de(e, t);
405
405
  switch (r.op) {
406
406
  case "eq":
407
407
  t.push(`${e}:${i(r.value)}`);
@@ -410,10 +410,10 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
410
410
  t.push(`${e}:-${i(r.value)}`);
411
411
  break;
412
412
  case "in":
413
- t.push(T(r.value).map((t) => `${e}:${i(t)}`));
413
+ t.push(D(r.value).map((t) => `${e}:${i(t)}`));
414
414
  break;
415
415
  case "nin":
416
- for (let n of T(r.value)) t.push(`${e}:-${i(n)}`);
416
+ for (let n of D(r.value)) t.push(`${e}:-${i(n)}`);
417
417
  break;
418
418
  case "gt":
419
419
  n.push(`${e} > ${a(r.value)}`);
@@ -433,12 +433,12 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
433
433
  facetFilters: t,
434
434
  numericFilters: n
435
435
  };
436
- }, N = (e, t = {}) => {
437
- let n = j("algolia", t), r, i = async () => (r ||= A("algoliasearch", "algolia", () => import("algoliasearch")).then((t) => t.algoliasearch(e.appId ?? "", e.apiKey)), r), a = async (e, t) => {
436
+ }, I = (e, t = {}) => {
437
+ let n = N("algolia", t), r, i = async () => (r ||= M("algoliasearch", "algolia", () => import("algoliasearch")).then((t) => t.algoliasearch(e.appId ?? "", e.apiKey)), r), a = async (e, t) => {
438
438
  try {
439
439
  return await t();
440
440
  } catch (t) {
441
- throw t instanceof w ? t : new w({
441
+ throw t instanceof E ? t : new E({
442
442
  engine: "algolia",
443
443
  op: e,
444
444
  message: String(t?.message ?? t),
@@ -463,7 +463,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
463
463
  });
464
464
  }),
465
465
  query: (e, { q: t, limit: r, offset: o, filters: s, facets: c, highlight: l, fuzziness: u, engineParams: d }) => a("query", async () => {
466
- let { facetFilters: a, numericFilters: f } = le(s), p = o ? {
466
+ let { facetFilters: a, numericFilters: f } = fe(s), p = o ? {
467
467
  offset: o,
468
468
  length: r ?? 20
469
469
  } : { hitsPerPage: r ?? 20 }, m = n(d), h = {
@@ -481,13 +481,13 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
481
481
  ...u === 0 ? { typoTolerance: !1 } : {},
482
482
  ...m.after
483
483
  };
484
- return ue(await (await i()).searchSingleIndex({
484
+ return pe(await (await i()).searchSingleIndex({
485
485
  indexName: e,
486
486
  searchParams: h
487
487
  }), l);
488
488
  })
489
489
  };
490
- }, ue = (e, t) => ({
490
+ }, pe = (e, t) => ({
491
491
  hits: e.hits.map((e) => {
492
492
  let { _highlightResult: n, ...r } = e;
493
493
  if (t && n) {
@@ -501,25 +501,25 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
501
501
  return { doc: r };
502
502
  }),
503
503
  facets: e.facets ?? {}
504
- }), P = "_voltro_search_stats", F = () => ({
504
+ }), L = "_voltro_search_stats", R = () => ({
505
505
  synced: 0,
506
506
  removed: 0,
507
507
  dropped: 0,
508
508
  lastReindexAt: null,
509
509
  lastReindexCount: 0
510
- }), I = h(P, {
511
- id: p({ prefix: "sstat" }),
512
- indexName: g().maxLength(191),
513
- replicaId: g().maxLength(191),
514
- synced: m().default(0),
515
- removed: m().default(0),
516
- dropped: m().default(0),
517
- scope: g().maxLength(8).default("local"),
518
- lastReindexAt: _().nullable(),
519
- lastReindexCount: m().default(0),
520
- updatedAt: _()
521
- }).unique("bySearchStatsIndexReplica", ["indexName", "replicaId"]).index("bySearchStatsIndex", ["indexName"]), L = () => [I], R = () => {
522
- let e = /* @__PURE__ */ new Map(), t = (t) => e.get(t) ?? F();
510
+ }), z = v(L, {
511
+ id: g({ prefix: "sstat" }),
512
+ indexName: y().maxLength(191),
513
+ replicaId: y().maxLength(191),
514
+ synced: _().default(0),
515
+ removed: _().default(0),
516
+ dropped: _().default(0),
517
+ scope: y().maxLength(8).default("local"),
518
+ lastReindexAt: b().nullable(),
519
+ lastReindexCount: _().default(0),
520
+ updatedAt: b()
521
+ }).unique("bySearchStatsIndexReplica", ["indexName", "replicaId"]).index("bySearchStatsIndex", ["indexName"]), B = () => [z], V = () => {
522
+ let e = /* @__PURE__ */ new Map(), t = (t) => e.get(t) ?? R();
523
523
  return {
524
524
  bump: async (n, r) => {
525
525
  let i = t(n);
@@ -534,6 +534,15 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
534
534
  dropped: i.dropped + 1
535
535
  });
536
536
  },
537
+ add: async (n, r) => {
538
+ let i = t(n);
539
+ e.set(n, {
540
+ ...i,
541
+ synced: i.synced + r.synced,
542
+ removed: i.removed + r.removed,
543
+ dropped: i.dropped + r.dropped
544
+ });
545
+ },
537
546
  recordReindex: async (n, r, i) => {
538
547
  let a = t(n);
539
548
  e.set(n, {
@@ -545,19 +554,19 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
545
554
  },
546
555
  get: async (e) => t(e)
547
556
  };
548
- }, z = (e) => ({
549
- table: P,
557
+ }, H = (e) => ({
558
+ table: L,
550
559
  predicate: e,
551
560
  order: [],
552
561
  take: void 0,
553
562
  skip: void 0,
554
563
  projection: void 0
555
- }), de = () => `sstat_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, fe = () => process.env.VOLTRO_REPLICA_ID ?? process.env.HOSTNAME ?? process.env.POD_NAME ?? `pid_${process.pid}_${Math.random().toString(36).slice(2, 8)}`, B = 32, V = (e, t = fe()) => {
556
- let n = async (n) => (await e.query(z(u(f("indexName", n), f("replicaId", t)))))[0] ?? null, r = async (e) => {
564
+ }), me = () => `sstat_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, he = () => process.env.VOLTRO_REPLICA_ID ?? process.env.HOSTNAME ?? process.env.POD_NAME ?? `pid_${process.pid}_${Math.random().toString(36).slice(2, 8)}`, U = 32, W = (e, t = he()) => {
565
+ let n = async (n) => (await e.query(H(p(h("indexName", n), h("replicaId", t)))))[0] ?? null, r = async (e) => {
557
566
  try {
558
567
  return await e();
559
568
  } catch (e) {
560
- throw e instanceof w ? e : new w({
569
+ throw e instanceof E ? e : new E({
561
570
  engine: "stats",
562
571
  op: "upsert",
563
572
  message: String(e?.message ?? e),
@@ -565,7 +574,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
565
574
  });
566
575
  }
567
576
  }, i = (i, a, o, s) => r(async () => {
568
- for (let r = 0; r < B; r++) {
577
+ for (let r = 0; r < U; r++) {
569
578
  r > 0 && await new Promise((e) => setTimeout(e, r));
570
579
  let c = await n(i);
571
580
  if (c) {
@@ -580,9 +589,9 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
580
589
  ...o(i),
581
590
  ...a ? { scope: a } : {},
582
591
  updatedAt: /* @__PURE__ */ new Date()
583
- }, { where: u(f("id", String(c.id)), f("synced", t), f("removed", n), f("dropped", r)) }) === 1) return;
592
+ }, { where: p(h("id", String(c.id)), h("synced", t), h("removed", n), h("dropped", r)) }) === 1) return;
584
593
  } else {
585
- let n = de(), r = await e.insertIgnore(P, {
594
+ let n = me(), r = await e.insertIgnore(L, {
586
595
  id: n,
587
596
  indexName: i,
588
597
  replicaId: t,
@@ -598,15 +607,24 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
598
607
  if (String(r.id) === n) return;
599
608
  }
600
609
  }
601
- throw new w({
610
+ throw new E({
602
611
  engine: "stats",
603
612
  op: "upsert",
604
- message: `search stats: contention on (${i}, ${t}) exceeded ${B} attempts`,
613
+ message: `search stats: contention on (${i}, ${t}) exceeded ${U} attempts`,
605
614
  transient: !0
606
615
  });
607
616
  });
608
617
  return {
609
618
  bump: (e, t, n) => i(e, n, (e) => t === "synced" ? { synced: e.synced + 1 } : t === "removed" ? { removed: e.removed + 1 } : { dropped: e.dropped + 1 }, t === "synced" ? { synced: 1 } : t === "removed" ? { removed: 1 } : { dropped: 1 }),
619
+ add: (e, t, n) => i(e, n, (e) => ({
620
+ synced: e.synced + t.synced,
621
+ removed: e.removed + t.removed,
622
+ dropped: e.dropped + t.dropped
623
+ }), {
624
+ synced: t.synced,
625
+ removed: t.removed,
626
+ dropped: t.dropped
627
+ }),
610
628
  recordReindex: (e, t, n) => i(e, void 0, (e) => ({
611
629
  synced: e.synced + t,
612
630
  lastReindexAt: new Date(n),
@@ -617,7 +635,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
617
635
  lastReindexCount: t
618
636
  }),
619
637
  get: (t) => r(async () => {
620
- let n = await e.query(z(f("indexName", t))), r = n.some((e) => e.scope === "fleet"), i = (e) => {
638
+ let n = await e.query(H(h("indexName", t))), r = n.some((e) => e.scope === "fleet"), i = (e) => {
621
639
  let t = 0;
622
640
  for (let i of n) {
623
641
  let n = Number(i[e] ?? 0);
@@ -630,7 +648,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
630
648
  t && (a === null || t > a) && (a = t, o = Number(e.lastReindexCount ?? 0));
631
649
  }
632
650
  return {
633
- ...F(),
651
+ ...R(),
634
652
  synced: i("synced"),
635
653
  removed: i("removed"),
636
654
  dropped: i("dropped"),
@@ -639,12 +657,44 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
639
657
  };
640
658
  })
641
659
  };
642
- }, H = (e) => e === void 0 || e === "memory" ? "memory" : typeof e.query == "function" ? e.engineKind === "memory" ? "memory" : "custom" : "vendor", U = class extends Error {
660
+ }, G = (e) => {
661
+ let t = /* @__PURE__ */ new Map(), n = 0, r = !1, i = async () => {
662
+ if (t.size === 0) return;
663
+ let r = t;
664
+ t = /* @__PURE__ */ new Map(), n = 0;
665
+ for (let [t, n] of r) try {
666
+ await e.flush(t, {
667
+ synced: n.synced,
668
+ removed: n.removed,
669
+ dropped: n.dropped
670
+ }, n.scope);
671
+ } catch {}
672
+ }, a = setInterval(() => {
673
+ i();
674
+ }, Math.max(1, e.intervalMs));
675
+ return a.unref?.(), {
676
+ bump: (a, o, s) => {
677
+ if (r) return;
678
+ let c = t.get(a);
679
+ c === void 0 ? t.set(a, {
680
+ synced: +(o === "synced"),
681
+ removed: +(o === "removed"),
682
+ dropped: +(o === "dropped"),
683
+ scope: s
684
+ }) : (o === "synced" ? c.synced += 1 : o === "removed" ? c.removed += 1 : c.dropped += 1, c.scope = s), n += 1, n >= e.maxBuffered && i();
685
+ },
686
+ flushNow: i,
687
+ shutdown: async () => {
688
+ r || (r = !0, clearInterval(a), await i());
689
+ },
690
+ pending: () => n
691
+ };
692
+ }, K = (e) => (t, n, r) => e().add(t, n, r), q = (e) => e === void 0 || e === "memory" ? "memory" : typeof e.query == "function" ? e.engineKind === "memory" ? "memory" : "custom" : "vendor", ge = class extends Error {
643
693
  _tag = "SearchBackendNotDurable";
644
694
  constructor(e) {
645
695
  super(e), this.name = "SearchBackendNotDurable";
646
696
  }
647
- }, pe = [
697
+ }, _e = [
648
698
  "plugin-search refuses to boot in production on the in-memory backend.",
649
699
  "",
650
700
  "The memory index lives in THIS process's heap. Two consequences, both silent:",
@@ -662,36 +712,36 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
662
712
  " searchPlugin({ singleProcessMemoryIndex: true, indexes })",
663
713
  "That is a claim about your topology, not a mute switch: if a second replica",
664
714
  "ever announces itself, the plugin logs that the claim was contradicted."
665
- ].join("\n"), me = [
715
+ ].join("\n"), ve = [
666
716
  "plugin-search is running the in-memory backend in production under",
667
717
  "`singleProcessMemoryIndex: true`. Holding you to the two conditions that makes true:",
668
718
  "exactly ONE process serves search, and it re-seeds every index at startup",
669
719
  "(`backfillIndex`) — the index is empty after each restart until it does."
670
- ].join(" "), W = (e) => e.backendKind !== "memory" || !e.production ? { level: "quiet" } : e.singleProcessDeclared ? {
720
+ ].join(" "), ye = (e) => e.backendKind !== "memory" || !e.production ? { level: "quiet" } : e.singleProcessDeclared ? {
671
721
  level: "note",
672
- message: me
722
+ message: ve
673
723
  } : {
674
724
  level: "refuse",
675
- message: pe
676
- }, G = (e, t) => t ? `search: replica "${e}" joined, but this app declared \`singleProcessMemoryIndex: true\`. That declaration is now false: each replica has its own in-memory index, so search results depend on which one serves the request. Configure a durable backend (typesense / meilisearch / algolia) or run one process.` : `search: replica "${e}" joined while search is served from an in-memory index. Each replica indexes only its OWN writes, so results depend on which replica answers. Configure a durable backend (typesense / meilisearch / algolia) before relying on these results.`, K = "_voltro_search_drift", q = h(K, {
677
- id: p({ prefix: "sdrft" }),
678
- indexName: g().maxLength(191),
679
- sourceTable: g().maxLength(191),
680
- rowId: g().maxLength(191),
681
- docId: g().maxLength(191),
682
- op: g().maxLength(16),
683
- attempts: m().default(0),
684
- lastError: g().maxLength(1e3),
685
- firstFailedAt: _(),
686
- lastFailedAt: _()
687
- }).unique("bySearchDriftIndexRow", ["indexName", "rowId"]).index("bySearchDriftIndex", ["indexName"]), J = (e, t) => ({
725
+ message: _e
726
+ }, be = (e, t) => t ? `search: replica "${e}" joined, but this app declared \`singleProcessMemoryIndex: true\`. That declaration is now false: each replica has its own in-memory index, so search results depend on which one serves the request. Configure a durable backend (typesense / meilisearch / algolia) or run one process.` : `search: replica "${e}" joined while search is served from an in-memory index. Each replica indexes only its OWN writes, so results depend on which replica answers. Configure a durable backend (typesense / meilisearch / algolia) before relying on these results.`, J = "_voltro_search_drift", xe = v(J, {
727
+ id: g({ prefix: "sdrft" }),
728
+ indexName: y().maxLength(191),
729
+ sourceTable: y().maxLength(191),
730
+ rowId: y().maxLength(191),
731
+ docId: y().maxLength(191),
732
+ op: y().maxLength(16),
733
+ attempts: _().default(0),
734
+ lastError: y().maxLength(1e3),
735
+ firstFailedAt: b(),
736
+ lastFailedAt: b()
737
+ }).unique("bySearchDriftIndexRow", ["indexName", "rowId"]).index("bySearchDriftIndex", ["indexName"]), Se = (e, t) => ({
688
738
  table: e,
689
- predicate: f("id", t),
739
+ predicate: h("id", t),
690
740
  order: [],
691
741
  take: 1,
692
742
  skip: void 0,
693
743
  projection: void 0
694
- }), Y = (e) => e ? new Date(e).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString(), he = (e) => ({
744
+ }), Y = (e) => e ? new Date(e).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString(), Ce = (e) => ({
695
745
  indexName: String(e.indexName),
696
746
  sourceTable: String(e.sourceTable),
697
747
  rowId: String(e.rowId),
@@ -701,7 +751,7 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
701
751
  lastError: String(e.lastError ?? ""),
702
752
  firstFailedAt: Y(e.firstFailedAt),
703
753
  lastFailedAt: Y(e.lastFailedAt)
704
- }), ge = () => {
754
+ }), we = () => {
705
755
  let e = /* @__PURE__ */ new Map(), t = (e, t) => `${e}\u0000${t}`;
706
756
  return {
707
757
  record: async (n) => {
@@ -731,8 +781,8 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
731
781
  e.delete(t(n, r));
732
782
  }
733
783
  };
734
- }, _e = () => `sdrft_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, X = (e, t) => ({
735
- table: K,
784
+ }, Te = () => `sdrft_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, X = (e, t) => ({
785
+ table: J,
736
786
  predicate: e,
737
787
  order: [{
738
788
  column: "firstFailedAt",
@@ -741,9 +791,9 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
741
791
  take: t,
742
792
  skip: void 0,
743
793
  projection: void 0
744
- }), ve = (e) => ({
794
+ }), Ee = (e) => ({
745
795
  record: async (t) => {
746
- let n = /* @__PURE__ */ new Date(), r = _e(), i = await e.insertIgnore(K, {
796
+ let n = /* @__PURE__ */ new Date(), r = Te(), i = await e.insertIgnore(J, {
747
797
  id: r,
748
798
  indexName: t.indexName,
749
799
  sourceTable: t.sourceTable,
@@ -755,27 +805,27 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
755
805
  firstFailedAt: n,
756
806
  lastFailedAt: n
757
807
  }, { conflictColumns: ["indexName", "rowId"] });
758
- String(i.id) !== r && await e.updateMany(K, {
808
+ String(i.id) !== r && await e.updateMany(J, {
759
809
  attempts: Number(i.attempts ?? 0) + 1,
760
810
  op: t.op,
761
811
  docId: t.docId,
762
812
  lastError: t.error.slice(0, 1e3),
763
813
  lastFailedAt: n
764
- }, { where: f("id", String(i.id)) });
814
+ }, { where: h("id", String(i.id)) });
765
815
  },
766
- list: async (t) => (await e.query(X(void 0, t))).map(he),
816
+ list: async (t) => (await e.query(X(void 0, t))).map(Ce),
767
817
  summary: async (t) => {
768
818
  let n = (await e.query({
769
- ...X(f("indexName", t), void 0),
819
+ ...X(h("indexName", t), void 0),
770
820
  order: [],
771
- aggregations: [d("n")]
821
+ aggregations: [m("n")]
772
822
  }))[0], r = Number(n?.n ?? n?.count ?? 0);
773
823
  if (r === 0) return {
774
824
  pending: 0,
775
825
  lastFailedAt: null
776
826
  };
777
827
  let i = await e.query({
778
- ...X(f("indexName", t), 1),
828
+ ...X(h("indexName", t), 1),
779
829
  order: [{
780
830
  column: "lastFailedAt",
781
831
  direction: "desc"
@@ -787,41 +837,47 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
787
837
  };
788
838
  },
789
839
  clear: async (t, n) => {
790
- await e.deleteMany(K, { where: u(f("indexName", t), f("rowId", n)) });
840
+ await e.deleteMany(J, { where: p(h("indexName", t), h("rowId", n)) });
791
841
  }
792
- }), ye = () => [q], be = (e, t) => {
793
- if (e === void 0 || e === "memory") return O();
842
+ }), De = () => [xe], Oe = (e, t) => {
843
+ if (e === void 0 || e === "memory") return A();
794
844
  if (typeof e.query == "function") return e;
795
845
  let n = e;
796
- return n.engine === "typesense" ? ne(n, t) : n.engine === "meilisearch" ? ae(n, t) : n.engine === "algolia" ? N(n, t) : O();
797
- }, xe = async (e, t, n) => {
846
+ return n.engine === "typesense" ? oe(n, t) : n.engine === "meilisearch" ? F(n, t) : n.engine === "algolia" ? I(n, t) : A();
847
+ }, ke = async (e, t, n) => {
798
848
  let r = n.map((e) => t.map(e));
799
849
  return r.length > 0 && await e.upsert(t.index, r), r.length;
800
- }, Se = async (e, t, n) => {
850
+ }, Z = async (e, t, n) => {
801
851
  if (n.op === "delete") {
802
852
  let r = n.old?.id;
803
853
  typeof r == "string" && await e.remove(t.index, [r]);
804
854
  return;
805
855
  }
806
856
  n.new && await e.upsert(t.index, [t.map(n.new)]);
807
- }, Z = {
857
+ }, Q = {
808
858
  retries: 5,
809
859
  retryBaseDelayMs: 200,
810
860
  retryMaxDelayMs: 1e4,
811
861
  resyncIntervalMs: 6e4,
812
- resyncBatchSize: 200
813
- }, Ce = (e) => ({
814
- retries: Math.max(0, e?.retries ?? Z.retries),
815
- retryBaseDelayMs: Math.max(1, e?.retryBaseDelayMs ?? Z.retryBaseDelayMs),
816
- retryMaxDelayMs: Math.max(1, e?.retryMaxDelayMs ?? Z.retryMaxDelayMs),
817
- resyncIntervalMs: Math.max(0, e?.resyncIntervalMs ?? Z.resyncIntervalMs),
818
- resyncBatchSize: Math.max(1, e?.resyncBatchSize ?? Z.resyncBatchSize)
819
- }), we = (e) => e instanceof w ? e : new w({
862
+ resyncBatchSize: 200,
863
+ reindexBatchSize: 1e3,
864
+ statsFlushIntervalMs: 5e3,
865
+ statsFlushMaxBuffered: 1e3
866
+ }, Ae = (e) => ({
867
+ retries: Math.max(0, e?.retries ?? Q.retries),
868
+ retryBaseDelayMs: Math.max(1, e?.retryBaseDelayMs ?? Q.retryBaseDelayMs),
869
+ retryMaxDelayMs: Math.max(1, e?.retryMaxDelayMs ?? Q.retryMaxDelayMs),
870
+ resyncIntervalMs: Math.max(0, e?.resyncIntervalMs ?? Q.resyncIntervalMs),
871
+ resyncBatchSize: Math.max(1, e?.resyncBatchSize ?? Q.resyncBatchSize),
872
+ reindexBatchSize: Math.max(1, e?.reindexBatchSize ?? Q.reindexBatchSize),
873
+ statsFlushIntervalMs: Math.max(0, e?.statsFlushIntervalMs ?? Q.statsFlushIntervalMs),
874
+ statsFlushMaxBuffered: Math.max(1, e?.statsFlushMaxBuffered ?? Q.statsFlushMaxBuffered)
875
+ }), je = (e) => e instanceof E ? e : new E({
820
876
  engine: "unknown",
821
877
  op: "upsert",
822
878
  message: String(e?.message ?? e),
823
879
  transient: !1
824
- }), Q = (e) => s.exponential(a.millis(e.retryBaseDelayMs), 2).pipe(s.either(s.spaced(a.millis(e.retryMaxDelayMs))), s.intersect(s.recurs(e.retries)), s.whileInput((e) => e.transient)), Te = (e) => {
880
+ }), Me = (e) => d.exponential(s.millis(e.retryBaseDelayMs), 2).pipe(d.either(d.spaced(s.millis(e.retryMaxDelayMs))), d.intersect(d.recurs(e.retries)), d.whileInput((e) => e.transient)), Ne = (e) => {
825
881
  if (!e || e === "memory" || typeof e.query == "function") return;
826
882
  let t = e;
827
883
  try {
@@ -829,80 +885,80 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
829
885
  } catch {
830
886
  return;
831
887
  }
832
- }, Ee = (e, t, n) => {
888
+ }, Pe = (e, t, n) => {
833
889
  let r = n ?? [];
834
890
  return e ? t == null ? null : [...r, {
835
891
  field: e,
836
892
  op: "eq",
837
893
  value: t
838
894
  }] : r;
839
- }, De = (e) => [
895
+ }, Fe = (e) => [
840
896
  ...(e.filters ?? []).map((e) => ["filter", e.field]),
841
897
  ...(e.facets ?? []).map((e) => ["facet", e]),
842
898
  ...(e.highlight?.fields ?? []).map((e) => ["highlight", e])
843
- ], $ = "@voltro/plugin-search", Oe = (i) => {
844
- let a = l({
899
+ ], $ = "@voltro/plugin-search", Ie = (o) => {
900
+ let s = ne({
845
901
  base: $,
846
- alias: i.alias,
847
- instance: i.name
848
- }), s = () => void 0, u = () => void 0, d = Ce(i.sync), f = Q(d), p = be(i.backend, {
849
- ...i.allowedEngineParams ? { allowEngineParams: i.allowedEngineParams } : {},
850
- onWarn: (e, t) => s(e, t)
851
- }), m = /* @__PURE__ */ new Map();
852
- for (let e of Object.values(i.indexes)) m.set(e.index, e);
853
- let h = H(i.backend), g = i.singleProcessMemoryIndex === !0, _ = !1, v, y = {
902
+ alias: o.alias,
903
+ instance: o.name
904
+ }), d = () => void 0, p = () => void 0, m = Ae(o.sync), h = Me(m), g = Oe(o.backend, {
905
+ ...o.allowedEngineParams ? { allowEngineParams: o.allowedEngineParams } : {},
906
+ onWarn: (e, t) => d(e, t)
907
+ }), _ = /* @__PURE__ */ new Map();
908
+ for (let e of Object.values(o.indexes)) _.set(e.index, e);
909
+ let v = q(o.backend), y = o.singleProcessMemoryIndex === !0, b = !1, x, S = {
854
910
  ...n,
855
911
  description: "Full-text search an index (facets/highlight/fuzzy/filters), auto-scoped to the caller tenant.",
856
912
  execute: (n, r) => {
857
- let { index: i, q: a, limit: s, offset: c, filters: l, facets: u, highlight: d, fuzziness: f, engineParams: h } = n, g = m.get(i);
858
- if (!g) return o.fail(new e({ index: i }));
859
- let _ = ee(De({
913
+ let { index: i, q: a, limit: o, offset: s, filters: l, facets: u, highlight: d, fuzziness: f, engineParams: p } = n, m = _.get(i);
914
+ if (!m) return c.fail(new e({ index: i }));
915
+ let h = re(Fe({
860
916
  ...l ? { filters: l } : {},
861
917
  ...u ? { facets: u } : {},
862
918
  ...d ? { highlight: d } : {}
863
- }), g.queryableFields);
864
- if (_) return o.fail(new t(_));
865
- let v = r.request.subject.tenantId ?? null, y = Ee(g.tenantField, v, l);
866
- if (y === null) return o.succeed({
919
+ }), m.queryableFields);
920
+ if (h) return c.fail(new t(h));
921
+ let ee = r.request.subject.tenantId ?? null, v = Pe(m.tenantField, ee, l);
922
+ if (v === null) return c.succeed({
867
923
  hits: [],
868
924
  facets: {}
869
925
  });
870
- let b = {
926
+ let y = {
871
927
  q: a,
872
- ...s === void 0 ? {} : { limit: s },
873
- ...c === void 0 ? {} : { offset: c },
874
- ...y.length > 0 ? { filters: y } : {},
928
+ ...o === void 0 ? {} : { limit: o },
929
+ ...s === void 0 ? {} : { offset: s },
930
+ ...v.length > 0 ? { filters: v } : {},
875
931
  ...u && u.length > 0 ? { facets: u } : {},
876
932
  ...d ? { highlight: d } : {},
877
933
  ...f === void 0 ? {} : { fuzziness: f },
878
- ...h ? { engineParams: h } : {}
934
+ ...p ? { engineParams: p } : {}
879
935
  };
880
- return o.promise(() => p.query(i, b));
936
+ return c.promise(() => g.query(i, y));
881
937
  }
882
- }, b = Te(i.backend), x = [
938
+ }, C = Ne(o.backend), ie = [
883
939
  "store:changes:read",
884
940
  "store:write",
885
941
  "inspect:read",
886
942
  "inspect:write",
887
- ...b ? [`network:outbound:${b}`] : []
888
- ], S = R(), C = ge(), w, T, E = (e, t, n) => o.tryPromise(() => S.bump(e, t, n)).pipe(o.catchAll((n) => o.sync(() => s("search stats bump failed", {
943
+ ...C ? [`network:outbound:${C}`] : []
944
+ ], w = V(), T = we(), E, D, O, k, A = (e, t, n) => k === void 0 ? c.tryPromise(() => w.bump(e, t, n)).pipe(c.catchAll((n) => c.sync(() => d("search stats bump failed", {
889
945
  index: e,
890
946
  kind: t,
891
947
  error: String(n)
892
- })))), D = async (e) => {
893
- let t = await C.list(e), n = 0, r = 0;
948
+ })))) : c.sync(() => k.bump(e, t, n)), j = async (e) => {
949
+ let t = await T.list(e), n = 0, r = 0;
894
950
  for (let e of t) {
895
- let t = m.get(e.indexName);
951
+ let t = _.get(e.indexName);
896
952
  if (!t) {
897
- await C.clear(e.indexName, e.rowId);
953
+ await T.clear(e.indexName, e.rowId);
898
954
  continue;
899
955
  }
900
956
  try {
901
- if (!T) throw Error("data store not bound");
902
- let r = (await T.query(J(e.sourceTable, e.rowId)))[0];
903
- r ? await p.upsert(t.index, [t.map(r)]) : await p.remove(t.index, [e.docId]), await C.clear(e.indexName, e.rowId), n++;
957
+ if (!D) throw Error("data store not bound");
958
+ let r = (await D.query(Se(e.sourceTable, e.rowId)))[0];
959
+ r ? await g.upsert(t.index, [t.map(r)]) : await g.remove(t.index, [e.docId]), await T.clear(e.indexName, e.rowId), n++;
904
960
  } catch (t) {
905
- r++, await C.record({
961
+ r++, await T.record({
906
962
  ...e,
907
963
  error: String(t?.message ?? t)
908
964
  }).catch(() => void 0);
@@ -913,29 +969,30 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
913
969
  repaired: n,
914
970
  failed: r
915
971
  };
916
- }, O = (e) => ({
972
+ }, M = (e) => ({
917
973
  kind: "json",
918
974
  data: e
919
- }), k = (e, t) => ({
975
+ }), N = (e, t) => ({
920
976
  kind: "json",
921
977
  status: e,
922
978
  data: { error: t }
923
979
  });
924
- return c({
925
- name: a,
980
+ return te({
981
+ name: s,
926
982
  baseName: $,
927
983
  description: "External search index sync (Typesense/Meilisearch/Algolia/memory) via the ChangeEvent tap + a tenant-scoped query route.",
928
- permissions: x,
929
- routes: [y],
984
+ permissions: ie,
985
+ routes: [S],
930
986
  rpcClientDescriptors: r,
931
987
  inspectEndpoints: [
932
988
  {
933
989
  method: "GET",
934
990
  path: "/indexes",
935
991
  description: "Configured indexes + durable, cross-replica sync stats + current index drift.",
936
- handler: () => o.promise(async () => {
937
- let e = await Promise.all(Object.entries(i.indexes).map(async ([e, t]) => {
938
- let n = await S.get(t.index), r = await C.summary(t.index);
992
+ handler: () => c.promise(async () => {
993
+ await k?.flushNow();
994
+ let e = await Promise.all(Object.entries(o.indexes).map(async ([e, t]) => {
995
+ let n = await w.get(t.index), r = await T.summary(t.index);
939
996
  return {
940
997
  table: e,
941
998
  index: t.index,
@@ -946,15 +1003,15 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
946
1003
  drifted: r.pending > 0
947
1004
  };
948
1005
  }));
949
- return O({
1006
+ return M({
950
1007
  indexes: e,
951
- backend: typeof i.backend == "string" ? i.backend : i.backend ? "custom/vendor" : "memory",
952
- durable: h !== "memory",
953
- singleProcessMemoryIndex: g,
1008
+ backend: typeof o.backend == "string" ? o.backend : o.backend ? "custom/vendor" : "memory",
1009
+ durable: v !== "memory",
1010
+ singleProcessMemoryIndex: y,
954
1011
  pendingDrift: e.reduce((e, t) => e + t.pendingDrift, 0),
955
1012
  sync: {
956
- ...d,
957
- resyncArmed: w !== void 0
1013
+ ...m,
1014
+ resyncArmed: E !== void 0
958
1015
  }
959
1016
  });
960
1017
  })
@@ -963,148 +1020,157 @@ var v = /^[A-Za-z_][A-Za-z0-9_.]*$/, y = (e) => v.test(e), ee = (e, t) => {
963
1020
  method: "GET",
964
1021
  path: "/drift",
965
1022
  description: "The changes that did NOT reach the engine, oldest first (the repair queue).",
966
- handler: (e) => o.promise(async () => {
967
- let t = Number(new URL(e.url, "http://localhost").searchParams.get("limit") ?? 100), n = await C.list(Number.isFinite(t) && t > 0 ? Math.min(t, 1e3) : 100);
968
- return O({ entries: n });
1023
+ handler: (e) => c.promise(async () => {
1024
+ let t = Number(new URL(e.url, "http://localhost").searchParams.get("limit") ?? 100), n = await T.list(Number.isFinite(t) && t > 0 ? Math.min(t, 1e3) : 100);
1025
+ return M({ entries: n });
969
1026
  })
970
1027
  },
971
1028
  {
972
1029
  method: "POST",
973
1030
  path: "/resync",
974
1031
  description: "Repair drifted rows now — re-reads each from the DB and re-applies it.",
975
- handler: (e) => o.promise(async () => {
1032
+ handler: (e) => c.promise(async () => {
976
1033
  let t;
977
1034
  try {
978
1035
  t = JSON.parse(e.body || "{}");
979
1036
  } catch {
980
- return k(400, "invalid JSON body");
1037
+ return N(400, "invalid JSON body");
981
1038
  }
982
- if (!T) return k(503, "data store not bound yet");
1039
+ if (!D) return N(503, "data store not bound yet");
983
1040
  try {
984
- let e = await D(Math.min(Math.max(1, t.limit ?? d.resyncBatchSize), 1e3));
985
- return O({
1041
+ let e = await j(Math.min(Math.max(1, t.limit ?? m.resyncBatchSize), 1e3));
1042
+ return M({
986
1043
  ok: !0,
987
1044
  ...e
988
1045
  });
989
1046
  } catch (e) {
990
- return k(500, e.message);
1047
+ return N(500, e.message);
991
1048
  }
992
1049
  })
993
1050
  },
994
1051
  {
995
1052
  method: "POST",
996
1053
  path: "/reindex",
997
- description: "Re-seed an index from the table's current rows.",
998
- handler: (e) => o.promise(async () => {
1054
+ description: "Re-seed an index from the table's current rows (streamed in bounded batches).",
1055
+ handler: (e) => c.promise(async () => {
999
1056
  let t;
1000
1057
  try {
1001
1058
  t = JSON.parse(e.body || "{}");
1002
1059
  } catch {
1003
- return k(400, "invalid JSON body");
1060
+ return N(400, "invalid JSON body");
1061
+ }
1062
+ let n = t.table, r = n ? o.indexes[n] : void 0;
1063
+ if (!n || !r) return N(404, `no index configured for table "${t.table ?? ""}"`);
1064
+ if (!O) return N(503, "data store not bound yet");
1065
+ let s = 0, d = await c.runPromiseExit(ee(O, {
1066
+ table: n,
1067
+ chunkSize: m.reindexBatchSize
1068
+ }).pipe(f.chunks, f.runForEach((e) => c.tryPromise(async () => {
1069
+ s += await ke(g, r, a.toReadonlyArray(e));
1070
+ }))));
1071
+ if (l.isFailure(d)) {
1072
+ let e = i.failureOption(d.cause), t = u.isSome(e) ? e.value : d.cause, n = t.cause ?? t.error ?? t;
1073
+ return N(500, String(n?.message ?? n));
1004
1074
  }
1005
- let n = t.table ? i.indexes[t.table] : void 0;
1006
- if (!t.table || !n) return k(404, `no index configured for table "${t.table ?? ""}"`);
1007
- if (!T) return k(503, "data store not bound yet");
1008
1075
  try {
1009
- let e = await T.query({
1010
- table: t.table,
1011
- predicate: void 0,
1012
- order: [],
1013
- take: void 0,
1014
- skip: void 0,
1015
- projection: void 0
1016
- }), r = await xe(p, n, e);
1017
- return await S.recordReindex(n.index, r, (/* @__PURE__ */ new Date()).toISOString()), O({
1018
- ok: !0,
1019
- table: t.table,
1020
- index: n.index,
1021
- count: r
1022
- });
1076
+ await w.recordReindex(r.index, s, (/* @__PURE__ */ new Date()).toISOString());
1023
1077
  } catch (e) {
1024
- return k(500, e.message);
1078
+ return N(500, e.message);
1025
1079
  }
1080
+ return M({
1081
+ ok: !0,
1082
+ table: n,
1083
+ index: r.index,
1084
+ count: s
1085
+ });
1026
1086
  })
1027
1087
  }
1028
1088
  ],
1029
- extendSchema: { tables: [...L(), ...ye()] },
1089
+ extendSchema: { tables: [...B(), ...De()] },
1030
1090
  bindDataStore: (e, t) => {
1031
- T = e, S = V(e), C = ve(e), h === "memory" && t?.membership !== void 0 && (v = t.membership.onChange((e) => {
1032
- e.kind === "left" || _ || t.instanceId !== void 0 && e.instanceId === t.instanceId || (_ = !0, s(G(e.instanceId, g), {
1091
+ D = e, O = e, w = W(e), T = Ee(e), v === "memory" && t?.membership !== void 0 && (x = t.membership.onChange((e) => {
1092
+ e.kind === "left" || b || t.instanceId !== void 0 && e.instanceId === t.instanceId || (b = !0, d(be(e.instanceId, y), {
1033
1093
  instanceId: t.instanceId ?? null,
1034
1094
  peer: e.instanceId,
1035
- indexes: Object.keys(i.indexes)
1095
+ indexes: Object.keys(o.indexes)
1036
1096
  }));
1037
- })), !(d.resyncIntervalMs <= 0 || t?.scheduleCoordinated === void 0) && (w = t.scheduleCoordinated("search.resync", d.resyncIntervalMs, async () => {
1097
+ })), !(m.resyncIntervalMs <= 0 || t?.scheduleCoordinated === void 0) && (E = t.scheduleCoordinated("search.resync", m.resyncIntervalMs, async () => {
1038
1098
  try {
1039
- let e = await D(d.resyncBatchSize);
1040
- return (e.repaired > 0 || e.failed > 0) && u("search: drift repair pass", e), { idle: e.scanned === 0 };
1099
+ let e = await j(m.resyncBatchSize);
1100
+ return (e.repaired > 0 || e.failed > 0) && p("search: drift repair pass", e), { idle: e.scanned === 0 };
1041
1101
  } catch (e) {
1042
- return s("search: drift repair pass failed", { error: String(e?.message ?? e) }), { idle: !1 };
1102
+ return d("search: drift repair pass failed", { error: String(e?.message ?? e) }), { idle: !1 };
1043
1103
  }
1044
1104
  }));
1045
1105
  },
1046
1106
  onChangeEvent: (e) => {
1047
- let t = i.indexes[e.table];
1048
- if (!t) return o.void;
1049
- let n = e.changeScope, r = e.changeScope === "fleet" || e.origin !== "injected", a = e.op === "delete" ? e.old : e.new, c = typeof a?.id == "string" ? a.id : "", l = e.op === "delete" ? "remove" : "upsert", u = () => {
1050
- if (e.op === "delete" || !e.new) return c;
1107
+ let t = o.indexes[e.table];
1108
+ if (!t) return c.void;
1109
+ let n = e.changeScope, r = e.changeScope === "fleet" || e.origin !== "injected", i = e.op === "delete" ? e.old : e.new, a = typeof i?.id == "string" ? i.id : "", s = e.op === "delete" ? "remove" : "upsert", l = () => {
1110
+ if (e.op === "delete" || !e.new) return a;
1051
1111
  try {
1052
- return String(t.map(e.new).id ?? c);
1112
+ return String(t.map(e.new).id ?? a);
1053
1113
  } catch {
1054
- return c;
1114
+ return a;
1055
1115
  }
1056
1116
  };
1057
- return o.tryPromise({
1058
- try: () => Se(p, t, e),
1059
- catch: we
1060
- }).pipe(o.retry(f)).pipe(o.matchEffect({
1061
- onSuccess: () => r ? E(t.index, e.op === "delete" ? "removed" : "synced", n) : o.void,
1117
+ return c.tryPromise({
1118
+ try: () => Z(g, t, e),
1119
+ catch: je
1120
+ }).pipe(c.retry(h)).pipe(c.matchEffect({
1121
+ onSuccess: () => r ? A(t.index, e.op === "delete" ? "removed" : "synced", n) : c.void,
1062
1122
  onFailure: (r) => {
1063
1123
  let i = {
1064
1124
  table: e.table,
1065
1125
  index: t.index,
1066
1126
  op: e.op,
1067
- rowId: c,
1127
+ rowId: a,
1068
1128
  transient: r.transient,
1069
1129
  error: r.message
1070
1130
  };
1071
- return c === "" ? o.sync(() => s("search: change not indexed and NOT recoverable (row has no id)", i)).pipe(o.zipRight(o.fail(r))) : o.tryPromise(() => C.record({
1131
+ return a === "" ? c.sync(() => d("search: change not indexed and NOT recoverable (row has no id)", i)).pipe(c.zipRight(c.fail(r))) : c.tryPromise(() => T.record({
1072
1132
  indexName: t.index,
1073
1133
  sourceTable: e.table,
1074
- rowId: c,
1075
- docId: u(),
1076
- op: l,
1134
+ rowId: a,
1135
+ docId: l(),
1136
+ op: s,
1077
1137
  error: r.message
1078
- })).pipe(o.matchEffect({
1079
- onSuccess: () => E(t.index, "dropped", n).pipe(o.zipRight(o.sync(() => s("search: index drift recorded — will be repaired from the database", i)))),
1080
- onFailure: (e) => o.sync(() => s("search: change LOST — engine failed and the drift ledger could not record it", {
1138
+ })).pipe(c.matchEffect({
1139
+ onSuccess: () => A(t.index, "dropped", n).pipe(c.zipRight(c.sync(() => d("search: index drift recorded — will be repaired from the database", i)))),
1140
+ onFailure: (e) => c.sync(() => d("search: change LOST — engine failed and the drift ledger could not record it", {
1081
1141
  ...i,
1082
1142
  ledgerError: String(e)
1083
- })).pipe(o.zipRight(o.fail(r)))
1143
+ })).pipe(c.zipRight(c.fail(r)))
1084
1144
  }));
1085
1145
  }
1086
1146
  }));
1087
1147
  },
1088
- onActivate: (e) => o.suspend(() => {
1089
- s = (t, n) => e.logger.warn(t, n), u = (t, n) => e.logger.info(t, n);
1090
- let t = W({
1091
- backendKind: h,
1148
+ onActivate: (e) => c.suspend(() => {
1149
+ d = (t, n) => e.logger.warn(t, n), p = (t, n) => e.logger.info(t, n);
1150
+ let t = ye({
1151
+ backendKind: v,
1092
1152
  production: (e.env?.NODE_ENV ?? process.env.NODE_ENV) === "production",
1093
- singleProcessDeclared: g
1153
+ singleProcessDeclared: y
1094
1154
  });
1095
- return t.level === "refuse" ? o.fail(new U(t.message)) : (t.level === "note" && e.logger.info(t.message, { indexes: Object.keys(i.indexes) }), o.sync(() => {
1155
+ return t.level === "refuse" ? c.fail(new ge(t.message)) : (t.level === "note" && e.logger.info(t.message, { indexes: Object.keys(o.indexes) }), m.statsFlushIntervalMs > 0 && k === void 0 && (k = G({
1156
+ flush: K(() => w),
1157
+ intervalMs: m.statsFlushIntervalMs,
1158
+ maxBuffered: m.statsFlushMaxBuffered
1159
+ })), c.sync(() => {
1096
1160
  e.logger.info("search active", {
1097
- indexes: Object.keys(i.indexes),
1098
- backend: typeof i.backend == "string" ? i.backend : "custom/vendor",
1099
- durable: h !== "memory",
1100
- sync: d
1161
+ indexes: Object.keys(o.indexes),
1162
+ backend: typeof o.backend == "string" ? o.backend : "custom/vendor",
1163
+ durable: v !== "memory",
1164
+ sync: m
1101
1165
  });
1102
1166
  }));
1103
1167
  }),
1104
- onDeactivate: () => o.sync(() => {
1105
- w?.stop(), w = void 0, v?.(), v = void 0, _ = !1;
1168
+ onDeactivate: () => c.promise(async () => {
1169
+ E?.stop(), E = void 0, x?.(), x = void 0, b = !1;
1170
+ let e = k;
1171
+ k = void 0, await e?.shutdown();
1106
1172
  })
1107
1173
  });
1108
1174
  };
1109
1175
  //#endregion
1110
- export { v as FIELD_NAME_PATTERN, K as SEARCH_DRIFT_TABLE, P as SEARCH_STATS_TABLE, Z as SYNC_DEFAULTS, w as SearchBackendError, U as SearchBackendNotDurable, t as SearchFieldRejected, e as SearchIndexNotFound, N as algoliaBackend, C as allowedEngineParams, Se as applyChange, we as asBackendError, W as auditMemoryBackend, H as backendKindOf, xe as backfillIndex, ve as dataStoreDriftLedger, V as dataStoreStatsStore, J as driftSourceQuery, ye as driftTables, y as isSafeFieldName, ae as meilisearchBackend, O as memoryBackend, ge as memoryDriftLedger, R as memoryStatsStore, G as peerObservedWarning, Ce as resolveSyncOptions, S as sanitizeEngineParams, Ee as scopeSearchFilters, q as searchDriftTable, Oe as searchPlugin, I as searchStatsTable, L as searchTables, Q as syncRetrySchedule, ne as typesenseBackend };
1176
+ export { x as FIELD_NAME_PATTERN, J as SEARCH_DRIFT_TABLE, L as SEARCH_STATS_TABLE, Q as SYNC_DEFAULTS, E as SearchBackendError, ge as SearchBackendNotDurable, t as SearchFieldRejected, e as SearchIndexNotFound, I as algoliaBackend, T as allowedEngineParams, Z as applyChange, je as asBackendError, ye as auditMemoryBackend, q as backendKindOf, ke as backfillIndex, Ee as dataStoreDriftLedger, W as dataStoreStatsStore, Se as driftSourceQuery, De as driftTables, S as isSafeFieldName, G as makeSearchStatsBuffer, F as meilisearchBackend, A as memoryBackend, we as memoryDriftLedger, V as memoryStatsStore, be as peerObservedWarning, Ae as resolveSyncOptions, w as sanitizeEngineParams, Pe as scopeSearchFilters, xe as searchDriftTable, Ie as searchPlugin, z as searchStatsTable, B as searchTables, K as statsStoreFlush, Me as syncRetrySchedule, oe as typesenseBackend };