@voltro/plugin-search 0.32.0 → 0.34.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 +2006 -0
- package/dist/index.d.ts +417 -12
- package/dist/index.js +759 -273
- package/dist/rpc-BQBNr0OU.js +61 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +2 -56
- package/dist/web.d.ts +10 -4
- package/package.json +6 -5
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
import { defineAction as t } from "@voltro/protocol";
|
|
3
|
+
//#region src/errors.ts
|
|
4
|
+
var n = class extends e.TaggedError()("SearchIndexNotFound", { index: e.String }) {}, r = class extends e.TaggedError()("SearchFieldRejected", {
|
|
5
|
+
field: e.String,
|
|
6
|
+
where: e.Literal("filter", "facet", "highlight"),
|
|
7
|
+
reason: e.Literal("not-an-identifier", "not-queryable")
|
|
8
|
+
}) {}, i = e.Union(e.String, e.Number, e.Boolean), a = e.Struct({
|
|
9
|
+
field: e.String,
|
|
10
|
+
op: e.Literal("eq", "neq", "gt", "gte", "lt", "lte", "in", "nin"),
|
|
11
|
+
value: e.Union(i, e.Array(i))
|
|
12
|
+
}), o = e.Struct({
|
|
13
|
+
fields: e.optional(e.Array(e.String)),
|
|
14
|
+
preTag: e.optional(e.String),
|
|
15
|
+
postTag: e.optional(e.String)
|
|
16
|
+
}), s = e.Struct({
|
|
17
|
+
doc: e.Record({
|
|
18
|
+
key: e.String,
|
|
19
|
+
value: e.Unknown
|
|
20
|
+
}),
|
|
21
|
+
highlights: e.optional(e.Record({
|
|
22
|
+
key: e.String,
|
|
23
|
+
value: e.String
|
|
24
|
+
}))
|
|
25
|
+
}), c = t({
|
|
26
|
+
name: "search.query",
|
|
27
|
+
input: e.Struct({
|
|
28
|
+
index: e.String,
|
|
29
|
+
q: e.String,
|
|
30
|
+
limit: e.optional(e.Number),
|
|
31
|
+
offset: e.optional(e.Number),
|
|
32
|
+
filters: e.optional(e.Array(a)),
|
|
33
|
+
facets: e.optional(e.Array(e.String)),
|
|
34
|
+
highlight: e.optional(o),
|
|
35
|
+
fuzziness: e.optional(e.Union(e.Number, e.Literal("auto"))),
|
|
36
|
+
engineParams: e.optional(e.Record({
|
|
37
|
+
key: e.String,
|
|
38
|
+
value: e.Unknown
|
|
39
|
+
}))
|
|
40
|
+
}),
|
|
41
|
+
output: e.Struct({
|
|
42
|
+
hits: e.Array(s),
|
|
43
|
+
facets: e.Record({
|
|
44
|
+
key: e.String,
|
|
45
|
+
value: e.Record({
|
|
46
|
+
key: e.String,
|
|
47
|
+
value: e.Number
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
}),
|
|
51
|
+
error: e.Union(n, r)
|
|
52
|
+
}), l = [{
|
|
53
|
+
tag: "search.query",
|
|
54
|
+
kind: "action",
|
|
55
|
+
import: {
|
|
56
|
+
module: "@voltro/plugin-search/rpc",
|
|
57
|
+
name: "queryDescriptor"
|
|
58
|
+
}
|
|
59
|
+
}];
|
|
60
|
+
//#endregion
|
|
61
|
+
export { n as a, r as i, c as n, l as r, a as t };
|
package/dist/rpc.d.ts
CHANGED
|
@@ -3,12 +3,19 @@ import { PluginRpcClientDescriptor } from '@voltro/protocol';
|
|
|
3
3
|
import { Schema } from 'effect';
|
|
4
4
|
|
|
5
5
|
export declare const queryDescriptor: ActionProcedureDescriptor<"search.query", Schema.Struct<{
|
|
6
|
+
/** One of the indexes the app declared. An unregistered name is refused
|
|
7
|
+
* (`SearchIndexNotFound`) — it has no spec, so it has no tenant field to
|
|
8
|
+
* scope by, and answering it would query an unscoped collection. */
|
|
6
9
|
index: typeof Schema.String;
|
|
7
10
|
q: typeof Schema.String;
|
|
8
11
|
limit: Schema.optional<typeof Schema.Number>;
|
|
9
12
|
offset: Schema.optional<typeof Schema.Number>;
|
|
10
13
|
/** Clauses ANDed together — equality, range, negation, set membership. */
|
|
11
14
|
filters: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
15
|
+
/** A doc field path. Validated server-side against the index's declared
|
|
16
|
+
* `queryableFields` (or a plain-identifier pattern) before it is spliced
|
|
17
|
+
* into the engine's filter DSL — a mismatch is a typed
|
|
18
|
+
* `SearchFieldRejected`, not a query. */
|
|
12
19
|
field: typeof Schema.String;
|
|
13
20
|
op: Schema.Literal<["eq", "neq", "gt", "gte", "lt", "lte", "in", "nin"]>;
|
|
14
21
|
value: Schema.Union<[Schema.Union<[typeof Schema.String, typeof Schema.Number, typeof Schema.Boolean]>, Schema.Array$<Schema.Union<[typeof Schema.String, typeof Schema.Number, typeof Schema.Boolean]>>]>;
|
|
@@ -23,7 +30,10 @@ export declare const queryDescriptor: ActionProcedureDescriptor<"search.query",
|
|
|
23
30
|
}>>;
|
|
24
31
|
/** Typo tolerance — a max edit distance (0 = exact) or `'auto'`. */
|
|
25
32
|
fuzziness: Schema.optional<Schema.Union<[typeof Schema.Number, Schema.Literal<["auto"]>]>>;
|
|
26
|
-
/** Escape hatch —
|
|
33
|
+
/** Escape hatch — the engine's presentation-only params (paging, ordering,
|
|
34
|
+
* typo tolerance, highlight shaping). Anything that could select a
|
|
35
|
+
* different document set is dropped server-side and logged; express a
|
|
36
|
+
* filter as a `filters[]` clause instead. */
|
|
27
37
|
engineParams: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
28
38
|
}>, Schema.Struct<{
|
|
29
39
|
hits: Schema.Array$<Schema.Struct<{
|
|
@@ -32,14 +42,60 @@ export declare const queryDescriptor: ActionProcedureDescriptor<"search.query",
|
|
|
32
42
|
}>>;
|
|
33
43
|
/** field → (value → count) for the requested facets. */
|
|
34
44
|
facets: Schema.Record$<typeof Schema.String, Schema.Record$<typeof Schema.String, typeof Schema.Number>>;
|
|
35
|
-
}>, typeof
|
|
45
|
+
}>, Schema.Union<[typeof SearchIndexNotFound, typeof SearchFieldRejected]>>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A field name the caller supplied — in `filters[].field`, `facets[]` or
|
|
49
|
+
* `highlight.fields[]` — was refused before it could reach the engine.
|
|
50
|
+
*
|
|
51
|
+
* `reason: 'not-an-identifier'` — the name is not a plain field path
|
|
52
|
+
* (`^[A-Za-z_][A-Za-z0-9_.]*$`). Every vendor adapter interpolates the name
|
|
53
|
+
* into that engine's filter DSL, so anything else is a control-plane injection
|
|
54
|
+
* (a Typesense `filter_by` is ONE flat string with `||`, so a crafted name
|
|
55
|
+
* re-groups the boolean tree around the appended tenant clause).
|
|
56
|
+
*
|
|
57
|
+
* `reason: 'not-queryable'` — the name is well-formed but not in the index's
|
|
58
|
+
* declared `queryableFields` allowlist.
|
|
59
|
+
*/
|
|
60
|
+
declare class SearchFieldRejected extends SearchFieldRejected_base {
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare const SearchFieldRejected_base: Schema.TaggedErrorClass<SearchFieldRejected, "SearchFieldRejected", {
|
|
64
|
+
readonly _tag: Schema.tag<"SearchFieldRejected">;
|
|
65
|
+
} & {
|
|
66
|
+
field: typeof Schema.String;
|
|
67
|
+
where: Schema.Literal<["filter", "facet", "highlight"]>;
|
|
68
|
+
reason: Schema.Literal<["not-an-identifier", "not-queryable"]>;
|
|
69
|
+
}>;
|
|
36
70
|
|
|
37
71
|
export declare const SearchFilterSchema: Schema.Struct<{
|
|
72
|
+
/** A doc field path. Validated server-side against the index's declared
|
|
73
|
+
* `queryableFields` (or a plain-identifier pattern) before it is spliced
|
|
74
|
+
* into the engine's filter DSL — a mismatch is a typed
|
|
75
|
+
* `SearchFieldRejected`, not a query. */
|
|
38
76
|
field: typeof Schema.String;
|
|
39
77
|
op: Schema.Literal<["eq", "neq", "gt", "gte", "lt", "lte", "in", "nin"]>;
|
|
40
78
|
value: Schema.Union<[Schema.Union<[typeof Schema.String, typeof Schema.Number, typeof Schema.Boolean]>, Schema.Array$<Schema.Union<[typeof Schema.String, typeof Schema.Number, typeof Schema.Boolean]>>]>;
|
|
41
79
|
}>;
|
|
42
80
|
|
|
81
|
+
/**
|
|
82
|
+
* The queried index is not one the app declared in `searchPlugin({ indexes })`.
|
|
83
|
+
*
|
|
84
|
+
* This is a REFUSAL, not an empty result, and the distinction is the whole
|
|
85
|
+
* point: an unknown index has no `IndexSpec`, therefore no `tenantField`,
|
|
86
|
+
* therefore no tenant clause — so answering it would run an unfiltered query
|
|
87
|
+
* against whatever collection of that name exists on the (usually shared)
|
|
88
|
+
* engine. Fail instead of querying something we cannot scope.
|
|
89
|
+
*/
|
|
90
|
+
declare class SearchIndexNotFound extends SearchIndexNotFound_base {
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare const SearchIndexNotFound_base: Schema.TaggedErrorClass<SearchIndexNotFound, "SearchIndexNotFound", {
|
|
94
|
+
readonly _tag: Schema.tag<"SearchIndexNotFound">;
|
|
95
|
+
} & {
|
|
96
|
+
index: typeof Schema.String;
|
|
97
|
+
}>;
|
|
98
|
+
|
|
43
99
|
/** Declared for the codegen (`VoltroPlugin.rpcClientDescriptors`) so each tag is
|
|
44
100
|
* emitted into the generated client group. Kept in lockstep with the exports. */
|
|
45
101
|
export declare const searchRpcClientImports: ReadonlyArray<PluginRpcClientDescriptor>;
|
package/dist/rpc.js
CHANGED
|
@@ -1,56 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/rpc.ts
|
|
4
|
-
var n = e.Union(e.String, e.Number, e.Boolean), r = e.Struct({
|
|
5
|
-
field: e.String,
|
|
6
|
-
op: e.Literal("eq", "neq", "gt", "gte", "lt", "lte", "in", "nin"),
|
|
7
|
-
value: e.Union(n, e.Array(n))
|
|
8
|
-
}), i = e.Struct({
|
|
9
|
-
fields: e.optional(e.Array(e.String)),
|
|
10
|
-
preTag: e.optional(e.String),
|
|
11
|
-
postTag: e.optional(e.String)
|
|
12
|
-
}), a = e.Struct({
|
|
13
|
-
doc: e.Record({
|
|
14
|
-
key: e.String,
|
|
15
|
-
value: e.Unknown
|
|
16
|
-
}),
|
|
17
|
-
highlights: e.optional(e.Record({
|
|
18
|
-
key: e.String,
|
|
19
|
-
value: e.String
|
|
20
|
-
}))
|
|
21
|
-
}), o = t({
|
|
22
|
-
name: "search.query",
|
|
23
|
-
input: e.Struct({
|
|
24
|
-
index: e.String,
|
|
25
|
-
q: e.String,
|
|
26
|
-
limit: e.optional(e.Number),
|
|
27
|
-
offset: e.optional(e.Number),
|
|
28
|
-
filters: e.optional(e.Array(r)),
|
|
29
|
-
facets: e.optional(e.Array(e.String)),
|
|
30
|
-
highlight: e.optional(i),
|
|
31
|
-
fuzziness: e.optional(e.Union(e.Number, e.Literal("auto"))),
|
|
32
|
-
engineParams: e.optional(e.Record({
|
|
33
|
-
key: e.String,
|
|
34
|
-
value: e.Unknown
|
|
35
|
-
}))
|
|
36
|
-
}),
|
|
37
|
-
output: e.Struct({
|
|
38
|
-
hits: e.Array(a),
|
|
39
|
-
facets: e.Record({
|
|
40
|
-
key: e.String,
|
|
41
|
-
value: e.Record({
|
|
42
|
-
key: e.String,
|
|
43
|
-
value: e.Number
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
}), s = [{
|
|
48
|
-
tag: "search.query",
|
|
49
|
-
kind: "action",
|
|
50
|
-
import: {
|
|
51
|
-
module: "@voltro/plugin-search/rpc",
|
|
52
|
-
name: "queryDescriptor"
|
|
53
|
-
}
|
|
54
|
-
}];
|
|
55
|
-
//#endregion
|
|
56
|
-
export { r as SearchFilterSchema, o as queryDescriptor, s as searchRpcClientImports };
|
|
1
|
+
import { n as e, r as t, t as n } from "./rpc-BQBNr0OU.js";
|
|
2
|
+
export { n as SearchFilterSchema, e as queryDescriptor, t as searchRpcClientImports };
|
package/dist/web.d.ts
CHANGED
|
@@ -13,11 +13,14 @@ export declare interface SearchHitOut<Doc> {
|
|
|
13
13
|
export declare interface SearchOptions {
|
|
14
14
|
readonly limit?: number;
|
|
15
15
|
readonly offset?: number;
|
|
16
|
-
/** Clauses ANDed together — equality, range, negation, set.
|
|
16
|
+
/** Clauses ANDed together — equality, range, negation, set. Each `field` is
|
|
17
|
+
* validated server-side (index allowlist, else a plain-identifier pattern);
|
|
18
|
+
* a mismatch is a typed `SearchFieldRejected`. */
|
|
17
19
|
readonly filters?: ReadonlyArray<SearchFilterInput>;
|
|
18
|
-
/** Facet-count fields (returned in `facets`). */
|
|
20
|
+
/** Facet-count fields (returned in `facets`). Validated like `filters[].field`. */
|
|
19
21
|
readonly facets?: ReadonlyArray<string>;
|
|
20
|
-
/** Matched-term highlighting (returned per-hit).
|
|
22
|
+
/** Matched-term highlighting (returned per-hit). `fields` is validated like
|
|
23
|
+
* `filters[].field`. */
|
|
21
24
|
readonly highlight?: {
|
|
22
25
|
readonly fields?: ReadonlyArray<string>;
|
|
23
26
|
readonly preTag?: string;
|
|
@@ -25,7 +28,10 @@ export declare interface SearchOptions {
|
|
|
25
28
|
};
|
|
26
29
|
/** Typo tolerance — a max edit distance (0 = exact) or `'auto'`. */
|
|
27
30
|
readonly fuzziness?: number | 'auto';
|
|
28
|
-
/** Escape hatch
|
|
31
|
+
/** Escape hatch, narrowed to the engine's presentation-only params (paging,
|
|
32
|
+
* ordering, typo tolerance, highlight shaping). Keys that could select a
|
|
33
|
+
* different document set are dropped server-side — express a filter as a
|
|
34
|
+
* `filters[]` clause, which is ANDed with the tenant scope. */
|
|
29
35
|
readonly engineParams?: Record<string, unknown>;
|
|
30
36
|
}
|
|
31
37
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Keep an external search index (Typesense / Meilisearch / Algolia) in sync with framework tables via the post-commit ChangeEvent tap, then query it — tenant-scoped, with a backfill path and a useSearch() hook.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"types": "./dist/rpc.d.ts",
|
|
33
33
|
"import": "./dist/rpc.js",
|
|
34
34
|
"default": "./dist/rpc.js"
|
|
35
|
-
}
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
36
37
|
},
|
|
37
38
|
"main": "./dist/index.js",
|
|
38
39
|
"module": "./dist/index.js",
|
|
@@ -42,9 +43,9 @@
|
|
|
42
43
|
"node": ">=24.0.0"
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
45
|
-
"@voltro/client": "0.
|
|
46
|
-
"@voltro/database": "0.
|
|
47
|
-
"@voltro/protocol": "0.
|
|
46
|
+
"@voltro/client": "0.34.0",
|
|
47
|
+
"@voltro/database": "0.34.0",
|
|
48
|
+
"@voltro/protocol": "0.34.0"
|
|
48
49
|
},
|
|
49
50
|
"optionalDependencies": {
|
|
50
51
|
"algoliasearch": "^5.56.0",
|