@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/CHANGELOG.md +167 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +317 -251
- package/dist/{rpc-BQBNr0OU.js → rpc-DaYt-dP6.js} +1 -0
- package/dist/rpc.js +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { a as e, i as t, n, r } from "./rpc-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
|
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 (!
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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(
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
150
|
-
case "nin": return
|
|
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] = [
|
|
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" ?
|
|
166
|
-
for (let n of e.split(/\s+/)) if (
|
|
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
|
-
},
|
|
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
|
-
},
|
|
219
|
+
}, M = async (e, t, n) => {
|
|
220
220
|
try {
|
|
221
221
|
return await n();
|
|
222
222
|
} catch {
|
|
223
|
-
throw new
|
|
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
|
-
},
|
|
231
|
-
let { params: r, appAllowed: i, dropped: a } =
|
|
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
|
-
},
|
|
240
|
-
if (!
|
|
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
|
-
},
|
|
248
|
-
let t = (e) => JSON.stringify(e), n =
|
|
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}:[${
|
|
257
|
-
case "nin": return `${n}:!=[${
|
|
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
|
-
},
|
|
260
|
-
let n =
|
|
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(
|
|
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
|
|
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
|
|
302
|
+
return se(await o.collections(e).documents().search(m));
|
|
303
303
|
})
|
|
304
304
|
};
|
|
305
|
-
},
|
|
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
|
-
},
|
|
323
|
-
let t = (e) => JSON.stringify(e), n =
|
|
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 [${
|
|
332
|
-
case "nin": return `${n} NOT IN [${
|
|
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
|
-
},
|
|
335
|
-
let n =
|
|
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(
|
|
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
|
|
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
|
|
375
|
+
return le(await (await i()).index(e).search(t, p), u);
|
|
376
376
|
})
|
|
377
377
|
};
|
|
378
|
-
},
|
|
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
|
-
}),
|
|
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
|
|
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
|
-
},
|
|
401
|
+
}, fe = (e) => {
|
|
402
402
|
let t = [], n = [];
|
|
403
403
|
for (let r of e ?? []) {
|
|
404
|
-
let e =
|
|
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(
|
|
413
|
+
t.push(D(r.value).map((t) => `${e}:${i(t)}`));
|
|
414
414
|
break;
|
|
415
415
|
case "nin":
|
|
416
|
-
for (let n of
|
|
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
|
-
},
|
|
437
|
-
let n =
|
|
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
|
|
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 } =
|
|
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
|
|
484
|
+
return pe(await (await i()).searchSingleIndex({
|
|
485
485
|
indexName: e,
|
|
486
486
|
searchParams: h
|
|
487
487
|
}), l);
|
|
488
488
|
})
|
|
489
489
|
};
|
|
490
|
-
},
|
|
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
|
-
}),
|
|
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
|
-
}),
|
|
511
|
-
id:
|
|
512
|
-
indexName:
|
|
513
|
-
replicaId:
|
|
514
|
-
synced:
|
|
515
|
-
removed:
|
|
516
|
-
dropped:
|
|
517
|
-
scope:
|
|
518
|
-
lastReindexAt:
|
|
519
|
-
lastReindexCount:
|
|
520
|
-
updatedAt:
|
|
521
|
-
}).unique("bySearchStatsIndexReplica", ["indexName", "replicaId"]).index("bySearchStatsIndex", ["indexName"]),
|
|
522
|
-
let e = /* @__PURE__ */ new Map(), t = (t) => e.get(t) ??
|
|
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
|
-
},
|
|
549
|
-
table:
|
|
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
|
-
}),
|
|
556
|
-
let n = async (n) => (await e.query(
|
|
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
|
|
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 <
|
|
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:
|
|
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 =
|
|
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
|
|
610
|
+
throw new E({
|
|
602
611
|
engine: "stats",
|
|
603
612
|
op: "upsert",
|
|
604
|
-
message: `search stats: contention on (${i}, ${t}) exceeded ${
|
|
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(
|
|
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
|
-
...
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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"),
|
|
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(" "),
|
|
720
|
+
].join(" "), ye = (e) => e.backendKind !== "memory" || !e.production ? { level: "quiet" } : e.singleProcessDeclared ? {
|
|
671
721
|
level: "note",
|
|
672
|
-
message:
|
|
722
|
+
message: ve
|
|
673
723
|
} : {
|
|
674
724
|
level: "refuse",
|
|
675
|
-
message:
|
|
676
|
-
},
|
|
677
|
-
id:
|
|
678
|
-
indexName:
|
|
679
|
-
sourceTable:
|
|
680
|
-
rowId:
|
|
681
|
-
docId:
|
|
682
|
-
op:
|
|
683
|
-
attempts:
|
|
684
|
-
lastError:
|
|
685
|
-
firstFailedAt:
|
|
686
|
-
lastFailedAt:
|
|
687
|
-
}).unique("bySearchDriftIndexRow", ["indexName", "rowId"]).index("bySearchDriftIndex", ["indexName"]),
|
|
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:
|
|
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(),
|
|
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
|
-
}),
|
|
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
|
-
},
|
|
735
|
-
table:
|
|
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
|
-
}),
|
|
794
|
+
}), Ee = (e) => ({
|
|
745
795
|
record: async (t) => {
|
|
746
|
-
let n = /* @__PURE__ */ new Date(), r =
|
|
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(
|
|
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:
|
|
814
|
+
}, { where: h("id", String(i.id)) });
|
|
765
815
|
},
|
|
766
|
-
list: async (t) => (await e.query(X(void 0, t))).map(
|
|
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(
|
|
819
|
+
...X(h("indexName", t), void 0),
|
|
770
820
|
order: [],
|
|
771
|
-
aggregations: [
|
|
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(
|
|
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(
|
|
840
|
+
await e.deleteMany(J, { where: p(h("indexName", t), h("rowId", n)) });
|
|
791
841
|
}
|
|
792
|
-
}),
|
|
793
|
-
if (e === void 0 || e === "memory") return
|
|
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" ?
|
|
797
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
857
|
+
}, Q = {
|
|
808
858
|
retries: 5,
|
|
809
859
|
retryBaseDelayMs: 200,
|
|
810
860
|
retryMaxDelayMs: 1e4,
|
|
811
861
|
resyncIntervalMs: 6e4,
|
|
812
|
-
resyncBatchSize: 200
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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
|
-
}),
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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",
|
|
844
|
-
let
|
|
899
|
+
], $ = "@voltro/plugin-search", Ie = (o) => {
|
|
900
|
+
let s = ne({
|
|
845
901
|
base: $,
|
|
846
|
-
alias:
|
|
847
|
-
instance:
|
|
848
|
-
}),
|
|
849
|
-
...
|
|
850
|
-
onWarn: (e, t) =>
|
|
851
|
-
}),
|
|
852
|
-
for (let e of Object.values(
|
|
853
|
-
let
|
|
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:
|
|
858
|
-
if (!
|
|
859
|
-
let
|
|
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
|
-
}),
|
|
864
|
-
if (
|
|
865
|
-
let
|
|
866
|
-
if (
|
|
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
|
|
926
|
+
let y = {
|
|
871
927
|
q: a,
|
|
872
|
-
...
|
|
873
|
-
...
|
|
874
|
-
...
|
|
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
|
-
...
|
|
934
|
+
...p ? { engineParams: p } : {}
|
|
879
935
|
};
|
|
880
|
-
return
|
|
936
|
+
return c.promise(() => g.query(i, y));
|
|
881
937
|
}
|
|
882
|
-
},
|
|
938
|
+
}, C = Ne(o.backend), ie = [
|
|
883
939
|
"store:changes:read",
|
|
884
940
|
"store:write",
|
|
885
941
|
"inspect:read",
|
|
886
942
|
"inspect:write",
|
|
887
|
-
...
|
|
888
|
-
],
|
|
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
|
-
})))),
|
|
893
|
-
let t = await
|
|
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 =
|
|
951
|
+
let t = _.get(e.indexName);
|
|
896
952
|
if (!t) {
|
|
897
|
-
await
|
|
953
|
+
await T.clear(e.indexName, e.rowId);
|
|
898
954
|
continue;
|
|
899
955
|
}
|
|
900
956
|
try {
|
|
901
|
-
if (!
|
|
902
|
-
let r = (await
|
|
903
|
-
r ? await
|
|
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
|
|
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
|
-
},
|
|
972
|
+
}, M = (e) => ({
|
|
917
973
|
kind: "json",
|
|
918
974
|
data: e
|
|
919
|
-
}),
|
|
975
|
+
}), N = (e, t) => ({
|
|
920
976
|
kind: "json",
|
|
921
977
|
status: e,
|
|
922
978
|
data: { error: t }
|
|
923
979
|
});
|
|
924
|
-
return
|
|
925
|
-
name:
|
|
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:
|
|
929
|
-
routes: [
|
|
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: () =>
|
|
937
|
-
|
|
938
|
-
|
|
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
|
|
1006
|
+
return M({
|
|
950
1007
|
indexes: e,
|
|
951
|
-
backend: typeof
|
|
952
|
-
durable:
|
|
953
|
-
singleProcessMemoryIndex:
|
|
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
|
-
...
|
|
957
|
-
resyncArmed:
|
|
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) =>
|
|
967
|
-
let t = Number(new URL(e.url, "http://localhost").searchParams.get("limit") ?? 100), n = await
|
|
968
|
-
return
|
|
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) =>
|
|
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
|
|
1037
|
+
return N(400, "invalid JSON body");
|
|
981
1038
|
}
|
|
982
|
-
if (!
|
|
1039
|
+
if (!D) return N(503, "data store not bound yet");
|
|
983
1040
|
try {
|
|
984
|
-
let e = await
|
|
985
|
-
return
|
|
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
|
|
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) =>
|
|
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
|
|
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
|
-
|
|
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
|
|
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: [...
|
|
1089
|
+
extendSchema: { tables: [...B(), ...De()] },
|
|
1030
1090
|
bindDataStore: (e, t) => {
|
|
1031
|
-
|
|
1032
|
-
e.kind === "left" ||
|
|
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(
|
|
1095
|
+
indexes: Object.keys(o.indexes)
|
|
1036
1096
|
}));
|
|
1037
|
-
})), !(
|
|
1097
|
+
})), !(m.resyncIntervalMs <= 0 || t?.scheduleCoordinated === void 0) && (E = t.scheduleCoordinated("search.resync", m.resyncIntervalMs, async () => {
|
|
1038
1098
|
try {
|
|
1039
|
-
let e = await
|
|
1040
|
-
return (e.repaired > 0 || e.failed > 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
|
|
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 =
|
|
1048
|
-
if (!t) return
|
|
1049
|
-
let n = e.changeScope, r = e.changeScope === "fleet" || e.origin !== "injected",
|
|
1050
|
-
if (e.op === "delete" || !e.new) return
|
|
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 ??
|
|
1112
|
+
return String(t.map(e.new).id ?? a);
|
|
1053
1113
|
} catch {
|
|
1054
|
-
return
|
|
1114
|
+
return a;
|
|
1055
1115
|
}
|
|
1056
1116
|
};
|
|
1057
|
-
return
|
|
1058
|
-
try: () =>
|
|
1059
|
-
catch:
|
|
1060
|
-
}).pipe(
|
|
1061
|
-
onSuccess: () => r ?
|
|
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:
|
|
1127
|
+
rowId: a,
|
|
1068
1128
|
transient: r.transient,
|
|
1069
1129
|
error: r.message
|
|
1070
1130
|
};
|
|
1071
|
-
return
|
|
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:
|
|
1075
|
-
docId:
|
|
1076
|
-
op:
|
|
1134
|
+
rowId: a,
|
|
1135
|
+
docId: l(),
|
|
1136
|
+
op: s,
|
|
1077
1137
|
error: r.message
|
|
1078
|
-
})).pipe(
|
|
1079
|
-
onSuccess: () =>
|
|
1080
|
-
onFailure: (e) =>
|
|
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(
|
|
1143
|
+
})).pipe(c.zipRight(c.fail(r)))
|
|
1084
1144
|
}));
|
|
1085
1145
|
}
|
|
1086
1146
|
}));
|
|
1087
1147
|
},
|
|
1088
|
-
onActivate: (e) =>
|
|
1089
|
-
|
|
1090
|
-
let t =
|
|
1091
|
-
backendKind:
|
|
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:
|
|
1153
|
+
singleProcessDeclared: y
|
|
1094
1154
|
});
|
|
1095
|
-
return t.level === "refuse" ?
|
|
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(
|
|
1098
|
-
backend: typeof
|
|
1099
|
-
durable:
|
|
1100
|
-
sync:
|
|
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: () =>
|
|
1105
|
-
|
|
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 {
|
|
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 };
|