blackbox_db 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +195 -0
- package/package.json +12 -0
package/index.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BlackBox DB HTTP client.
|
|
3
|
+
* Uses global fetch (Node 18+). Throws on HTTP/network errors.
|
|
4
|
+
*/
|
|
5
|
+
export class BlackBoxClient {
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} [options]
|
|
8
|
+
* @param {string} [options.url="http://127.0.0.1"] - Base URL including protocol/host.
|
|
9
|
+
* @param {number} [options.port=8080] - Port to connect to.
|
|
10
|
+
*/
|
|
11
|
+
constructor({ url = "http://127.0.0.1", port = 8080 } = {}) {
|
|
12
|
+
this.baseUrl = this._buildBaseUrl(url, port);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_buildBaseUrl(url, port) {
|
|
16
|
+
if (!url) throw new Error("url is required");
|
|
17
|
+
const normalized = url.endsWith("/") ? url.slice(0, -1) : url;
|
|
18
|
+
return port ? `${normalized}:${port}` : normalized;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_toQuery(params = {}) {
|
|
22
|
+
const query = new URLSearchParams();
|
|
23
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
24
|
+
if (value === undefined || value === null) return;
|
|
25
|
+
query.append(key, String(value));
|
|
26
|
+
});
|
|
27
|
+
const qs = query.toString();
|
|
28
|
+
return qs ? `?${qs}` : "";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async _request(path, options = {}) {
|
|
32
|
+
const endpoint = `${this.baseUrl}${path}`;
|
|
33
|
+
const headers = { ...(options.headers || {}) };
|
|
34
|
+
if (options.body && !headers["Content-Type"]) {
|
|
35
|
+
headers["Content-Type"] = "application/json";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const response = await fetch(endpoint, { ...options, headers });
|
|
39
|
+
const contentType = response.headers.get("content-type") || "";
|
|
40
|
+
const isJson = contentType.includes("application/json");
|
|
41
|
+
const payload = isJson ? await response.json().catch(() => null) : null;
|
|
42
|
+
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const message = payload?.error?.message || response.statusText || "Request failed";
|
|
45
|
+
throw new Error(`HTTP ${response.status} ${message}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return payload ?? (await response.text());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Health & config
|
|
52
|
+
async health() {
|
|
53
|
+
return this._request("/v1/health");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async metrics() {
|
|
57
|
+
return this._request("/v1/metrics");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async prometheusMetrics() {
|
|
61
|
+
return this._request("/metrics", { headers: { Accept: "text/plain" } });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async config() {
|
|
65
|
+
return this._request("/v1/config");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Index management
|
|
69
|
+
async createIndex(body) {
|
|
70
|
+
return this._request("/v1/indexes", { method: "POST", body: JSON.stringify(body) });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async listIndexes() {
|
|
74
|
+
return this._request("/v1/indexes");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Snapshots / shipping
|
|
78
|
+
async saveSnapshot(path) {
|
|
79
|
+
const qs = this._toQuery(path ? { path } : {});
|
|
80
|
+
return this._request(`/v1/snapshot${qs}`, { method: "POST" });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async loadSnapshot(path) {
|
|
84
|
+
const qs = this._toQuery(path ? { path } : {});
|
|
85
|
+
return this._request(`/v1/snapshot/load${qs}`, { method: "POST" });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async shipPlan() {
|
|
89
|
+
return this._request("/v1/ship");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async shipApply(path) {
|
|
93
|
+
if (!path) throw new Error("path is required");
|
|
94
|
+
return this._request(`/v1/ship/apply${this._toQuery({ path })}`, { method: "POST" });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async shipFetchApply(base) {
|
|
98
|
+
if (!base) throw new Error("base is required");
|
|
99
|
+
return this._request(`/v1/ship/fetch_apply${this._toQuery({ base })}`, { method: "POST" });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Documents
|
|
103
|
+
async indexDocument(index, doc) {
|
|
104
|
+
if (!index) throw new Error("index is required");
|
|
105
|
+
return this._request(`/v1/${encodeURIComponent(index)}/doc`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
body: JSON.stringify(doc),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async bulkIndex(index, docs, { continueOnError = true } = {}) {
|
|
112
|
+
if (!index) throw new Error("index is required");
|
|
113
|
+
return this._request(`/v1/${encodeURIComponent(index)}/_bulk?continue_on_error=${continueOnError}`, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
body: JSON.stringify(Array.isArray(docs) ? docs : { docs }),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getDocument(index, id) {
|
|
120
|
+
if (!index || id === undefined || id === null) throw new Error("index and id are required");
|
|
121
|
+
return this._request(`/v1/${encodeURIComponent(index)}/doc/${encodeURIComponent(id)}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async replaceDocument(index, id, doc) {
|
|
125
|
+
if (!index || id === undefined || id === null) throw new Error("index and id are required");
|
|
126
|
+
return this._request(`/v1/${encodeURIComponent(index)}/doc/${encodeURIComponent(id)}`, {
|
|
127
|
+
method: "PUT",
|
|
128
|
+
body: JSON.stringify(doc),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async updateDocument(index, id, doc) {
|
|
133
|
+
if (!index || id === undefined || id === null) throw new Error("index and id are required");
|
|
134
|
+
return this._request(`/v1/${encodeURIComponent(index)}/doc/${encodeURIComponent(id)}`, {
|
|
135
|
+
method: "PATCH",
|
|
136
|
+
body: JSON.stringify(doc),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async deleteDocument(index, id) {
|
|
141
|
+
if (!index || id === undefined || id === null) throw new Error("index and id are required");
|
|
142
|
+
return this._request(`/v1/${encodeURIComponent(index)}/doc/${encodeURIComponent(id)}`, {
|
|
143
|
+
method: "DELETE",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async storedMatch(index, { field, value }) {
|
|
148
|
+
if (!index) throw new Error("index is required");
|
|
149
|
+
if (!field) throw new Error("field is required");
|
|
150
|
+
if (value === undefined || value === null) throw new Error("value is required");
|
|
151
|
+
return this._request(
|
|
152
|
+
`/v1/${encodeURIComponent(index)}/stored_match${this._toQuery({ field, value })}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Run a search query.
|
|
158
|
+
* @param {string} index - Index name.
|
|
159
|
+
* @param {Object} params - Querystring parameters (e.g., q, mode, from, size, vec).
|
|
160
|
+
*/
|
|
161
|
+
async search(index, params = {}) {
|
|
162
|
+
if (!index) throw new Error("index is required");
|
|
163
|
+
return this._request(
|
|
164
|
+
`/v1/${encodeURIComponent(index)}/search${this._toQuery(params)}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Custom aggregations/templates
|
|
169
|
+
async listCustomTemplates() {
|
|
170
|
+
return this._request("/v1/custom");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async getCustomTemplate(name) {
|
|
174
|
+
if (!name) throw new Error("name is required");
|
|
175
|
+
return this._request(`/v1/custom/${encodeURIComponent(name)}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async putCustomTemplate(name, template) {
|
|
179
|
+
if (!name) throw new Error("name is required");
|
|
180
|
+
return this._request(`/v1/custom/${encodeURIComponent(name)}`, {
|
|
181
|
+
method: "PUT",
|
|
182
|
+
body: JSON.stringify(template),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async executeCustomTemplate(name, params = {}) {
|
|
187
|
+
if (!name) throw new Error("name is required");
|
|
188
|
+
return this._request(`/v1/custom/${encodeURIComponent(name)}`, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
body: JSON.stringify(params),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export default BlackBoxClient;
|
package/package.json
ADDED