searchsocket 0.4.0 → 0.5.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/README.md +49 -31
- package/dist/cli.js +634 -1326
- package/dist/client.cjs +41 -117
- package/dist/client.d.cts +3 -17
- package/dist/client.d.ts +3 -17
- package/dist/client.js +41 -117
- package/dist/index.cjs +608 -1398
- package/dist/index.d.cts +73 -35
- package/dist/index.d.ts +73 -35
- package/dist/index.js +605 -1392
- package/dist/plugin-B_npJSux.d.cts +36 -0
- package/dist/plugin-M-aW0ev6.d.ts +36 -0
- package/dist/scroll.cjs +185 -0
- package/dist/scroll.d.cts +42 -0
- package/dist/scroll.d.ts +42 -0
- package/dist/scroll.js +183 -0
- package/dist/sveltekit.cjs +781 -1278
- package/dist/sveltekit.d.cts +3 -43
- package/dist/sveltekit.d.ts +3 -43
- package/dist/sveltekit.js +779 -1276
- package/dist/{types-z2dw3H6E.d.cts → types-Dk43uz25.d.cts} +46 -141
- package/dist/{types-z2dw3H6E.d.ts → types-Dk43uz25.d.ts} +46 -141
- package/package.json +10 -3
package/dist/client.cjs
CHANGED
|
@@ -1,60 +1,50 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// src/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const rerankedPos = /* @__PURE__ */ new Map();
|
|
13
|
-
for (let i = 0; i < rerankedUrls.length; i++) {
|
|
14
|
-
rerankedPos.set(rerankedUrls[i], i);
|
|
15
|
-
}
|
|
16
|
-
const displacements = [];
|
|
17
|
-
for (const url of initialUrls) {
|
|
18
|
-
const iPos = initialPos.get(url);
|
|
19
|
-
const rPos = rerankedPos.get(url);
|
|
20
|
-
const displacement = rPos !== void 0 ? Math.abs(iPos - rPos) : 0;
|
|
21
|
-
displacements.push({ url, displacement });
|
|
3
|
+
// src/client.ts
|
|
4
|
+
var SNIPPET_TARGET_MAX_WORDS = 12;
|
|
5
|
+
function normalizeTargetText(value) {
|
|
6
|
+
return value.replace(/\u2026/g, " ").replace(/\.{3,}/g, " ").replace(/\s+/g, " ").trim();
|
|
7
|
+
}
|
|
8
|
+
function shortenForTarget(value) {
|
|
9
|
+
const words = value.split(/\s+/).filter(Boolean);
|
|
10
|
+
if (words.length <= SNIPPET_TARGET_MAX_WORDS) {
|
|
11
|
+
return value;
|
|
22
12
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
13
|
+
return words.slice(0, SNIPPET_TARGET_MAX_WORDS).join(" ");
|
|
14
|
+
}
|
|
15
|
+
function selectTextTarget(result) {
|
|
16
|
+
const sectionTitle = normalizeTargetText(result.sectionTitle ?? "");
|
|
17
|
+
const snippetCandidate = normalizeTargetText(result.chunks?.[0]?.snippet ?? result.snippet);
|
|
18
|
+
if (snippetCandidate) {
|
|
19
|
+
if (!sectionTitle || snippetCandidate.toLowerCase().includes(sectionTitle.toLowerCase())) {
|
|
20
|
+
return shortenForTarget(snippetCandidate);
|
|
21
|
+
}
|
|
30
22
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
23
|
+
return sectionTitle;
|
|
24
|
+
}
|
|
25
|
+
function buildResultUrl(result) {
|
|
26
|
+
const textTarget = selectTextTarget(result);
|
|
27
|
+
if (!textTarget) {
|
|
28
|
+
return result.url;
|
|
38
29
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
const hashIdx = result.url.indexOf("#");
|
|
31
|
+
const beforeHash = hashIdx >= 0 ? result.url.slice(0, hashIdx) : result.url;
|
|
32
|
+
const existingHash = hashIdx >= 0 ? result.url.slice(hashIdx) : "";
|
|
33
|
+
const queryIdx = beforeHash.indexOf("?");
|
|
34
|
+
const path = queryIdx >= 0 ? beforeHash.slice(0, queryIdx) : beforeHash;
|
|
35
|
+
const existingQuery = queryIdx >= 0 ? beforeHash.slice(queryIdx + 1) : "";
|
|
36
|
+
const params = new URLSearchParams(existingQuery);
|
|
37
|
+
if (result.sectionTitle) {
|
|
38
|
+
params.set("_ssk", result.sectionTitle);
|
|
39
|
+
} else {
|
|
40
|
+
params.delete("_ssk");
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
response: {
|
|
49
|
-
...reranked,
|
|
50
|
-
results: mergedResults
|
|
51
|
-
},
|
|
52
|
-
usedRerankedOrder: false,
|
|
53
|
-
displacements
|
|
54
|
-
};
|
|
42
|
+
params.set("_sskt", textTarget);
|
|
43
|
+
const textFragment = `:~:text=${encodeURIComponent(textTarget)}`;
|
|
44
|
+
const hashWithoutTextFragment = existingHash.replace(/:~:text=.*$/u, "");
|
|
45
|
+
const hash = existingHash ? `${hashWithoutTextFragment}${textFragment}` : `#${textFragment}`;
|
|
46
|
+
return `${path}?${params.toString()}${hash}`;
|
|
55
47
|
}
|
|
56
|
-
|
|
57
|
-
// src/client.ts
|
|
58
48
|
function createSearchClient(options = {}) {
|
|
59
49
|
const endpoint = options.endpoint ?? "/api/search";
|
|
60
50
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
@@ -81,77 +71,11 @@ function createSearchClient(options = {}) {
|
|
|
81
71
|
throw new Error(message);
|
|
82
72
|
}
|
|
83
73
|
return payload;
|
|
84
|
-
},
|
|
85
|
-
async streamSearch(request, onPhase) {
|
|
86
|
-
const response = await fetchImpl(endpoint, {
|
|
87
|
-
method: "POST",
|
|
88
|
-
headers: {
|
|
89
|
-
"content-type": "application/json"
|
|
90
|
-
},
|
|
91
|
-
body: JSON.stringify(request)
|
|
92
|
-
});
|
|
93
|
-
if (!response.ok) {
|
|
94
|
-
let payload;
|
|
95
|
-
try {
|
|
96
|
-
payload = await response.json();
|
|
97
|
-
} catch {
|
|
98
|
-
throw new Error("Search failed");
|
|
99
|
-
}
|
|
100
|
-
const message = payload.error?.message ?? "Search failed";
|
|
101
|
-
throw new Error(message);
|
|
102
|
-
}
|
|
103
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
104
|
-
if (contentType.includes("application/json")) {
|
|
105
|
-
const data = await response.json();
|
|
106
|
-
onPhase({ phase: "initial", data });
|
|
107
|
-
return data;
|
|
108
|
-
}
|
|
109
|
-
if (!response.body) {
|
|
110
|
-
throw new Error("Response body is not readable");
|
|
111
|
-
}
|
|
112
|
-
const reader = response.body.getReader();
|
|
113
|
-
const decoder = new TextDecoder();
|
|
114
|
-
let buffer = "";
|
|
115
|
-
let lastResponse = null;
|
|
116
|
-
for (; ; ) {
|
|
117
|
-
const { done, value } = await reader.read();
|
|
118
|
-
if (done) break;
|
|
119
|
-
buffer += decoder.decode(value, { stream: true });
|
|
120
|
-
let newlineIdx;
|
|
121
|
-
while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
|
|
122
|
-
const line = buffer.slice(0, newlineIdx).trim();
|
|
123
|
-
buffer = buffer.slice(newlineIdx + 1);
|
|
124
|
-
if (line.length === 0) continue;
|
|
125
|
-
const event = JSON.parse(line);
|
|
126
|
-
if (event.phase === "error") {
|
|
127
|
-
const errData = event.data;
|
|
128
|
-
throw new Error(errData.error.message ?? "Streaming search error");
|
|
129
|
-
}
|
|
130
|
-
const searchEvent = event;
|
|
131
|
-
onPhase(searchEvent);
|
|
132
|
-
lastResponse = searchEvent.data;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const remaining = buffer.trim();
|
|
136
|
-
if (remaining.length > 0) {
|
|
137
|
-
const event = JSON.parse(remaining);
|
|
138
|
-
if (event.phase === "error") {
|
|
139
|
-
const errData = event.data;
|
|
140
|
-
throw new Error(errData.error.message ?? "Streaming search error");
|
|
141
|
-
}
|
|
142
|
-
const searchEvent = event;
|
|
143
|
-
onPhase(searchEvent);
|
|
144
|
-
lastResponse = searchEvent.data;
|
|
145
|
-
}
|
|
146
|
-
if (!lastResponse) {
|
|
147
|
-
throw new Error("No search results received");
|
|
148
|
-
}
|
|
149
|
-
return lastResponse;
|
|
150
74
|
}
|
|
151
75
|
};
|
|
152
76
|
}
|
|
153
77
|
|
|
78
|
+
exports.buildResultUrl = buildResultUrl;
|
|
154
79
|
exports.createSearchClient = createSearchClient;
|
|
155
|
-
exports.mergeSearchResults = mergeSearchResults;
|
|
156
80
|
//# sourceMappingURL=client.cjs.map
|
|
157
81
|
//# sourceMappingURL=client.cjs.map
|
package/dist/client.d.cts
CHANGED
|
@@ -1,26 +1,12 @@
|
|
|
1
|
-
import { S as
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Smart merge of initial (pre-rerank) and reranked search results.
|
|
5
|
-
*
|
|
6
|
-
* If the reranker barely changed the ordering, we keep the initial order
|
|
7
|
-
* (which the user already saw) and just update scores from the reranked response.
|
|
8
|
-
* If the reranker moved any single result by more than `maxDisplacement`
|
|
9
|
-
* positions, we adopt the reranked order — the reranker is semantic and
|
|
10
|
-
* expensive, so if it strongly disagrees on even one result, trust it.
|
|
11
|
-
*/
|
|
12
|
-
declare function mergeSearchResults(initial: SearchResponse, reranked: SearchResponse, options?: MergeSearchOptions): MergeSearchResult;
|
|
1
|
+
import { S as SearchRequest, a as SearchResponse, b as SearchResult } from './types-Dk43uz25.cjs';
|
|
13
2
|
|
|
3
|
+
declare function buildResultUrl(result: SearchResult): string;
|
|
14
4
|
interface SearchClientOptions {
|
|
15
5
|
endpoint?: string;
|
|
16
6
|
fetchImpl?: typeof fetch;
|
|
17
7
|
}
|
|
18
8
|
declare function createSearchClient(options?: SearchClientOptions): {
|
|
19
9
|
search(request: SearchRequest): Promise<SearchResponse>;
|
|
20
|
-
streamSearch(request: SearchRequest & {
|
|
21
|
-
stream: true;
|
|
22
|
-
rerank: true;
|
|
23
|
-
}, onPhase: (event: StreamSearchEvent) => void): Promise<SearchResponse>;
|
|
24
10
|
};
|
|
25
11
|
|
|
26
|
-
export { type SearchClientOptions,
|
|
12
|
+
export { type SearchClientOptions, buildResultUrl, createSearchClient };
|
package/dist/client.d.ts
CHANGED
|
@@ -1,26 +1,12 @@
|
|
|
1
|
-
import { S as
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Smart merge of initial (pre-rerank) and reranked search results.
|
|
5
|
-
*
|
|
6
|
-
* If the reranker barely changed the ordering, we keep the initial order
|
|
7
|
-
* (which the user already saw) and just update scores from the reranked response.
|
|
8
|
-
* If the reranker moved any single result by more than `maxDisplacement`
|
|
9
|
-
* positions, we adopt the reranked order — the reranker is semantic and
|
|
10
|
-
* expensive, so if it strongly disagrees on even one result, trust it.
|
|
11
|
-
*/
|
|
12
|
-
declare function mergeSearchResults(initial: SearchResponse, reranked: SearchResponse, options?: MergeSearchOptions): MergeSearchResult;
|
|
1
|
+
import { S as SearchRequest, a as SearchResponse, b as SearchResult } from './types-Dk43uz25.js';
|
|
13
2
|
|
|
3
|
+
declare function buildResultUrl(result: SearchResult): string;
|
|
14
4
|
interface SearchClientOptions {
|
|
15
5
|
endpoint?: string;
|
|
16
6
|
fetchImpl?: typeof fetch;
|
|
17
7
|
}
|
|
18
8
|
declare function createSearchClient(options?: SearchClientOptions): {
|
|
19
9
|
search(request: SearchRequest): Promise<SearchResponse>;
|
|
20
|
-
streamSearch(request: SearchRequest & {
|
|
21
|
-
stream: true;
|
|
22
|
-
rerank: true;
|
|
23
|
-
}, onPhase: (event: StreamSearchEvent) => void): Promise<SearchResponse>;
|
|
24
10
|
};
|
|
25
11
|
|
|
26
|
-
export { type SearchClientOptions,
|
|
12
|
+
export { type SearchClientOptions, buildResultUrl, createSearchClient };
|
package/dist/client.js
CHANGED
|
@@ -1,58 +1,48 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const rerankedPos = /* @__PURE__ */ new Map();
|
|
11
|
-
for (let i = 0; i < rerankedUrls.length; i++) {
|
|
12
|
-
rerankedPos.set(rerankedUrls[i], i);
|
|
13
|
-
}
|
|
14
|
-
const displacements = [];
|
|
15
|
-
for (const url of initialUrls) {
|
|
16
|
-
const iPos = initialPos.get(url);
|
|
17
|
-
const rPos = rerankedPos.get(url);
|
|
18
|
-
const displacement = rPos !== void 0 ? Math.abs(iPos - rPos) : 0;
|
|
19
|
-
displacements.push({ url, displacement });
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var SNIPPET_TARGET_MAX_WORDS = 12;
|
|
3
|
+
function normalizeTargetText(value) {
|
|
4
|
+
return value.replace(/\u2026/g, " ").replace(/\.{3,}/g, " ").replace(/\s+/g, " ").trim();
|
|
5
|
+
}
|
|
6
|
+
function shortenForTarget(value) {
|
|
7
|
+
const words = value.split(/\s+/).filter(Boolean);
|
|
8
|
+
if (words.length <= SNIPPET_TARGET_MAX_WORDS) {
|
|
9
|
+
return value;
|
|
20
10
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
return words.slice(0, SNIPPET_TARGET_MAX_WORDS).join(" ");
|
|
12
|
+
}
|
|
13
|
+
function selectTextTarget(result) {
|
|
14
|
+
const sectionTitle = normalizeTargetText(result.sectionTitle ?? "");
|
|
15
|
+
const snippetCandidate = normalizeTargetText(result.chunks?.[0]?.snippet ?? result.snippet);
|
|
16
|
+
if (snippetCandidate) {
|
|
17
|
+
if (!sectionTitle || snippetCandidate.toLowerCase().includes(sectionTitle.toLowerCase())) {
|
|
18
|
+
return shortenForTarget(snippetCandidate);
|
|
19
|
+
}
|
|
28
20
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
21
|
+
return sectionTitle;
|
|
22
|
+
}
|
|
23
|
+
function buildResultUrl(result) {
|
|
24
|
+
const textTarget = selectTextTarget(result);
|
|
25
|
+
if (!textTarget) {
|
|
26
|
+
return result.url;
|
|
36
27
|
}
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
const hashIdx = result.url.indexOf("#");
|
|
29
|
+
const beforeHash = hashIdx >= 0 ? result.url.slice(0, hashIdx) : result.url;
|
|
30
|
+
const existingHash = hashIdx >= 0 ? result.url.slice(hashIdx) : "";
|
|
31
|
+
const queryIdx = beforeHash.indexOf("?");
|
|
32
|
+
const path = queryIdx >= 0 ? beforeHash.slice(0, queryIdx) : beforeHash;
|
|
33
|
+
const existingQuery = queryIdx >= 0 ? beforeHash.slice(queryIdx + 1) : "";
|
|
34
|
+
const params = new URLSearchParams(existingQuery);
|
|
35
|
+
if (result.sectionTitle) {
|
|
36
|
+
params.set("_ssk", result.sectionTitle);
|
|
37
|
+
} else {
|
|
38
|
+
params.delete("_ssk");
|
|
40
39
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
response: {
|
|
47
|
-
...reranked,
|
|
48
|
-
results: mergedResults
|
|
49
|
-
},
|
|
50
|
-
usedRerankedOrder: false,
|
|
51
|
-
displacements
|
|
52
|
-
};
|
|
40
|
+
params.set("_sskt", textTarget);
|
|
41
|
+
const textFragment = `:~:text=${encodeURIComponent(textTarget)}`;
|
|
42
|
+
const hashWithoutTextFragment = existingHash.replace(/:~:text=.*$/u, "");
|
|
43
|
+
const hash = existingHash ? `${hashWithoutTextFragment}${textFragment}` : `#${textFragment}`;
|
|
44
|
+
return `${path}?${params.toString()}${hash}`;
|
|
53
45
|
}
|
|
54
|
-
|
|
55
|
-
// src/client.ts
|
|
56
46
|
function createSearchClient(options = {}) {
|
|
57
47
|
const endpoint = options.endpoint ?? "/api/search";
|
|
58
48
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
@@ -79,76 +69,10 @@ function createSearchClient(options = {}) {
|
|
|
79
69
|
throw new Error(message);
|
|
80
70
|
}
|
|
81
71
|
return payload;
|
|
82
|
-
},
|
|
83
|
-
async streamSearch(request, onPhase) {
|
|
84
|
-
const response = await fetchImpl(endpoint, {
|
|
85
|
-
method: "POST",
|
|
86
|
-
headers: {
|
|
87
|
-
"content-type": "application/json"
|
|
88
|
-
},
|
|
89
|
-
body: JSON.stringify(request)
|
|
90
|
-
});
|
|
91
|
-
if (!response.ok) {
|
|
92
|
-
let payload;
|
|
93
|
-
try {
|
|
94
|
-
payload = await response.json();
|
|
95
|
-
} catch {
|
|
96
|
-
throw new Error("Search failed");
|
|
97
|
-
}
|
|
98
|
-
const message = payload.error?.message ?? "Search failed";
|
|
99
|
-
throw new Error(message);
|
|
100
|
-
}
|
|
101
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
102
|
-
if (contentType.includes("application/json")) {
|
|
103
|
-
const data = await response.json();
|
|
104
|
-
onPhase({ phase: "initial", data });
|
|
105
|
-
return data;
|
|
106
|
-
}
|
|
107
|
-
if (!response.body) {
|
|
108
|
-
throw new Error("Response body is not readable");
|
|
109
|
-
}
|
|
110
|
-
const reader = response.body.getReader();
|
|
111
|
-
const decoder = new TextDecoder();
|
|
112
|
-
let buffer = "";
|
|
113
|
-
let lastResponse = null;
|
|
114
|
-
for (; ; ) {
|
|
115
|
-
const { done, value } = await reader.read();
|
|
116
|
-
if (done) break;
|
|
117
|
-
buffer += decoder.decode(value, { stream: true });
|
|
118
|
-
let newlineIdx;
|
|
119
|
-
while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
|
|
120
|
-
const line = buffer.slice(0, newlineIdx).trim();
|
|
121
|
-
buffer = buffer.slice(newlineIdx + 1);
|
|
122
|
-
if (line.length === 0) continue;
|
|
123
|
-
const event = JSON.parse(line);
|
|
124
|
-
if (event.phase === "error") {
|
|
125
|
-
const errData = event.data;
|
|
126
|
-
throw new Error(errData.error.message ?? "Streaming search error");
|
|
127
|
-
}
|
|
128
|
-
const searchEvent = event;
|
|
129
|
-
onPhase(searchEvent);
|
|
130
|
-
lastResponse = searchEvent.data;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const remaining = buffer.trim();
|
|
134
|
-
if (remaining.length > 0) {
|
|
135
|
-
const event = JSON.parse(remaining);
|
|
136
|
-
if (event.phase === "error") {
|
|
137
|
-
const errData = event.data;
|
|
138
|
-
throw new Error(errData.error.message ?? "Streaming search error");
|
|
139
|
-
}
|
|
140
|
-
const searchEvent = event;
|
|
141
|
-
onPhase(searchEvent);
|
|
142
|
-
lastResponse = searchEvent.data;
|
|
143
|
-
}
|
|
144
|
-
if (!lastResponse) {
|
|
145
|
-
throw new Error("No search results received");
|
|
146
|
-
}
|
|
147
|
-
return lastResponse;
|
|
148
72
|
}
|
|
149
73
|
};
|
|
150
74
|
}
|
|
151
75
|
|
|
152
|
-
export {
|
|
76
|
+
export { buildResultUrl, createSearchClient };
|
|
153
77
|
//# sourceMappingURL=client.js.map
|
|
154
78
|
//# sourceMappingURL=client.js.map
|