@basaltkit/search 1.1.0 → 1.3.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.d.ts +7 -1
- package/dist/index.js +24 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -103,6 +103,12 @@ declare class MeilisearchError extends BasaltError {
|
|
|
103
103
|
readonly httpStatus: number;
|
|
104
104
|
constructor(httpStatus: number, message: string);
|
|
105
105
|
}
|
|
106
|
+
declare class SearchFilterFieldError extends BasaltError {
|
|
107
|
+
constructor(field: string);
|
|
108
|
+
}
|
|
109
|
+
declare class SearchIndexNameError extends BasaltError {
|
|
110
|
+
constructor(name: string);
|
|
111
|
+
}
|
|
106
112
|
interface MeilisearchDriverOptions {
|
|
107
113
|
host: string;
|
|
108
114
|
apiKey?: string;
|
|
@@ -166,4 +172,4 @@ interface SearchPluginOptions {
|
|
|
166
172
|
}
|
|
167
173
|
declare function searchPlugin(options?: SearchPluginOptions): _basaltkit_core.BasaltPlugin<unknown>;
|
|
168
174
|
|
|
169
|
-
export { type IndexDefinition, MeilisearchDriver, type MeilisearchDriverOptions, MeilisearchError, MemorySearchDriver, SEARCH, Search, type SearchDocument, type SearchDriver, type SearchHit, type SearchOptions, type SearchPluginOptions, type SearchQuery, type SearchResult, type SyncRule, TenantRequiredError, defineIndex, searchPlugin, syncRule };
|
|
175
|
+
export { type IndexDefinition, MeilisearchDriver, type MeilisearchDriverOptions, MeilisearchError, MemorySearchDriver, SEARCH, Search, type SearchDocument, type SearchDriver, SearchFilterFieldError, type SearchHit, SearchIndexNameError, type SearchOptions, type SearchPluginOptions, type SearchQuery, type SearchResult, type SyncRule, TenantRequiredError, defineIndex, searchPlugin, syncRule };
|
package/dist/index.js
CHANGED
|
@@ -128,6 +128,22 @@ var MeilisearchError = class extends BasaltError2 {
|
|
|
128
128
|
}
|
|
129
129
|
httpStatus;
|
|
130
130
|
};
|
|
131
|
+
var SearchFilterFieldError = class extends BasaltError2 {
|
|
132
|
+
constructor(field) {
|
|
133
|
+
super("SEARCH_INVALID_FILTER_FIELD", `Invalid filter field name: ${JSON.stringify(field)}.`);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var SearchIndexNameError = class extends BasaltError2 {
|
|
137
|
+
constructor(name) {
|
|
138
|
+
super("SEARCH_INVALID_INDEX_NAME", `Invalid index name: ${JSON.stringify(name)}.`);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
var SAFE_INDEX_NAME = /^[A-Za-z0-9_-]+$/;
|
|
142
|
+
var assertValidIndexName = (name) => {
|
|
143
|
+
if (!SAFE_INDEX_NAME.test(name)) throw new SearchIndexNameError(name);
|
|
144
|
+
return name;
|
|
145
|
+
};
|
|
146
|
+
var SAFE_FILTER_FIELD = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
131
147
|
var primaryKey = (tenantId, id) => Buffer.from(`${tenantId}::${id}`).toString("base64url");
|
|
132
148
|
var quote = (value) => JSON.stringify(value);
|
|
133
149
|
var MeilisearchDriver = class {
|
|
@@ -138,6 +154,7 @@ var MeilisearchDriver = class {
|
|
|
138
154
|
options;
|
|
139
155
|
fetch;
|
|
140
156
|
async register(index) {
|
|
157
|
+
assertValidIndexName(index.name);
|
|
141
158
|
try {
|
|
142
159
|
await this.request("POST", "/indexes", { uid: index.name, primaryKey: "_pk" });
|
|
143
160
|
} catch {
|
|
@@ -151,16 +168,20 @@ var MeilisearchDriver = class {
|
|
|
151
168
|
await this.bulk(indexName, [document]);
|
|
152
169
|
}
|
|
153
170
|
async bulk(indexName, documents) {
|
|
171
|
+
assertValidIndexName(indexName);
|
|
154
172
|
const withPk = documents.map((d) => ({ ...d, _pk: primaryKey(d.tenantId, d.id) }));
|
|
155
173
|
await this.request("PUT", `/indexes/${indexName}/documents`, withPk);
|
|
156
174
|
}
|
|
157
175
|
async remove(indexName, tenantId, id) {
|
|
176
|
+
assertValidIndexName(indexName);
|
|
158
177
|
await this.request("DELETE", `/indexes/${indexName}/documents/${primaryKey(tenantId, id)}`);
|
|
159
178
|
}
|
|
160
179
|
async clear(indexName) {
|
|
180
|
+
assertValidIndexName(indexName);
|
|
161
181
|
await this.request("DELETE", `/indexes/${indexName}/documents`);
|
|
162
182
|
}
|
|
163
183
|
async search(indexName, query) {
|
|
184
|
+
assertValidIndexName(indexName);
|
|
164
185
|
const result = await this.request("POST", `/indexes/${indexName}/search`, {
|
|
165
186
|
q: query.q,
|
|
166
187
|
filter: this.buildFilter(query.tenantId, query.filters),
|
|
@@ -182,6 +203,7 @@ var MeilisearchDriver = class {
|
|
|
182
203
|
buildFilter(tenantId, filters) {
|
|
183
204
|
const parts = [`tenantId = ${quote(tenantId)}`];
|
|
184
205
|
for (const [field, value] of Object.entries(filters ?? {})) {
|
|
206
|
+
if (!SAFE_FILTER_FIELD.test(field)) throw new SearchFilterFieldError(field);
|
|
185
207
|
parts.push(Array.isArray(value) ? `${field} IN [${value.map(quote).join(", ")}]` : `${field} = ${quote(value)}`);
|
|
186
208
|
}
|
|
187
209
|
return parts.join(" AND ");
|
|
@@ -254,6 +276,8 @@ export {
|
|
|
254
276
|
MemorySearchDriver,
|
|
255
277
|
SEARCH,
|
|
256
278
|
Search,
|
|
279
|
+
SearchFilterFieldError,
|
|
280
|
+
SearchIndexNameError,
|
|
257
281
|
TenantRequiredError,
|
|
258
282
|
defineIndex,
|
|
259
283
|
searchPlugin,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basaltkit/search",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Full-text search for Basalt: tenant-scoped indexing and querying with a pluggable driver (in-memory for dev/test, Meilisearch for production) and automatic sync from domain events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|